metartc库是对外提供接口:
void yang_create_metaConnection(YangMetaConnection* metaconn){
metaconn->session=calloc(sizeof(YangMetaSession),1);
yang_setLogLevel(5);
yang_setLogFile(1);
metaconn->init=g_yang_mt_init;
metaconn->initParam=g_yang_mt_initParam;
metaconn->parseHeader=g_yang_mt_parseHeader;
metaconn->connectSfuServer=g_yang_mt_connectServer;
metaconn->close=g_yang_mt_disconnectServer;
metaconn->setExtradata=g_yang_mt_setExtradata;
metaconn->publishAudio=g_yang_mt_publishAudio;
metaconn->publishVideo=g_yang_mt_publishVideo;
metaconn->isConnected=g_yang_mt_getState;
metaconn->recvvideoNotify=g_yang_mt_recvvideo_notify;
}
1. 连接srs 服务器yang_srs_connectRtcServer,调用yang_srs_getSignal 发送信令及sdp 信息交换。
int32_t yang_srs_connectRtcServer(YangRtcConnection* conn){
YangRtcSession* session=conn->session;
int err=Yang_Ok;
SrsSdpResponseType srs;
memset(&srs,0,sizeof(SrsSdpResponseType));
char *tsdp=NULL;
conn->createOffer(session, &tsdp);
if ((err=yang_srs_getSignal(conn->session,&srs,tsdp)) == Yang_Ok) {
conn->setRemoteDescription(conn->session,srs.sdp);
}
yang_free(tsdp);
yang_destroy_srsresponse(&srs);
return err;
}
函数 yang_srs_getSignal,封装sdp 信息。
int32_t yang_srs_getSignal(YangRtcSession* session,SrsSdpResponseType* srs,char* sdp) {
int32_t err = Yang_Ok;
char *srsSdp = (char*)calloc(1,1024*12);
char qt = '"';
YangStreamOptType role=session->context.streamConfig->streamOptType;
const char* roleStr=role==Yang_Stream_Play?"play":"publish";
sprintf(srsSdp,
"{%capi%c:%chttp://%s:%d/rtc/v1/%s/%c,%cstreamurl%c:%cwebrtc://%s:%d/%s/%s%c,%cclientip%c:null,%csdp%c:%c%s%c}",
qt, qt, qt, session->context.streamConfig->remoteIp, session->context.streamConfig->remotePort,roleStr ,qt, qt, qt, qt, session->context.streamConfig->remoteIp,
session->context.streamConfig->remotePort, session->context.streamConfig->app, session->context.streamConfig->stream, qt, qt, qt, qt, qt, qt, sdp, qt);
char apiurl[256] ;
memset(apiurl,0,sizeof(apiurl));
sprintf(apiurl, "rtc/v1/%s/", roleStr);
err=yang_sdp_querySrs(session,srs,role==Yang_Stream_Play?1:0,(char*)session->context.streamConfig->remoteIp,session->context.streamConfig->remotePort,apiurl, srsSdp);
yang_free(srsSdp);
return err;
}
yang_sdp_querySrs 函数:yang_http_post 通过发送本段sdp及接收srs服务器的sdp 信息。
int32_t yang_sdp_querySrs(YangRtcSession* session,SrsSdpResponseType* srs,int32_t isplay,char* ip,int32_t port,char* purl, char* psdp)
{
int32_t err=Yang_Ok;
char* sdp=(char*)calloc(1,Yang_SDP_BUFFERLEN);
if(yang_http_post(sdp,ip, port, purl, (uint8_t*)psdp, strlen(psdp))){
yang_free(sdp);
return yang_error_wrap(1,"query srs sdp failure!");
}
char* sBuffer=(char*)calloc(1,Yang_SDP_BUFFERLEN);
yang_cstr_replace(sdp,sBuffer, "{", "");
memset(sdp,0,Yang_SDP_BUFFERLEN);
strcpy(sdp,sBuffer);
memset(sBuffer,0,Yang_SDP_BUFFERLEN);
yang_cstr_replace(sdp,sBuffer, "}", "");
memset(sdp,0,Yang_SDP_BUFFERLEN);
strcpy(sdp,sBuffer);
memset(sBuffer,0,Yang_SDP_BUFFERLEN);
yang_cstr_replace(sdp,sBuffer, "\\r\\n", "\n");
YangStrings strs;
memset(&strs,0,sizeof(YangStrings));
yang_cstr_split(sBuffer, (char*)",",&strs);
char* p=NULL;
for (int32_t i = 0; i < strs.vsize; i++) {
if ((p = strstr(strs.str[i], "\"code\":"))) {
char *buf = (char*) calloc(1, strlen(p) + 1);
yang_cstr_replace(p + strlen("\"code\":"), buf, "\"", "");
srs->retcode = atoi(buf);
yang_free(buf);
if ((err = srs->retcode) != 0) break;
continue;
}
if ((p = strstr(strs.str[i], "\"server\":"))) {
srs->serverIp = (char*) calloc(1, strlen(p) + 1);
yang_cstr_replace(p + strlen("\"server\":"), srs->serverIp, "\"", "");
continue;
}
if ((p = strstr(strs.str[i], "\"sessionid\":"))) {
srs->sessionid = (char*) calloc(1, strlen(p) + 1);
yang_cstr_replace(p + strlen("\"sessionid\":"), srs->sessionid, "\"","");
continue;
}
if ((p = strstr(strs.str[i], "\"sdp\":"))) {
srs->sdp = (char*) calloc(1, strlen(p) + 1);
yang_cstr_replace(p + strlen("\"sdp\":"), srs->sdp, "\"", "");
continue;
}
}
yang_destroy_strings(&strs);
yang_free(sdp);
return err;
}
yang_http_post 通过http 协议post 接口,发送sdp,并接收对端的sdp。
int32_t yang_http_post(char *rets, char *ip, int32_t port, char *api,
uint8_t *data, int32_t plen) {
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
#endif
int32_t socketfd;
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(port);
#ifdef _WIN32
serverAddress.sin_addr.S_un.S_addr=inet_addr(ip);
#else
serverAddress.sin_addr.s_addr = inet_addr(ip);
#endif
socketfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int32_t on = 1;
setsockopt(socketfd, IPPROTO_TCP, TCP_NODELAY, (char*) &on, sizeof(on));
#ifdef _WIN32
int32_t timeout=800;
setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
#else
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 800000; // 200 ms
setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv,
sizeof(struct timeval));
#endif
if (connect(socketfd, (struct sockaddr*) &serverAddress,
sizeof(struct sockaddr)) == -1) {
closesocket(socketfd);
return yang_error_wrap(ERROR_SOCKET, "http connect socket error(%d)",
GetSockError());
}
char *buf = (char*) malloc(Yang_Http_Buffer);
memset(buf, 0, Yang_Http_Buffer);
const char *s = "POST /%s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Accept: */*\r\n"
"Content-Type:application/json;charset=UTF-8\r\n"
"Content-Length: %u\r\n"
"\r\n%s";
int len = sprintf(buf, s, api, ip, port, plen, data);
int32_t nBytes = send(socketfd, buf, len, 0);
if (nBytes < 1) {
close(socketfd);
return yang_error_wrap(ERROR_SOCKET, "http send server fail!");
}
int32_t recvLen = 0;
int32_t recvtimes=0;
int32_t contentLen=0;
char contentLenStr[20];
int32_t contetSize=sizeof(Yang_Http_Content);
char* p=NULL;
int32_t headerLen=0;
while (true) {
memset(buf, 0, Yang_Http_Buffer);
nBytes = recv(socketfd, (char*) buf, Yang_Http_Buffer, 0);
if (nBytes > 0) {
memcpy(rets + recvLen, buf, nBytes);
recvLen += nBytes;
if(recvtimes==0&&strstr(buf, "HTTP")==NULL) break;
recvtimes++;
if(contentLen==0){
p=strstr(rets,Yang_Http_Content);
if(recvtimes>0&&p==NULL) break;
if(p==NULL) continue;
int32_t ind=yang_cstr_userfindindex(p,'\r');
if(ind==0) continue;
if(ind>contetSize){
memset(contentLenStr,0,sizeof(contentLenStr));
memcpy(contentLenStr,p+contetSize,ind-contetSize);
int numberIndex=yang_cstr_isnumber(contentLenStr,sizeof(contentLenStr));
if(numberIndex>-1&&numberIndex 0) headerLen = contentPos + 4;
}
}
if(recvLen >= headerLen+contentLen) goto success;
continue;
} else if (nBytes == -1) {
int32_t sockerr = GetSockError();
if (sockerr == EINTR)
continue;
if (sockerr == EWOULDBLOCK || sockerr == EAGAIN) {
nBytes = 0;
continue;
}
yang_error("%s, recv returned %d. GetSockError(): %d (%s)",
__FUNCTION__, nBytes, sockerr, strerror(sockerr));
break;
} else if (nBytes == 0) {
break;
}
break;
}
closesocket(socketfd);
yang_free(buf);
return 1;
success:
closesocket(socketfd);
yang_free(buf);
return Yang_Ok;
}
setRemoteDescription 函数:指向yang_rtcconn_startRtc 。
调用yang_rtcconn_getRemoteSdp,解析sdp 信息,
createRequestStunPacket 发送stun 协议packet。
int32_t yang_rtcconn_startRtc(YangRtcSession* session,char* sdp){
yang_trace("\nstartRtc,port=%d",session->context.streamConfig->localPort);
session->isServer=session->context.streamConfig->isServer;
yang_rtcconn_getRemoteSdp(session,sdp);
session->ice.session.stun.createRequestStunPacket(session,session->remoteIcePwd);
if(session->context.avinfo->sys.mediaServer==Yang_Server_P2p){
if(session->context.avinfo->rtc.iceUsingLocalIp==0 &&
session->ice.iceHandle(&session->ice.session,session,yang_rtcconn_turn_receive,
session->context.streamConfig->remoteIp,session->context.streamConfig->remotePort)==YangIceTurn){
yang_create_rtcudp(session->context.udp,session->context.streamConfig->localPort);
session->context.udp->sendData=yang_rtcconn_turn_sendData;
yang_rtcconn_startudp(session);
g_yang_startStunTimer(session->context.udp->session.user);
return Yang_Ok;
}
}
yang_create_rtcudp(session->context.udp,session->context.streamConfig->localPort);
session->context.udp->updateRemoteAddress(&session->context.udp->session,session->context.streamConfig->remoteIp,session->isServer?0:session->context.streamConfig->remotePort);
yang_rtcconn_startudp(session);
session->context.udp->start(&session->context.udp->session);
return Yang_Ok;
}
2。 metartc 数据收流程。发送流程省略
数据rtp收发:
yang_create_rtcConnection
session->context.udp->session.receive = g_session_receive;
g_session_receive
conn->receive
conn->receive=yang_rtcconn_receive;
yang_rtcconn_init
yang_create_rtcplay
yang_create_playTrackAudio
yang_create_playvideoTrack
yang_create_playTrackH264
yang_create_playTrackH265
yang_rtcconn_startRtc
yang_create_rtcudp
yang_start_rtcudp
pthread_create(&udp->threadId, 0, yang_run_rtcudp_thread, udp)
yang_run_rtcudp_thread
//udp->receive 指向g_session_receive
udp->receive(buffer, len, udp->user);
yang_rtcconn_receive
session->play->on_rtp
yang_rtcplay_on_rtp
video_track->on_rtp
yang_playvideoTrack_on_rtp
yang_playtrackH264_on_rtp
yang_playtrackH264_packet_video
yang_playtrackH264_put_frame_video
yang_playtrack_receiveVideo
context->streamConfig->recvCallback.receiveVideo
yang_playtrackH265_on_rtp
audio_track->on_rtp
context->streamConfig->recvCallback.receiveVideo 指向stream.recvCallback.receiveAudio=g_ff_rtc_receiveAudio
3. metartc datachannel 数据收流程:
usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, g_sctp_receive_cb, NULL, 0, sctp);
g_sctp_receive_cb
sctp->receive_msg
context->sctp.receive_msg=yang_datachannel_receive_msg;
yang_datachannel_receive_msg
recvCallback.receiveMsg
recvCallback.receiveMsg=g_ipc_rtcrecv_receiveMsg
g_ipc_rtcrecv_receiveMsg