流媒体分析之webrtc之metartc 实现。

 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

 

 

 

 

 

你可能感兴趣的:(流媒体分析,webrtc,音视频)