webrtc 打开Simulcast功能

webrtc 打开Simulcast功能

liwenlong_only 2018-11-01 10:53:51 3842 收藏 5

分类专栏: webrtc

版权

webrtc 开启Simulcast功能

webrtc自带了Simulcast功能,可以将一个分辨率的流编码成多个分辨率并发送,观看端可以根据带宽去动态的选择某个分辨率,也可以自己选择某个分辨率,据说在webrtc M70版本提供了对外的接口开启Simulcast,并 vp8,vp9,h264三种编码器都支持Simulcast功能,但是在M70版本以下并不支持h264编码器的Simulcast功能,如果在M70版本以下使用Simulcast功能,需要通过修改SDP来开启,话不多说,直接上代码:

  • 头文件
//
//  sdp_helpers.h
//
//  Created by ilong on 2018/10/29.
//  Copyright © 2018 ilong. All rights reserved.
//

#ifndef sdp_helpers_h
#define sdp_helpers_h

#include <stdio.h>
#include <string>
#include <vector>

class SdpHelpers {
   
public:
   template<typename T>
   static T StringTo(std::string str);
   
   template<typename T>
   static std::string ToString(T arg);
   
   // return sdp ,numSpatialLayers 表示开启几路流,一般是2
   static std::string EnableSimulcast(const std::string &sdp, const int numSpatialLayers);
   
private:
   SdpHelpers();
   ~SdpHelpers();
   static std::vector<std::string> GetFID(const std::string &sdp);
   static std::string GetSsrcTagValue(const std::string &sdp, uint64_t fid, std::string &tag);
   static std::string AddSim(std::vector<uint64_t> &spatialLayers);
   static std::string AddGroup(uint64_t spatialLayerId, uint64_t spatialLayerIdRtx);
   static std::string AddSpatialLayer(std::string &cname, std::string &msid, std::string &mslabel, std::string &label, uint64_t spatialLayerId, uint64_t spatialLayerIdRtx);
   static void StrReplace(std::string &baseString, std::string &src, std::string &dst);
   static std::string RemoveSsrcLine(std::string &sdp ,uint64_t fid);
   static void StringReplace( std::string &strBig, const std::string &strsrc, const std::string &strdst);
};

#endif /* sdp_helpers_h */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 实现文件
//
//  sdp_helpers.cpp
//
//  Created by ilong on 2018/10/29.
//  Copyright © 2018 ilong. All rights reserved.
//

#include "sdp_helpers.h"
#include <sstream>
#include <regex>

SdpHelpers::SdpHelpers(){
   
}

SdpHelpers::~SdpHelpers(){
   
}

template <typename T>
T SdpHelpers::StringTo(std::string str) {
   T tmp;
   std::stringstream ss;
   ss << str;
   ss >> tmp;
   return tmp;
}

template<typename T>
std::string SdpHelpers::ToString(T arg){
   std::stringstream ss;
   ss << arg;
   return ss.str();
}

std::string SdpHelpers::EnableSimulcast(const std::string &sdp, const int numSpatialLayers){
   std::string sdpStr = sdp;
   uint64_t baseSsrc = 0, baseSsrcRtx = 0;
   std::vector<std::string> results = SdpHelpers::GetFID(sdp);
   if (results.size()>2) {
      baseSsrc = SdpHelpers::StringTo<uint64_t>(results[1]);
      baseSsrcRtx = SdpHelpers::StringTo<uint64_t>(results[2]);
   }else{
      //LOGW("fid is empty.");
      return "";
   }
   std::string tag = "cname";
   std::string cname = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag);
   if (cname.length()<=0) {
      //LOGW("cname length is 0.");
      return "";
   }
   tag = "msid";
   std::string msid = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag);
   if (msid.length()<=0) {
      //LOGW("msid length is 0.");
      return "";
   }
   tag = "mslabel";
   std::string mslabel = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag);
   if (mslabel.length()<=0) {
      //LOGW("mslabel length is 0.");
      return "";
   }
   tag = "label";
   std::string label = SdpHelpers::GetSsrcTagValue(sdp, baseSsrc, tag);
   if (label.length()<=0) {
      //LOGW("label length is 0.");
      return "";
   }
   
   sdpStr = SdpHelpers::RemoveSsrcLine(sdpStr, baseSsrc);
   sdpStr = SdpHelpers::RemoveSsrcLine(sdpStr, baseSsrcRtx);
   
   std::vector<uint64_t> spatialLayers;
   spatialLayers.push_back(baseSsrc);
   std::vector<uint64_t> spatialLayersRtx;
   spatialLayersRtx.push_back(baseSsrcRtx);
   for (int i = 1; i<numSpatialLayers; i++) {
      spatialLayers.push_back(baseSsrc+i*1000);
      spatialLayersRtx.push_back(baseSsrcRtx+i*1000);
   }
   
   std::string result = SdpHelpers::AddSim(spatialLayers);
   for (int i = 0; i < spatialLayers.size(); i++) {
      result += SdpHelpers::AddGroup(spatialLayers[i], spatialLayersRtx[i]);
   }
   
   for (int i = 0; i < spatialLayers.size(); i++) {
      result += SdpHelpers::AddSpatialLayer(cname, msid, mslabel, label, spatialLayers[i], spatialLayersRtx[i]);
   }
   result += "a=x-google-flag:conference\r\n";
   SdpHelpers::StrReplace(sdpStr, results[0], result);
   return sdpStr;
}

