Qt实现sdp组包,sdp策略介绍

sdp简介

SDP:会话描述协议 ( Session Des cription Protocol)
会话描述协议(SDP)为会话通知、会话邀请和其它形式的多媒体会话初始化等目的提供了多媒体会话描述。
SDP会话描述由多行=组成。其中是一个字符。是一个字符串,其格式视而定。
SDP会话描述由一个会话级描述(session_level description)和多个媒体级描述(media_level description)组成。会话级(session_level)的作用域是整个会话。其位置是从’v=’行开始到第一个媒体描述为止。媒体级(media_level)描述是对单个的媒体流进行描述(例如传送单个音频或者视频的vlc sdp文件只有短短的几句话,从m=开始,这其实就是个媒体机描述),其位置是从’m=’行开始到下一个媒体描述为止。

v=0//SDP的版本号,必选,示例:"v=0\n"
o=<username> <sessionid> <version> <network type> <address type> <address>//会话的发起者描述,必选,示例:"o=MetaRtc 10000 2 IN IP4 0.0.0.0\n"
s=<sessionname>//会话名,必选,示例:"s=MetaRtcSession\n"
c=<networktype> <address type> <connection address>//媒体连接信息,可选,示例:"c=IN IP4 0.0.0.0\n"
b=<modifier>:<bandwidth-value>//带宽,可选,示例:b=X-YZ:128
t=<start time>  <stop time>//描述了会话的开始时间和结束时间,必选,示例:"t=0 0\n"
m=<media><port> <transport> <fmt list>//一个会话描述包括几个媒体描述,必选,示例:"m=audio 9 UDP/TLS/RTP/SAVPF 111\n";"m=video 9 UDP/TLS/RTP/SAVPF 125 114\n"#125和114是编解码器编号codecs
a=rtpmap:<payload type><encoding name>/<clock rate>[/<encodingparameters>]//编码参数,可选,示例:"a=rtpmap:111 opus/48000/2\n"
a=<TYPE>或 a=<TYPE>:<VALUES>//SuggestedAttributes,建议的属性,可选
a=framerate:<帧速率>//单位:帧/秒,可选
a=lang:<语言标记>//会话描述的缺省语言或媒体描述的语言,可选

音视频通话sdp策略

音视频流程主要包括:穿透/中继,sdp交互,dtls握手,udp收发音视频数据,会话信令交互

sdp策略
1、sdp会话描述协议,sdp是不允许丢失的,因此建议通过信令服务器转发,通常是http或websockt转发。
2、如果没有信令服务器转发,也可以用frpc(ngrok)做内网穿透。
3、sdp携带大量信息,至于是否携带本端公网ip和port,根据策略决定。

udp策略
1、dtls和音视频数据都是通过udp发送,p2p通信需要做udp穿透,可使用开源的coturn服务器stun协议实现,穿透成功主被叫分别获取自己的公网ip和port,并通过sdp发送给对方。
2、如果coturn穿透失败,可使用coturn的turn服务进行中继转发,此时发送的sdp不包含本端的ip和port。
3、有一种局域网的demo策略比较容易实现,主叫知道被叫的http服务ip和端口,主叫生成随机的udp端口,作为http客户端给被叫的http服务端发送sdp,此sdp可以不携带udp端口号;被叫也生成随机的udp端口,并写入sdp回复给主叫,此时主叫解析到了被叫的udp端口,主叫作为udp客户端往被叫的udp发送音视频数据,被叫作为udp服务端收到主叫的udp包并解析主叫的udp端口,给主叫发送udp数据。

Qt实现sdp组包

qt套壳,底层通过C/C++实现,源码待打包。

#include "sdpmainwindow.h"
#include "ui_sdpmainwindow.h"

