1. 程式人生 > >Janus客戶端修改WebRTC原始碼支援會議室功能

Janus客戶端修改WebRTC原始碼支援會議室功能

Janus客戶端使用最新版本的WebRTC的so,發現subscribe組時,不能看到火狐客戶端推送的視訊

分析日誌,原因是接收rtp包的receiver的sink中沒有被註冊任何接受者,所以解碼後的資料幀沒有被回撥到應用層。

 

經過分析,剛開始以為是mid不一致所致,後來發現,是底層庫對sendonly做了特殊處理:

火狐的SDP:mid為video字串


a=group:BUNDLE video


a=msid-semantic: WMS janus


m=video 9 UDP/TLS/RTP/SAVPF 96


c=IN IP4 11.12.115.200


a=sendonly


a=mid:video


a=rtcp-mux

Webrtc中生成的SDP:mid則為0


a=group:BUNDLE 0 1


a=msid-semantic: WMS ARDAMS


m=video 9 UDP/TLS/RTP/SAVPF 127 97 98 99 100 101 125 103 104


c=IN IP4 0.0.0.0


a=rtcp:9 IN IP4 0.0.0.0


a=ice-ufrag:sOgE


a=ice-pwd:OAEMHfMMr26hgYbs70QwRuVT


a=ice-options:trickle renomination

a=mid:0

 

而WebRTC庫中建立Peerconnection物件時,會預先建立一個transceiver(sender和receiver),但mid預設為0

修改前的程式碼:

RTCErrorOr<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
PeerConnection::AssociateTransceiver(cricket::ContentSource source,
                                     SdpType type,
                                     size_t mline_index,
                                     const ContentInfo& content,
                                     const ContentInfo* old_local_content,
                                     const ContentInfo* old_remote_content)
{
//...
 if (source == cricket::CS_LOCAL) {
    // Find the RtpTransceiver that corresponds to this m= section, using the
    // mapping between transceivers and m= section indices established when
    // creating the offer.
    if (!transceiver) { 
      transceiver = GetTransceiverByMLineIndex(mline_index);
    }
    if (!transceiver) {
      LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
                           "Unknown transceiver");
    }
  } else {
    RTC_DCHECK_EQ(source, cricket::CS_REMOTE);
    // If the m= section is sendrecv or recvonly, and there are RtpTransceivers
    // of the same type...
    if (!transceiver  
        RtpTransceiverDirectionHasRecv(media_desc->direction())) {
	  RTC_LOG(LS_INFO) << "continue find=" << media_desc->direction();
      transceiver = FindAvailableTransceiverToReceive(media_desc->type()); 
    }
    // If no RtpTransceiver was found in the previous step, create one with a
    // recvonly direction.
    if (!transceiver) {
      RTC_LOG(LS_INFO) << "Adding "
                       << cricket::MediaTypeToString(media_desc->type())
                       << " transceiver for MID=" << content.name
                       << " at i=" << mline_index
                       << " in response to the remote description.";
      auto sender =
          CreateSender(media_desc->type(), nullptr, {rtc::CreateRandomUuid()});
      std::string receiver_id;
      if (!media_desc->streams().empty()) {
        receiver_id = media_desc->streams()[0].id;
      } else {
        receiver_id = rtc::CreateRandomUuid();
      }
      auto receiver = CreateReceiver(media_desc->type(), receiver_id);
      transceiver = CreateAndAddTransceiver(sender, receiver);
      transceiver->internal()->set_direction(
          RtpTransceiverDirection::kRecvOnly);
    }

}

rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
PeerConnection::GetAssociatedTransceiver(const std::string& mid) const {
  RTC_DCHECK(IsUnifiedPlan());
  for (auto transceiver : transceivers_) {
  	
	RTC_LOG(LS_INFO) << ", mid:" << mid;
    if (transceiver->mid() == mid) {
      return transceiver;
    }
  }
  RTC_LOG(LS_INFO) << "GetAssociatedTransceiver is null, mid:" << mid;
  return nullptr;
}

修改後的程式碼:

RTCErrorOr<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
PeerConnection::AssociateTransceiver(cricket::ContentSource source,
                                     SdpType type,
                                     size_t mline_index,
                                     const ContentInfo& content,
                                     const ContentInfo* old_local_content,
                                     const ContentInfo* old_remote_content)
{
//...

  const MediaContentDescription* media_desc = content.media_description();
  auto transceiver = GetAssociatedTransceiver(content.name);
  if (source == cricket::CS_LOCAL) {
    // Find the RtpTransceiver that corresponds to this m= section, using the
    // mapping between transceivers and m= section indices established when
    // creating the offer.
    if (!transceiver) { 
      transceiver = GetTransceiverByMLineIndex(mline_index);
    }
    if (!transceiver) {
      LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
                           "Unknown transceiver");
    }
  } else {
    RTC_DCHECK_EQ(source, cricket::CS_REMOTE);
    // If the m= section is sendrecv or recvonly, and there are RtpTransceivers
    // of the same type...

    //modify start.
    if (!transceiver) {
	  RTC_LOG(LS_INFO) << "continue find=" << media_desc->direction();
      transceiver = FindAvailableTransceiverToReceive(media_desc->type());

      //remote sendonly ,so the client is recvonly
	  if (!RtpTransceiverDirectionHasRecv(media_desc->direction())) {
	      transceiver->internal()->set_direction(
	          RtpTransceiverDirection::kRecvOnly);
	  } 
    }
    //modify end.

    // If no RtpTransceiver was found in the previous step, create one with a
    // recvonly direction.
    if (!transceiver) {
      RTC_LOG(LS_INFO) << "Adding "
                       << cricket::MediaTypeToString(media_desc->type())
                       << " transceiver for MID=" << content.name
                       << " at i=" << mline_index
                       << " in response to the remote description.";
      auto sender =
          CreateSender(media_desc->type(), nullptr, {rtc::CreateRandomUuid()});
      std::string receiver_id;
      if (!media_desc->streams().empty()) {
        receiver_id = media_desc->streams()[0].id;
      } else {
        receiver_id = rtc::CreateRandomUuid();
      }
      auto receiver = CreateReceiver(media_desc->type(), receiver_id);
      transceiver = CreateAndAddTransceiver(sender, receiver);
      transceiver->internal()->set_direction(
          RtpTransceiverDirection::kRecvOnly);
    }
  }




}