1. 程式人生 > >webrtc 開啟Simulcast功能

webrtc 開啟Simulcast功能

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 */

  • 實現檔案
//
//  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;
}