sdpMainWindow::sdpMainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::sdpMainWindow)
{
    ui->setupUi(this);

    session=(chwRtcSession*)calloc(sizeof(chwRtcSession),1);
    session->context.streamConfig=(chwStreamConfig*)calloc(sizeof(chwStreamConfig),1);
    session->context.avinfo=(chwAVInfo*)calloc(sizeof(chwAVInfo),1);
    session->context.cer=(chwCertificate*)calloc(sizeof(chwCertificate),1);

    //chwStreamConfig
    strcpy(session->context.streamConfig->app,"live");
    session->context.streamConfig->streamOptType=chw_Stream_Both;
    strcpy(session->context.streamConfig->remoteIp,"192.168.3.36");//对方IP
    session->context.streamConfig->remotePort=9092;//对方端口
    strcpy(session->context.streamConfig->stream,"livestream");
    session->context.streamConfig->uid=0;
    session->context.streamConfig->isServer=1;
    session->context.streamConfig->localPort=9091;//本地udp端口
    session->context.streamConfig->recvCallback.context=this;

    //avinfo
    initVideo(&session->context.avinfo->video);
    initAudio(&session->context.avinfo->audio);
    initSys(&session->context.avinfo->sys);
    initEnc(&session->context.avinfo->enc);
    initRtc(&session->context.avinfo->rtc);

    session->isServer = 1;
    chw_create_rtcContext(&session->context);

    char* localSdp;
    createOffer(session,&localSdp);

    //换行打印
    std::string prtlocalSdp = localSdp;
    std::string::size_type pos = 0;
    while ((pos = prtlocalSdp.find("\\r\\n", pos)) != std::string::npos)
    {
        prtlocalSdp.replace(pos, 4, "\r\n");
    }
    printf("localsdp=%s\n",prtlocalSdp.c_str());
}

sdpMainWindow::~sdpMainWindow()
{
    delete ui;
}

int32_t sdpMainWindow::createOffer(chwRtcSession *session, char **psdp)
{
    int32_t localport=session->context.streamConfig->localPort;
    chwStreamOptType role=session->context.streamConfig->streamOptType;
    return chw_sdp_genLocalSdp(session,localport, psdp,role);
}

void sdpMainWindow::initVideo(chwVideoInfo* video){
    memset(video,0,sizeof(chwVideoInfo));
    //本端分辨率根据配置设置,接收对端视频数据包解析头部获取对方分辨率
    video->width =  640;
    video->height =  480;
    video->outWidth =  640;
    video->outHeight = 480;
    video->rate = 2048;
    video->frame =  25;
    video->rotate = 0;
    video->bitDepth = 8;

    video->videoCacheNum =50;
    video->evideoCacheNum = 50;
    video->videoPlayCacheNum = 5;

    video->videoCaptureFormat = (chwYuvType)("video", "videoCaptureFormat", chwYuy2);
    video->videoEncoderFormat = (chwYuvType)("video", "videoEncoderFormat", chwI420);
    video->videoDecoderFormat = (chwYuvType)("video", "videoDecoderFormat", chwI420);

    video->videoEncoderType = ("video", "videoEncoderType", 0);
    video->videoDecoderType = ("video", "videoDecoderType", 0);
    video->videoEncHwType = ("video", "videoEncHwType", 0);
    video->videoDecHwType = ("video", "videoDecHwType", 0);
    video->vIndex = ("video", "vIndex", 0);
}
void sdpMainWindow::initAudio(chwAudioInfo* audio){
    memset(audio,0,sizeof(chwAudioInfo));
    audio->sample= 44100;
    audio->frameSize= 1024;
    audio->channel= 2;
    audio->bitrate = 128;
    audio->usingMono=0;
    audio->hasAec = 0;
    audio->echoPath = 10;
    audio->aecBufferFrames=0;
    audio->hasAudioHeader = 0;
    audio->audioEncoderType = 0;
    audio->audioDecoderType = 0;
    audio->audioPlayType = 0;
    audio->audioCacheNum = 100;
    audio->audioCacheSize = 100;
    audio->audioPlayCacheNum = 10;

    audio->aIndex = 0;
    audio->aSubIndex = 0;
    //aSubIndex
    if(audio->usingMono){
        if(audio->audioEncoderType<2) audio->audioEncoderType=2;
        if(audio->audioDecoderType<2)audio->audioDecoderType=2;
        audio->channel=1;
        audio->sample=16000;
        audio->frameSize=320;
    }
}
void sdpMainWindow::initSys(chwSysInfo *sys){
    memset(sys,0,sizeof(chwSysInfo));

    sys->transType =  0;
    sys->mediaServer = 9;
    sys->isMultCamera = 0;
    sys->usingDataServer = 0;

    strcpy(sys->localIp , "192.168.3.33");//本地ip
    sys->rtmpPort =  1935;
    sys->srtPort = 8080;
    sys->rtcPort = 1985;
    sys->rtcLocalPort =  16000;
    sys->httpPort =  8080;
    sys->dataPort =  9999;
    sys->hasLogFile= 0;
    sys->logLevel = 1;
    sys->logLevel = 1;
    sys->cameraCount = 3;
    strcpy( sys->cameraIndexs, "1");
    strcpy( sys->rtmpServerIP, "127.0.0.1");
    strcpy(sys->srtServerIP, "127.0.0.1");
    strcpy(sys->rtcServerIP, "127.0.0.1");
    strcpy( sys->httpServerIP, "127.0.0.1");
    strcpy( sys->dataServerIP, "127.0.0.1");
}