std::vector<std::string> SdpHelpers::GetFID(const std::string &sdp){
   std::string pattern{ "a=ssrc-group:FID ([0-9]*) ([0-9]*)\r?\n" }; // id card
   std::regex re(pattern);
   std::smatch results;
   std::vector<std::string> res;
   res.clear();
   bool ret = std::regex_search(sdp, results, re);
   if (ret) {
      for (auto item:results) {
         res.push_back(item.str());
      }
   }
   return res;
}

std::string SdpHelpers::GetSsrcTagValue(const std::string &sdp, uint64_t fid, std::string &tag){
   std::stringstream ss;
   ss << "a=ssrc:" << fid <<" "<< tag <<":(.*)\r?\n";
   std::regex re(ss.str());
   std::smatch results;
   bool ret = std::regex_search(sdp, results, re);
   if (ret) {
      return results[1].str();
   }
   return "";
}

std::string SdpHelpers::AddSim(std::vector<uint64_t> &spatialLayers){
   std::string line{"a=ssrc-group:SIM"};
   for (auto item:spatialLayers) {
      line+=" "+SdpHelpers::ToString(item);
   }
   return line+"\r\n";
}

std::string SdpHelpers::AddGroup(uint64_t spatialLayerId, uint64_t spatialLayerIdRtx){
   return "a=ssrc-group:FID "+SdpHelpers::ToString(spatialLayerId)+" "+SdpHelpers::ToString(spatialLayerIdRtx)+"\r\n";
}

std::string SdpHelpers::AddSpatialLayer(std::string &cname, std::string &msid, std::string &mslabel, std::string &label, uint64_t spatialLayerId, uint64_t spatialLayerIdRtx){
   return "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" cname:"+cname+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" msid:"+msid+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" mslabel:"+mslabel+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerId)+" label:"+label+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" cname:"+cname+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" msid:"+msid+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" mslabel:"+mslabel+"\r\n"+
          "a=ssrc:"+SdpHelpers::ToString(spatialLayerIdRtx)+" label:"+label+"\r\n";
}

void SdpHelpers::StrReplace(std::string &baseString, std::string &src, std::string &dst){
   SdpHelpers::StringReplace(baseString, src, dst);
}

void SdpHelpers::StringReplace( std::string &strBig, const std::string &strsrc, const std::string &strdst){
   std::string::size_type pos = 0;
   std::string::size_type srclen = strsrc.size();
   std::string::size_type dstlen = strdst.size();
   
   while( (pos=strBig.find(strsrc, pos)) != std::string::npos ){
      strBig.replace( pos, srclen, strdst );
      pos += dstlen;
   }
}

std::string SdpHelpers::RemoveSsrcLine(std::string &sdp ,uint64_t fid){
   std::string retStr = sdp;
   std::stringstream ss;
   ss << "a=ssrc:" << fid <<".*\r?\n";
   std::regex re(ss.str());
   std::smatch results;
   //多次匹配
   while (std::regex_search(retStr, results, re)) {
      for (auto item:results) {
         SdpHelpers::StringReplace(retStr, item.str(), std::string(""));
      }
   }
   return retStr;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebRTC中,Simulcast是一种视频编码技术,它可以将视频流分为不同的质量层,以适应不同带宽和设备的需求。下面我将回答如何设置WebRTCSimulcast。 首先,为了在WebRTC中启用Simulcast,需要在SDP(Session Description Protocol)中添加相应的参数。SDP是一种用于描述会话的协议,包含了有关音视频编解码、网络连接和会话设置等信息。 在SDP中,需要添加以下参数: 1. "a=fmtp":这个参数用于指定Simulcast的编码器参数,例如帧率、分辨率等。 2. "a=ssrc-group":这个参数用于指定Simulcast流的组ID,并将相关流的SSRC(Synchronization Source)ID与组ID进行关联。 3. "a=ssrc":这个参数用于指定Simulcast流的SSRC ID,每个流都有一个唯一的SSRC ID。 接下来,在JavaScript代码中,可以使用WebRTC API来设置Simulcast。具体步骤如下: 1. 创建PeerConnection对象,并设置相应的STUN/TURN服务器信息。 2. 使用getUserMedia函数获取本地的音视频流。 3. 创建一个新的RTCRtpTransceiver对象,并通过设置direction属性来指定发送方向。 4. 使用addTransceiver函数将音视频流添加到PeerConnection中。 5. 使用createOffer函数创建一个SDP offer。 6. 在SDP offer中,设置Simulcast的相关参数,例如编码器参数、组ID和SSRC等。 7. 使用setLocalDescription函数将修改后的SDP offer设置为本地的描述。 8. 将修改后的SDP offer发送给远程端。 9. 远程端接收到SDP offer后,解析其中的Simulcast参数,并创建相应的SDP answer。 10. 使用setRemoteDescription函数将SDP answer设置为远程的描述。 通过以上步骤,即可成功设置WebRTCSimulcast。Simulcast可以提供更好的适应性,以适应不同网络环境和设备的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值