int32_t yang_sdp_genLocalSdp2(YangRtcSession *session, int32_t localport,char *dst, YangStreamOptType role) {
int32_t mediaServer=session->context.avinfo->sys.mediaServer;
int32_t redPayloadtype=1;
char *src = (char*) calloc(1, Yang_SDP_BUFFERLEN);
char randstr[128];
//创建YangSdp结构体对象
YangSdp *local_sdp = (YangSdp*) calloc(sizeof(YangSdp), 1);
//初始化sdp的部分字段
yang_create_rtcsdp(local_sdp);
//设置version为0
strcpy(local_sdp->version, "0");
//设置username为MetaRtc
strcpy(local_sdp->username, "MetaRtc");
//将local_sdp的地址格式化为字符串拷贝到randstr中
memset(randstr, 0, sizeof(randstr));
snprintf(randstr, 22, "%" PRId64, (int64_t) &local_sdp);
//将randstr作为session_id
strcpy(local_sdp->session_id, randstr);
//设置session_version为2
strcpy(local_sdp->session_version, "2");
//设置网络类型为因特网
strcpy(local_sdp->nettype, "IN");
//设置ip地址类型为ipv4
strcpy(local_sdp->addrtype, "IP4");
//设置广播地址为0.0.0.0
strcpy(local_sdp->unicast_address, "0.0.0.0");
//设置session_name为MetaRtcSession
strcpy(local_sdp->session_name, "MetaRtcSession");
//设置msid_semantic为WMS,WMS是WebRTC Media Stream简称,表示本机支持传输多个流,每个流可包含多个track。
strcpy(local_sdp->msid_semantic, "WMS");
//设置msids
yang_create_stringVector(&local_sdp->msids);
char streamnames[164];
memset(streamnames, 0, sizeof(streamnames));
sprintf(streamnames, "%s/%s", session->context.streamConfig->app,session->context.streamConfig->stream);
yang_insert_stringVector(&local_sdp->msids, streamnames);
//设置group_policy,0表示音频 1表示视频,BUNDLE表示音频和视频绑定在一起。
strcpy(local_sdp->group_policy,"BUNDLE 0 1");
char tmps[5][16];
//设置media_descs为空。
yang_create_YangMediaDescVector(&local_sdp->media_descs);
yang_insert_YangMediaDescVector(&local_sdp->media_descs, NULL);
//获取到音频媒体描述字段进行设置。
YangMediaDesc *audio_media_desc = &local_sdp->media_descs.payload[0];
//设置type为audio
strcpy(audio_media_desc->type, "audio");
//设置端口为9
audio_media_desc->port = 9;
//设置使用UDP传输RTP数据包,使用TLS加密。
strcpy(audio_media_desc->protos, "UDP/TLS/RTP/SAVPF");
//表示rtp和rtcp复用一个端口
audio_media_desc->rtcp_mux = true;
//表示希望所见rtcp协议的流量
audio_media_desc->rtcp_rsize = true;
//设置音频的mid为0
strcpy(audio_media_desc->mid, "0");
//获取到视频媒体描述字段进行设置。
YangMediaDesc *video_media_desc = &local_sdp->media_descs.payload[1];
//设置type为video
strcpy(video_media_desc->type, "video");
//设置端口为9
video_media_desc->port = 9;
//设置使用UDP传输RTP数据包,使用TLS加密。
strcpy(video_media_desc->protos, "UDP/TLS/RTP/SAVPF");
//表示rtp和rtcp复用一个端口
video_media_desc->rtcp_mux = true;
//表示希望所见rtcp协议的流量
video_media_desc->rtcp_rsize = true;
//设置音频的mid为1
strcpy(video_media_desc->mid, "1");
#if Yang_Enable_Datachannel
YangMediaDesc *data_media_desc = NULL;
//如果yang_config.ini或代码中配置enableDatachannel为1时则进行数据通道的sdp配置。
if(session->context.avinfo->rtc.enableDatachannel){
//设置media_descs为空
yang_insert_YangMediaDescVector(&local_sdp->media_descs, NULL);
//拿到数据通道的描述字段用于配置信息
data_media_desc=&local_sdp->media_descs.payload[2];
//设置type为application
strcpy(data_media_desc->type, "application");
//设置port为9
data_media_desc->port = 9;
//设置UDP传输SCTP协议的数据,使用DTLS加密。
strcpy(data_media_desc->protos, "UDP/DTLS/SCTP webrtc-datachannel");
//设置rtcp不复用SCTP通道
data_media_desc->rtcp_mux = false;
//设置rtcp不缩减流量
data_media_desc->rtcp_rsize = false;
//设置mid为2
strcpy(data_media_desc->mid, "2");
//设置音视频和数据通道绑定到一起,0为音频,1为视频,2为数据
strcpy(local_sdp->group_policy,"BUNDLE 0 1 2");
}
#endif
//Yang_Stream_Play表示仅接收音视频
if (role == Yang_Stream_Play) {
audio_media_desc->recvonly = true;
video_media_desc->recvonly = true;
} else if (role == Yang_Stream_Publish) {
//Yang_Stream_Publish表示仅发送音视频
audio_media_desc->sendonly = true;
video_media_desc->sendonly = true;
} else if (role == Yang_Stream_Both) {
//Yang_Stream_Both表示既发送又接收音视频
audio_media_desc->sendrecv = true;
video_media_desc->sendrecv = true;
}
#if Yang_Enable_Datachannel
//如果数据通道开启了,则激活sctp端口
if(data_media_desc) data_media_desc->sctp_port = true;
#endif
//随机4个字节的str到randstr中。
memset(randstr, 0, sizeof(randstr));
yang_cstr_random(4, randstr);
//将随机的randstr设置为ice_ufrag,他和ice_pwd组合用于校验用户p2p对端是否合法。
memset(session->local_ufrag,0,sizeof(session->local_ufrag));
strcpy(session->local_ufrag, randstr);
strcpy(audio_media_desc->session_info.ice_ufrag, randstr);
strcpy(video_media_desc->session_info.ice_ufrag, randstr);
#if Yang_Enable_Datachannel
//如果数据通道开启了则同时设置数据通道的ice_ufrag
if(data_media_desc) strcpy(data_media_desc->session_info.ice_ufrag, randstr);
#endif
//随机32个字节的str到randstr中。
memset(randstr, 0, sizeof(randstr));
yang_cstr_random(32, randstr);
//将随机的randstr设置为ice_pwd
strcpy(audio_media_desc->session_info.ice_pwd, randstr);
strcpy(video_media_desc->session_info.ice_pwd, randstr);
#if Yang_Enable_Datachannel
//如果数据通道开启了则同时设置数据通道的ice_pwd
if(data_media_desc) strcpy(data_media_desc->session_info.ice_pwd, randstr);
#endif
memset(session->localIcePwd,0,sizeof(session->localIcePwd));
strcpy(session->localIcePwd,randstr);
//设置fingerprint_algo为sha-256
strcpy(audio_media_desc->session_info.fingerprint_algo, "sha-256");
strcpy(video_media_desc->session_info.fingerprint_algo, "sha-256");
#if Yang_Enable_Datachannel
if(data_media_desc) strcpy(data_media_desc->session_info.fingerprint_algo, "sha-256");
if(data_media_desc) strcpy(data_media_desc->session_info.ice_options, "trickle");
#endif
//如果开启dtls传输,则设置证书中的fingerprint放到audio,video,data中。
#if Yang_Enable_Dtls
strcpy(audio_media_desc->session_info.fingerprint,session->context.cer->fingerprint);
strcpy(video_media_desc->session_info.fingerprint,session->context.cer->fingerprint);
#if Yang_Enable_Datachannel
if(data_media_desc) strcpy(data_media_desc->session_info.fingerprint,session->context.cer->fingerprint);
#endif
#endif
//passive表示本机角色为服务器,actpass表示本机角色既可以是服务器也可以是客户端。
strcpy(audio_media_desc->session_info.setup, session->isServer?"passive":"actpass");
strcpy(video_media_desc->session_info.setup, session->isServer?"passive":"actpass");
#if Yang_Enable_Datachannel
if(data_media_desc) strcpy(data_media_desc->session_info.setup, session->isServer?"passive":"actpass");
#endif
//设置音频传输类型为opus/48000
yang_create_YangMediaPayloadTypeVector(&audio_media_desc->payload_types);
yang_insert_YangMediaPayloadTypeVector(&audio_media_desc->payload_types,
NULL);
YangMediaPayloadType *audiotype =
&audio_media_desc->payload_types.payload[0];
audiotype->payload_type = 111;
strcpy(audiotype->encoding_name, "opus");
audiotype->clock_rate = session->context.avinfo->audio.sample; //48000;
yang_itoa(session->context.avinfo->audio.channel,
audiotype->encoding_param, 10);
//设置rtcp的feedback类型为transport-cc
yang_create_stringVector(&audiotype->rtcp_fb);
yang_insert_stringVector(&audiotype->rtcp_fb, "transport-cc");
yang_create_YangMediaPayloadTypeVector(&video_media_desc->payload_types);
//insert h264/h265
yang_insert_YangMediaPayloadTypeVector(&video_media_desc->payload_types,NULL);
//设置编码格式支持H264或H265
YangMediaPayloadType *videotype =&video_media_desc->payload_types.payload[0];
if (session->context.avinfo->video.videoEncoderType == Yang_VED_264) {
videotype->payload_type = 125;
strcpy(videotype->encoding_name, "H264");
} else if (session->context.avinfo->video.videoEncoderType == Yang_VED_265) {
videotype->payload_type = 126;
strcpy(videotype->encoding_name, "H265");
}
yang_sdp_genLocalSdp_payloadType(videotype);
//设置编码格式支持red
yang_insert_YangMediaPayloadTypeVector(&video_media_desc->payload_types,NULL);
videotype =&video_media_desc->payload_types.payload[redPayloadtype];
strcpy(videotype->encoding_name, "red");
videotype->payload_type = 114;
videotype->clock_rate = 90000;
//设置ssrc
yang_insert_YangSSRCInfoVector(&audio_media_desc->ssrc_infos, NULL);
yang_insert_YangSSRCInfoVector(&video_media_desc->ssrc_infos, NULL);
audio_media_desc->ssrc_infos.payload[0].ssrc = session->context.audioSsrc;
video_media_desc->ssrc_infos.payload[0].ssrc = session->context.videoSsrc;
//设置ssrc的cname
memset(randstr, 0, sizeof(randstr));
yang_cstr_random(16, randstr);
strcpy(audio_media_desc->ssrc_infos.payload[0].cname, randstr);
strcpy(video_media_desc->ssrc_infos.payload[0].cname, randstr);
strcpy(audio_media_desc->ssrc_infos.payload[0].mslabel, "-");
strcpy(video_media_desc->ssrc_infos.payload[0].mslabel, "-");
//随机randstr放入音频的ssrc的msid_tracker和label中
memset(tmps, 0, 16 * 5);
yang_cstr_random(8, tmps[0]);
yang_cstr_random(4, tmps[1]);
yang_cstr_random(4, tmps[2]);
yang_cstr_random(4, tmps[3]);
yang_cstr_random(12, tmps[4]);
memset(randstr, 0, sizeof(randstr));
sprintf(randstr, "%s-%s-%s-%s-%s", tmps[0], tmps[1], tmps[2], tmps[3],tmps[4]);
strcpy(audio_media_desc->ssrc_infos.payload[0].msid, "-");
strcpy(audio_media_desc->ssrc_infos.payload[0].msid_tracker, randstr);
strcpy(audio_media_desc->ssrc_infos.payload[0].label, randstr);
//随机randstr放入视频的ssrc的msid_tracker和label中
memset(tmps, 0, 16 * 5);
yang_cstr_random(8, tmps[0]);
yang_cstr_random(4, tmps[1]);
yang_cstr_random(4, tmps[2]);
yang_cstr_random(4, tmps[3]);
yang_cstr_random(12, tmps[4]);
memset(randstr, 0, sizeof(randstr));
sprintf(randstr, "%s-%s-%s-%s-%s", tmps[0], tmps[1], tmps[2], tmps[3],
tmps[4]);
strcpy(video_media_desc->ssrc_infos.payload[0].msid, "-");
strcpy(video_media_desc->ssrc_infos.payload[0].msid_tracker, randstr);
strcpy(video_media_desc->ssrc_infos.payload[0].label, randstr);
//如果媒体服务器为p2pServer,则设置candidates数据,这里仅设置了一种candidate类型的数据,其实应该把host,srflx,relay都设置进去,由对端决定最优的线路。
if(mediaServer==Yang_Server_P2p){
yang_create_YangCandidateVector(&audio_media_desc->candidates);
yang_create_YangCandidateVector(&video_media_desc->candidates);
//获取本地端口和ip
int32_t localport=session->context.streamConfig->localPort;
char* localip=session->context.avinfo->sys.localIp;
//如果iceUsingLocalIp为1,则设置本地ip为本机ip地址
if(session->context.avinfo->rtc.iceUsingLocalIp){
localip=session->context.avinfo->rtc.iceLocalIP;
}else if(session->ice.session.candidateType==YangIceStun&&session->ice.session.server.stunPort>0){
//如果candidateType是stun并且stun端口号有设置,则获取stun的ip,设置为localip和localport.
struct sockaddr_in addr;
addr.sin_addr.s_addr= session->ice.session.server.stunIp;
localip=inet_ntoa(addr.sin_addr);
localport=session->ice.session.server.stunPort;
}else if(session->ice.session.candidateType==YangIceTurn&&(session->ice.session.isTurnReady||session->ice.session.isTurnAllocated)){
//如果candidateType是turn并且isTurnReady和isTurnAllocated,则获取turn的中继ip,设置为localip和localport.
struct sockaddr_in addr;
addr.sin_addr.s_addr= session->ice.session.server.relayIp;
localip=inet_ntoa(addr.sin_addr);
localport=session->ice.session.server.relayPort;
}else{
}
//根据localip和localport配置candidate的ip、port和type
yang_sdp_genLocalSdp_candidate(session,audio_media_desc,localip,localport);
yang_sdp_genLocalSdp_candidate(session,video_media_desc,localip,localport);
#if Yang_Enable_Datachannel
if(data_media_desc){
yang_create_YangCandidateVector(&data_media_desc->candidates);
yang_sdp_genLocalSdp_candidate(session,data_media_desc,localip,localport);
}
#endif
}
//将local_sdp编码到src中。
YangBuffer buf;
yang_init_buffer(&buf, src, Yang_SDP_BUFFERLEN);
yang_rtcsdp_encode(local_sdp, &buf);
//根据是否server,替换不同的分割字符串。放到dst中。
if(mediaServer==Yang_Server_P2p&&!session->isServer){
yang_cstr_replace(src, dst, (char*) "\r\n", (char*) "\n");
}
else{
yang_cstr_replace(src, dst, (char*) "\r\n", (char*) "\\r\\n");
}
yang_destroy_rtcsdp(local_sdp);
yang_free(local_sdp);
yang_free(src);
return Yang_Ok;
}