void sdpMainWindow::initEnc(chwVideoEncInfo *enc){
    memset(enc,0,sizeof(chwVideoEncInfo));
    enc->preset = 3;
    enc->level_idc =  31;
    enc->profile =  0;
    enc->keyint_max = 30;
    enc->enc_threads =  4;
    enc->createMeta = true;
    enc->gop = 30;

}

void sdpMainWindow::initRtc(chwRtcInfo *rtc){
    memset(rtc,0,sizeof(chwRtcInfo));
    rtc->sessionTimeout =  30*1000000;
    rtc->usingDatachannel =  1;
    rtc->hasIceServer = 0;
    rtc->iceStunPort = 3478;
    rtc->audioQueueCount =  5;
    rtc->videoQueueCount =  5;

    strcpy( rtc->iceServerIP, "127.0.0.1");

}

打印sdp

v=0
o=MetaRtc 140726066547688 2 IN IP4 0.0.0.0
s=MetaRtcSession
t=0 0
a=ice-lite
a=group:BUNDLE 0 1
a=msid-semantic: WMS live/livestream
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=ice-ufrag:3829
a=ice-pwd:41q6q68f8n58mleb76380ksr11245p4q
a=fingerprint:sha-256 FC:56:1B:EA:E6:F9:23:CD:34:22:B1:B9:8A:B2:4A:8C:C6:34:28:54:46:FE:CF:AD:05:7A:9F:6C:72:2A:EC:B9
a=setup:passive
a=mid:0
a=extmap:0 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/44100/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:192686677 cname:6a621o75scxudrl4
a=ssrc:192686677 msid:- x827358k-21pr-q9x2-335a-8m50f902017e
a=ssrc:192686677 mslabel:-
a=ssrc:192686677 label:x827358k-21pr-q9x2-335a-8m50f902017e
a=candidate:0 1 udp 2130706431 192.168.3.33 9091 typ host generation 0
m=video 9 UDP/TLS/RTP/SAVPF 125 114
c=IN IP4 0.0.0.0
a=ice-ufrag:3829
a=ice-pwd:41q6q68f8n58mleb76380ksr11245p4q
a=fingerprint:sha-256 FC:56:1B:EA:E6:F9:23:CD:34:22:B1:B9:8A:B2:4A:8C:C6:34:28:54:46:FE:CF:AD:05:7A:9F:6C:72:2A:EC:B9
a=setup:passive
a=mid:1
a=extmap:0 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:125 H264/90000
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:114 red/90000
a=ssrc:192686678 cname:6a621o75scxudrl4
a=ssrc:192686678 msid:- k913003w-1847-r191-141t-7x9w6j460504
a=ssrc:192686678 mslabel:-
a=ssrc:192686678 label:k913003w-1847-r191-141t-7x9w6j460504
a=candidate:0 1 udp 2130706431 192.168.3.33 9091 typ host generation 0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值