LCOV - code coverage report
Current view: top level - media/webrtc/signaling/src/peerconnection - MediaPipelineFactory.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 447 0.2 %
Date: 2017-07-14 16:53:18 Functions: 2 19 10.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "logging.h"
       6             : #include "nsIGfxInfo.h"
       7             : #include "nsServiceManagerUtils.h"
       8             : 
       9             : #include "PeerConnectionImpl.h"
      10             : #include "PeerConnectionMedia.h"
      11             : #include "MediaPipelineFactory.h"
      12             : #include "MediaPipelineFilter.h"
      13             : #include "transportflow.h"
      14             : #include "transportlayer.h"
      15             : #include "transportlayerdtls.h"
      16             : #include "transportlayerice.h"
      17             : 
      18             : #include "signaling/src/jsep/JsepTrack.h"
      19             : #include "signaling/src/jsep/JsepTransport.h"
      20             : #include "signaling/src/common/PtrVector.h"
      21             : 
      22             : #include "MediaStreamTrack.h"
      23             : #include "nsIPrincipal.h"
      24             : #include "nsIDocument.h"
      25             : #include "mozilla/Preferences.h"
      26             : #include "MediaEngine.h"
      27             : 
      28             : #include "mozilla/Preferences.h"
      29             : 
      30             : #include "WebrtcGmpVideoCodec.h"
      31             : 
      32             : #include <stdlib.h>
      33             : 
      34             : namespace mozilla {
      35             : 
      36           0 : MOZ_MTLOG_MODULE("MediaPipelineFactory")
      37             : 
      38             : static nsresult
      39           0 : JsepCodecDescToCodecConfig(const JsepCodecDescription& aCodec,
      40             :                            AudioCodecConfig** aConfig)
      41             : {
      42           0 :   MOZ_ASSERT(aCodec.mType == SdpMediaSection::kAudio);
      43           0 :   if (aCodec.mType != SdpMediaSection::kAudio)
      44           0 :     return NS_ERROR_INVALID_ARG;
      45             : 
      46             :   const JsepAudioCodecDescription& desc =
      47           0 :       static_cast<const JsepAudioCodecDescription&>(aCodec);
      48             : 
      49             :   uint16_t pt;
      50             : 
      51           0 :   if (!desc.GetPtAsInt(&pt)) {
      52           0 :     MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << desc.mDefaultPt);
      53           0 :     return NS_ERROR_INVALID_ARG;
      54             :   }
      55             : 
      56           0 :   *aConfig = new AudioCodecConfig(pt,
      57             :                                   desc.mName,
      58           0 :                                   desc.mClock,
      59           0 :                                   desc.mPacketSize,
      60           0 :                                   desc.mForceMono ? 1 : desc.mChannels,
      61           0 :                                   desc.mBitrate,
      62           0 :                                   desc.mFECEnabled);
      63           0 :   (*aConfig)->mMaxPlaybackRate = desc.mMaxPlaybackRate;
      64           0 :   (*aConfig)->mDtmfEnabled = desc.mDtmfEnabled;
      65             : 
      66           0 :   return NS_OK;
      67             : }
      68             : 
      69             : static std::vector<JsepCodecDescription*>
      70           0 : GetCodecs(const JsepTrackNegotiatedDetails& aDetails)
      71             : {
      72             :   // We do not try to handle cases where a codec is not used on the primary
      73             :   // encoding.
      74           0 :   if (aDetails.GetEncodingCount()) {
      75           0 :     return aDetails.GetEncoding(0).GetCodecs();
      76             :   }
      77           0 :   return std::vector<JsepCodecDescription*>();
      78             : }
      79             : 
      80             : static nsresult
      81           0 : NegotiatedDetailsToAudioCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
      82             :                                      PtrVector<AudioCodecConfig>* aConfigs)
      83             : {
      84           0 :   std::vector<JsepCodecDescription*> codecs(GetCodecs(aDetails));
      85           0 :   for (const JsepCodecDescription* codec : codecs) {
      86             :     AudioCodecConfig* config;
      87           0 :     if (NS_FAILED(JsepCodecDescToCodecConfig(*codec, &config))) {
      88           0 :       return NS_ERROR_INVALID_ARG;
      89             :     }
      90           0 :     aConfigs->values.push_back(config);
      91             :   }
      92           0 :   return NS_OK;
      93             : }
      94             : 
      95             : static nsresult
      96           0 : JsepCodecDescToCodecConfig(const JsepCodecDescription& aCodec,
      97             :                            VideoCodecConfig** aConfig)
      98             : {
      99           0 :   MOZ_ASSERT(aCodec.mType == SdpMediaSection::kVideo);
     100           0 :   if (aCodec.mType != SdpMediaSection::kVideo) {
     101           0 :     MOZ_ASSERT(false, "JsepCodecDescription has wrong type");
     102             :     return NS_ERROR_INVALID_ARG;
     103             :   }
     104             : 
     105             :   const JsepVideoCodecDescription& desc =
     106           0 :       static_cast<const JsepVideoCodecDescription&>(aCodec);
     107             : 
     108             :   uint16_t pt;
     109             : 
     110           0 :   if (!desc.GetPtAsInt(&pt)) {
     111           0 :     MOZ_MTLOG(ML_ERROR, "Invalid payload type: " << desc.mDefaultPt);
     112           0 :     return NS_ERROR_INVALID_ARG;
     113             :   }
     114             : 
     115           0 :   UniquePtr<VideoCodecConfigH264> h264Config;
     116             : 
     117           0 :   if (desc.mName == "H264") {
     118           0 :     h264Config = MakeUnique<VideoCodecConfigH264>();
     119           0 :     size_t spropSize = sizeof(h264Config->sprop_parameter_sets);
     120           0 :     strncpy(h264Config->sprop_parameter_sets,
     121             :             desc.mSpropParameterSets.c_str(),
     122           0 :             spropSize);
     123           0 :     h264Config->sprop_parameter_sets[spropSize - 1] = '\0';
     124           0 :     h264Config->packetization_mode = desc.mPacketizationMode;
     125           0 :     h264Config->profile_level_id = desc.mProfileLevelId;
     126           0 :     h264Config->tias_bw = 0; // TODO. Issue 165.
     127             :   }
     128             : 
     129             :   VideoCodecConfig* configRaw;
     130           0 :   configRaw = new VideoCodecConfig(
     131           0 :       pt, desc.mName, desc.mConstraints, h264Config.get());
     132             : 
     133           0 :   configRaw->mAckFbTypes = desc.mAckFbTypes;
     134           0 :   configRaw->mNackFbTypes = desc.mNackFbTypes;
     135           0 :   configRaw->mCcmFbTypes = desc.mCcmFbTypes;
     136           0 :   configRaw->mRembFbSet = desc.RtcpFbRembIsSet();
     137           0 :   configRaw->mFECFbSet = desc.mFECEnabled;
     138           0 :   if (desc.mFECEnabled) {
     139           0 :     configRaw->mREDPayloadType = desc.mREDPayloadType;
     140           0 :     configRaw->mULPFECPayloadType = desc.mULPFECPayloadType;
     141             :   }
     142             : 
     143           0 :   *aConfig = configRaw;
     144           0 :   return NS_OK;
     145             : }
     146             : 
     147             : static nsresult
     148           0 : NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
     149             :                                      PtrVector<VideoCodecConfig>* aConfigs)
     150             : {
     151           0 :   std::vector<JsepCodecDescription*> codecs(GetCodecs(aDetails));
     152           0 :   for (const JsepCodecDescription* codec : codecs) {
     153             :     VideoCodecConfig* config;
     154           0 :     if (NS_FAILED(JsepCodecDescToCodecConfig(*codec, &config))) {
     155           0 :       return NS_ERROR_INVALID_ARG;
     156             :     }
     157             : 
     158           0 :     config->mTias = aDetails.GetTias();
     159             : 
     160           0 :     for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
     161           0 :       const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
     162           0 :       if (jsepEncoding.HasFormat(codec->mDefaultPt)) {
     163           0 :         VideoCodecConfig::SimulcastEncoding encoding;
     164           0 :         encoding.rid = jsepEncoding.mRid;
     165           0 :         encoding.constraints = jsepEncoding.mConstraints;
     166           0 :         config->mSimulcastEncodings.push_back(encoding);
     167             :       }
     168             :     }
     169             : 
     170           0 :     aConfigs->values.push_back(config);
     171             :   }
     172             : 
     173           0 :   return NS_OK;
     174             : }
     175             : 
     176             : // Accessing the PCMedia should be safe here because we shouldn't
     177             : // have enqueued this function unless it was still active and
     178             : // the ICE data is destroyed on the STS.
     179             : static void
     180           0 : FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
     181             :                         RefPtr<TransportFlow> aFlow, size_t aLevel,
     182             :                         bool aIsRtcp,
     183             :                         nsAutoPtr<PtrVector<TransportLayer> > aLayerList)
     184             : {
     185             :   TransportLayerIce* ice =
     186           0 :       static_cast<TransportLayerIce*>(aLayerList->values.front());
     187           0 :   ice->SetParameters(aPCMedia->ice_ctx(),
     188           0 :                      aPCMedia->ice_media_stream(aLevel),
     189           0 :                      aIsRtcp ? 2 : 1);
     190             :   nsAutoPtr<std::queue<TransportLayer*> > layerQueue(
     191           0 :       new std::queue<TransportLayer*>);
     192           0 :   for (auto& value : aLayerList->values) {
     193           0 :     layerQueue->push(value);
     194             :   }
     195           0 :   aLayerList->values.clear();
     196           0 :   (void)aFlow->PushLayers(layerQueue); // TODO(bug 854518): Process errors.
     197           0 : }
     198             : 
     199             : static void
     200           0 : AddNewIceStreamForRestart_s(RefPtr<PeerConnectionMedia> aPCMedia,
     201             :                             RefPtr<TransportFlow> aFlow,
     202             :                             size_t aLevel,
     203             :                             bool aIsRtcp)
     204             : {
     205             :   TransportLayerIce* ice =
     206           0 :       static_cast<TransportLayerIce*>(aFlow->GetLayer("ice"));
     207           0 :   ice->SetParameters(aPCMedia->ice_ctx(),
     208           0 :                      aPCMedia->ice_media_stream(aLevel),
     209           0 :                      aIsRtcp ? 2 : 1);
     210           0 : }
     211             : 
     212             : nsresult
     213           0 : MediaPipelineFactory::CreateOrGetTransportFlow(
     214             :     size_t aLevel,
     215             :     bool aIsRtcp,
     216             :     const JsepTransport& aTransport,
     217             :     RefPtr<TransportFlow>* aFlowOutparam)
     218             : {
     219             :   nsresult rv;
     220           0 :   RefPtr<TransportFlow> flow;
     221             : 
     222           0 :   flow = mPCMedia->GetTransportFlow(aLevel, aIsRtcp);
     223           0 :   if (flow) {
     224           0 :     if (mPCMedia->IsIceRestarting()) {
     225           0 :       MOZ_MTLOG(ML_INFO, "Flow[" << flow->id() << "]: "
     226             :                                  << "detected ICE restart - level: "
     227             :                                  << aLevel << " rtcp: " << aIsRtcp);
     228             : 
     229           0 :       rv = mPCMedia->GetSTSThread()->Dispatch(
     230           0 :           WrapRunnableNM(AddNewIceStreamForRestart_s,
     231             :                          mPCMedia, flow, aLevel, aIsRtcp),
     232           0 :           NS_DISPATCH_NORMAL);
     233           0 :       if (NS_FAILED(rv)) {
     234           0 :         MOZ_MTLOG(ML_ERROR, "Failed to dispatch AddNewIceStreamForRestart_s");
     235           0 :         return rv;
     236             :       }
     237             :     }
     238             : 
     239           0 :     *aFlowOutparam = flow;
     240           0 :     return NS_OK;
     241             :   }
     242             : 
     243           0 :   std::ostringstream osId;
     244           0 :   osId << mPC->GetHandle() << ":" << aLevel << ","
     245           0 :        << (aIsRtcp ? "rtcp" : "rtp");
     246           0 :   flow = new TransportFlow(osId.str());
     247             : 
     248             :   // The media streams are made on STS so we need to defer setup.
     249           0 :   auto ice = MakeUnique<TransportLayerIce>(mPC->GetHandle());
     250           0 :   auto dtls = MakeUnique<TransportLayerDtls>();
     251           0 :   dtls->SetRole(aTransport.mDtls->GetRole() ==
     252             :                         JsepDtlsTransport::kJsepDtlsClient
     253             :                     ? TransportLayerDtls::CLIENT
     254           0 :                     : TransportLayerDtls::SERVER);
     255             : 
     256           0 :   RefPtr<DtlsIdentity> pcid = mPC->Identity();
     257           0 :   if (!pcid) {
     258           0 :     MOZ_MTLOG(ML_ERROR, "Failed to get DTLS identity.");
     259           0 :     return NS_ERROR_FAILURE;
     260             :   }
     261           0 :   dtls->SetIdentity(pcid);
     262             : 
     263             :   const SdpFingerprintAttributeList& fingerprints =
     264           0 :       aTransport.mDtls->GetFingerprints();
     265           0 :   for (const auto& fingerprint : fingerprints.mFingerprints) {
     266           0 :     std::ostringstream ss;
     267           0 :     ss << fingerprint.hashFunc;
     268           0 :     rv = dtls->SetVerificationDigest(ss.str(), &fingerprint.fingerprint[0],
     269           0 :                                      fingerprint.fingerprint.size());
     270           0 :     if (NS_FAILED(rv)) {
     271           0 :       MOZ_MTLOG(ML_ERROR, "Could not set fingerprint");
     272           0 :       return rv;
     273             :     }
     274             :   }
     275             : 
     276           0 :   std::vector<uint16_t> srtpCiphers;
     277           0 :   srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80);
     278           0 :   srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_32);
     279             : 
     280           0 :   rv = dtls->SetSrtpCiphers(srtpCiphers);
     281           0 :   if (NS_FAILED(rv)) {
     282           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't set SRTP ciphers");
     283           0 :     return rv;
     284             :   }
     285             : 
     286             :   // Always permits negotiation of the confidential mode.
     287             :   // Only allow non-confidential (which is an allowed default),
     288             :   // if we aren't confidential.
     289           0 :   std::set<std::string> alpn;
     290           0 :   std::string alpnDefault = "";
     291           0 :   alpn.insert("c-webrtc");
     292           0 :   if (!mPC->PrivacyRequested()) {
     293           0 :     alpnDefault = "webrtc";
     294           0 :     alpn.insert(alpnDefault);
     295             :   }
     296           0 :   rv = dtls->SetAlpn(alpn, alpnDefault);
     297           0 :   if (NS_FAILED(rv)) {
     298           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't set ALPN");
     299           0 :     return rv;
     300             :   }
     301             : 
     302           0 :   nsAutoPtr<PtrVector<TransportLayer> > layers(new PtrVector<TransportLayer>);
     303           0 :   layers->values.push_back(ice.release());
     304           0 :   layers->values.push_back(dtls.release());
     305             : 
     306           0 :   rv = mPCMedia->GetSTSThread()->Dispatch(
     307           0 :       WrapRunnableNM(FinalizeTransportFlow_s, mPCMedia, flow, aLevel, aIsRtcp,
     308             :                      layers),
     309           0 :       NS_DISPATCH_NORMAL);
     310           0 :   if (NS_FAILED(rv)) {
     311           0 :     MOZ_MTLOG(ML_ERROR, "Failed to dispatch FinalizeTransportFlow_s");
     312           0 :     return rv;
     313             :   }
     314             : 
     315           0 :   mPCMedia->AddTransportFlow(aLevel, aIsRtcp, flow);
     316             : 
     317           0 :   *aFlowOutparam = flow;
     318             : 
     319           0 :   return NS_OK;
     320             : }
     321             : 
     322             : nsresult
     323           0 : MediaPipelineFactory::GetTransportParameters(
     324             :     const JsepTrackPair& aTrackPair,
     325             :     const JsepTrack& aTrack,
     326             :     size_t* aLevelOut,
     327             :     RefPtr<TransportFlow>* aRtpOut,
     328             :     RefPtr<TransportFlow>* aRtcpOut,
     329             :     nsAutoPtr<MediaPipelineFilter>* aFilterOut)
     330             : {
     331           0 :   *aLevelOut = aTrackPair.mLevel;
     332             : 
     333           0 :   size_t transportLevel = aTrackPair.HasBundleLevel() ?
     334             :                           aTrackPair.BundleLevel() :
     335           0 :                           aTrackPair.mLevel;
     336             : 
     337             :   nsresult rv = CreateOrGetTransportFlow(
     338           0 :       transportLevel, false, *aTrackPair.mRtpTransport, aRtpOut);
     339           0 :   if (NS_FAILED(rv)) {
     340           0 :     return rv;
     341             :   }
     342           0 :   MOZ_ASSERT(aRtpOut);
     343             : 
     344           0 :   if (aTrackPair.mRtcpTransport) {
     345             :     rv = CreateOrGetTransportFlow(
     346           0 :         transportLevel, true, *aTrackPair.mRtcpTransport, aRtcpOut);
     347           0 :     if (NS_FAILED(rv)) {
     348           0 :       return rv;
     349             :     }
     350           0 :     MOZ_ASSERT(aRtcpOut);
     351             :   }
     352             : 
     353           0 :   if (aTrackPair.HasBundleLevel()) {
     354           0 :     bool receiving = aTrack.GetDirection() == sdp::kRecv;
     355             : 
     356           0 :     *aFilterOut = new MediaPipelineFilter;
     357             : 
     358           0 :     if (receiving) {
     359             :       // Add remote SSRCs so we can distinguish which RTP packets actually
     360             :       // belong to this pipeline (also RTCP sender reports).
     361           0 :       for (unsigned int ssrc : aTrack.GetSsrcs()) {
     362           0 :         (*aFilterOut)->AddRemoteSSRC(ssrc);
     363             :       }
     364             : 
     365             :       // TODO(bug 1105005): Tell the filter about the mid for this track
     366             : 
     367             :       // Add unique payload types as a last-ditch fallback
     368           0 :       auto uniquePts = aTrack.GetNegotiatedDetails()->GetUniquePayloadTypes();
     369           0 :       for (unsigned char& uniquePt : uniquePts) {
     370           0 :         (*aFilterOut)->AddUniquePT(uniquePt);
     371             :       }
     372             :     }
     373             :   }
     374             : 
     375           0 :   return NS_OK;
     376             : }
     377             : 
     378             : nsresult
     379           0 : MediaPipelineFactory::CreateOrUpdateMediaPipeline(
     380             :     const JsepTrackPair& aTrackPair,
     381             :     const JsepTrack& aTrack)
     382             : {
     383             :   // The GMP code is all the way on the other side of webrtc.org, and it is not
     384             :   // feasible to plumb this information all the way through. So, we set it (for
     385             :   // the duration of this call) in a global variable. This allows the GMP code
     386             :   // to report errors to the PC.
     387           0 :   WebrtcGmpPCHandleSetter setter(mPC->GetHandle());
     388             : 
     389           0 :   MOZ_ASSERT(aTrackPair.mRtpTransport);
     390             : 
     391           0 :   bool receiving = aTrack.GetDirection() == sdp::kRecv;
     392             : 
     393             :   size_t level;
     394           0 :   RefPtr<TransportFlow> rtpFlow;
     395           0 :   RefPtr<TransportFlow> rtcpFlow;
     396           0 :   nsAutoPtr<MediaPipelineFilter> filter;
     397             : 
     398             :   nsresult rv = GetTransportParameters(aTrackPair,
     399             :                                        aTrack,
     400             :                                        &level,
     401             :                                        &rtpFlow,
     402             :                                        &rtcpFlow,
     403           0 :                                        &filter);
     404           0 :   if (NS_FAILED(rv)) {
     405           0 :     MOZ_MTLOG(ML_ERROR, "Failed to get transport parameters for pipeline, rv="
     406             :               << static_cast<unsigned>(rv));
     407           0 :     return rv;
     408             :   }
     409             : 
     410           0 :   if (aTrack.GetMediaType() == SdpMediaSection::kApplication) {
     411             :     // GetTransportParameters has already done everything we need for
     412             :     // datachannel.
     413           0 :     return NS_OK;
     414             :   }
     415             : 
     416             :   // Find the stream we need
     417             :   SourceStreamInfo* stream;
     418           0 :   if (receiving) {
     419           0 :     stream = mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
     420             :   } else {
     421           0 :     stream = mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
     422             :   }
     423             : 
     424           0 :   if (!stream) {
     425           0 :     MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
     426             :               << " stream id " << aTrack.GetStreamId() << " was never added");
     427           0 :     MOZ_ASSERT(false);
     428             :     return NS_ERROR_FAILURE;
     429             :   }
     430             : 
     431           0 :   if (!stream->HasTrack(aTrack.GetTrackId())) {
     432           0 :     MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
     433             :               << " track id " << aTrack.GetTrackId() << " was never added");
     434           0 :     MOZ_ASSERT(false);
     435             :     return NS_ERROR_FAILURE;
     436             :   }
     437             : 
     438           0 :   RefPtr<MediaSessionConduit> conduit;
     439           0 :   if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
     440           0 :     rv = GetOrCreateAudioConduit(aTrackPair, aTrack, &conduit);
     441           0 :     if (NS_FAILED(rv)) {
     442           0 :       return rv;
     443             :     }
     444           0 :   } else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
     445           0 :     rv = GetOrCreateVideoConduit(aTrackPair, aTrack, &conduit);
     446           0 :     if (NS_FAILED(rv)) {
     447           0 :       return rv;
     448             :     }
     449           0 :     conduit->SetPCHandle(mPC->GetHandle());
     450             :   } else {
     451             :     // We've created the TransportFlow, nothing else to do here.
     452           0 :     return NS_OK;
     453             :   }
     454             : 
     455           0 :   if (aTrack.GetActive()) {
     456           0 :     if (receiving) {
     457           0 :       auto error = conduit->StartReceiving();
     458           0 :       if (error) {
     459           0 :         MOZ_MTLOG(ML_ERROR, "StartReceiving failed: " << error);
     460           0 :         return NS_ERROR_FAILURE;
     461             :       }
     462             :     } else {
     463           0 :       auto error = conduit->StartTransmitting();
     464           0 :       if (error) {
     465           0 :         MOZ_MTLOG(ML_ERROR, "StartTransmitting failed: " << error);
     466           0 :         return NS_ERROR_FAILURE;
     467             :       }
     468             :     }
     469             :   } else {
     470           0 :     if (receiving) {
     471           0 :       auto error = conduit->StopReceiving();
     472           0 :       if (error) {
     473           0 :         MOZ_MTLOG(ML_ERROR, "StopReceiving failed: " << error);
     474           0 :         return NS_ERROR_FAILURE;
     475             :       }
     476             :     } else {
     477           0 :       auto error = conduit->StopTransmitting();
     478           0 :       if (error) {
     479           0 :         MOZ_MTLOG(ML_ERROR, "StopTransmitting failed: " << error);
     480           0 :         return NS_ERROR_FAILURE;
     481             :       }
     482             :     }
     483             :   }
     484             : 
     485             :   RefPtr<MediaPipeline> pipeline =
     486           0 :     stream->GetPipelineByTrackId_m(aTrack.GetTrackId());
     487             : 
     488           0 :   if (pipeline && pipeline->level() != static_cast<int>(level)) {
     489           0 :     MOZ_MTLOG(ML_WARNING, "Track " << aTrack.GetTrackId() <<
     490             :                           " has moved from level " << pipeline->level() <<
     491             :                           " to level " << level <<
     492             :                           ". This requires re-creating the MediaPipeline.");
     493             :     RefPtr<dom::MediaStreamTrack> domTrack =
     494           0 :       stream->GetTrackById(aTrack.GetTrackId());
     495           0 :     MOZ_ASSERT(domTrack, "MediaPipeline existed for a track, but no MediaStreamTrack");
     496             : 
     497             :     // Since we do not support changing the conduit on a pre-existing
     498             :     // MediaPipeline
     499           0 :     pipeline = nullptr;
     500           0 :     stream->RemoveTrack(aTrack.GetTrackId());
     501           0 :     stream->AddTrack(aTrack.GetTrackId(), domTrack);
     502             :   }
     503             : 
     504           0 :   if (pipeline) {
     505           0 :     pipeline->UpdateTransport_m(level, rtpFlow, rtcpFlow, filter);
     506           0 :     return NS_OK;
     507             :   }
     508             : 
     509           0 :   MOZ_MTLOG(ML_DEBUG,
     510             :             "Creating media pipeline"
     511             :                 << " m-line index=" << aTrackPair.mLevel
     512             :                 << " type=" << aTrack.GetMediaType()
     513             :                 << " direction=" << aTrack.GetDirection());
     514             : 
     515           0 :   if (receiving) {
     516           0 :     rv = CreateMediaPipelineReceiving(aTrackPair, aTrack,
     517             :                                       level, rtpFlow, rtcpFlow, filter,
     518           0 :                                       conduit);
     519           0 :     if (NS_FAILED(rv))
     520           0 :       return rv;
     521             :   } else {
     522           0 :     rv = CreateMediaPipelineSending(aTrackPair, aTrack,
     523             :                                     level, rtpFlow, rtcpFlow, filter,
     524           0 :                                     conduit);
     525           0 :     if (NS_FAILED(rv))
     526           0 :       return rv;
     527             :   }
     528             : 
     529           0 :   return NS_OK;
     530             : }
     531             : 
     532             : nsresult
     533           0 : MediaPipelineFactory::CreateMediaPipelineReceiving(
     534             :     const JsepTrackPair& aTrackPair,
     535             :     const JsepTrack& aTrack,
     536             :     size_t aLevel,
     537             :     RefPtr<TransportFlow> aRtpFlow,
     538             :     RefPtr<TransportFlow> aRtcpFlow,
     539             :     nsAutoPtr<MediaPipelineFilter> aFilter,
     540             :     const RefPtr<MediaSessionConduit>& aConduit)
     541             : {
     542             :   // We will error out earlier if this isn't here.
     543             :   RefPtr<RemoteSourceStreamInfo> stream =
     544           0 :       mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
     545             : 
     546           0 :   RefPtr<MediaPipelineReceive> pipeline;
     547             : 
     548           0 :   TrackID numericTrackId = stream->GetNumericTrackId(aTrack.GetTrackId());
     549           0 :   MOZ_ASSERT(IsTrackIDExplicit(numericTrackId));
     550             : 
     551           0 :   MOZ_MTLOG(ML_DEBUG, __FUNCTION__ << ": Creating pipeline for "
     552             :             << numericTrackId << " -> " << aTrack.GetTrackId());
     553             : 
     554           0 :   if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
     555             :     pipeline = new MediaPipelineReceiveAudio(
     556           0 :         mPC->GetHandle(),
     557           0 :         mPC->GetMainThread().get(),
     558           0 :         mPC->GetSTSThread(),
     559           0 :         stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
     560           0 :         aTrack.GetTrackId(),
     561             :         numericTrackId,
     562             :         aLevel,
     563           0 :         static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
     564             :         aRtpFlow,
     565             :         aRtcpFlow,
     566           0 :         aFilter);
     567           0 :   } else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
     568             :     pipeline = new MediaPipelineReceiveVideo(
     569           0 :         mPC->GetHandle(),
     570           0 :         mPC->GetMainThread().get(),
     571           0 :         mPC->GetSTSThread(),
     572           0 :         stream->GetMediaStream()->GetInputStream()->AsSourceStream(),
     573           0 :         aTrack.GetTrackId(),
     574             :         numericTrackId,
     575             :         aLevel,
     576           0 :         static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
     577             :         aRtpFlow,
     578             :         aRtcpFlow,
     579           0 :         aFilter);
     580             :   } else {
     581           0 :     MOZ_ASSERT(false);
     582             :     MOZ_MTLOG(ML_ERROR, "Invalid media type in CreateMediaPipelineReceiving");
     583             :     return NS_ERROR_FAILURE;
     584             :   }
     585             : 
     586           0 :   nsresult rv = pipeline->Init();
     587           0 :   if (NS_FAILED(rv)) {
     588           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't initialize receiving pipeline");
     589           0 :     return rv;
     590             :   }
     591             : 
     592           0 :   rv = stream->StorePipeline(aTrack.GetTrackId(),
     593           0 :                              RefPtr<MediaPipeline>(pipeline));
     594           0 :   if (NS_FAILED(rv)) {
     595           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
     596             :                         static_cast<unsigned>(rv));
     597           0 :     return rv;
     598             :   }
     599             : 
     600           0 :   stream->SyncPipeline(pipeline);
     601             : 
     602           0 :   return NS_OK;
     603             : }
     604             : 
     605             : nsresult
     606           0 : MediaPipelineFactory::CreateMediaPipelineSending(
     607             :     const JsepTrackPair& aTrackPair,
     608             :     const JsepTrack& aTrack,
     609             :     size_t aLevel,
     610             :     RefPtr<TransportFlow> aRtpFlow,
     611             :     RefPtr<TransportFlow> aRtcpFlow,
     612             :     nsAutoPtr<MediaPipelineFilter> aFilter,
     613             :     const RefPtr<MediaSessionConduit>& aConduit)
     614             : {
     615             :   nsresult rv;
     616             : 
     617             :   // This is checked earlier
     618             :   RefPtr<LocalSourceStreamInfo> stream =
     619           0 :       mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
     620             : 
     621             :   dom::MediaStreamTrack* track =
     622           0 :     stream->GetTrackById(aTrack.GetTrackId());
     623           0 :   MOZ_ASSERT(track);
     624             : 
     625             :   // Now we have all the pieces, create the pipeline
     626             :   RefPtr<MediaPipelineTransmit> pipeline = new MediaPipelineTransmit(
     627           0 :       mPC->GetHandle(),
     628           0 :       mPC->GetMainThread().get(),
     629           0 :       mPC->GetSTSThread(),
     630             :       track,
     631           0 :       aTrack.GetTrackId(),
     632             :       aLevel,
     633             :       aConduit,
     634             :       aRtpFlow,
     635             :       aRtcpFlow,
     636           0 :       aFilter);
     637             : 
     638             :   // implement checking for peerIdentity (where failure == black/silence)
     639           0 :   nsIDocument* doc = mPC->GetWindow()->GetExtantDoc();
     640           0 :   if (doc) {
     641           0 :     pipeline->UpdateSinkIdentity_m(track,
     642             :                                    doc->NodePrincipal(),
     643           0 :                                    mPC->GetPeerIdentity());
     644             :   } else {
     645           0 :     MOZ_MTLOG(ML_ERROR, "Cannot initialize pipeline without attached doc");
     646           0 :     return NS_ERROR_FAILURE; // Don't remove this till we know it's safe.
     647             :   }
     648             : 
     649           0 :   rv = pipeline->Init();
     650           0 :   if (NS_FAILED(rv)) {
     651           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't initialize sending pipeline");
     652           0 :     return rv;
     653             :   }
     654             : 
     655           0 :   rv = stream->StorePipeline(aTrack.GetTrackId(),
     656           0 :                              RefPtr<MediaPipeline>(pipeline));
     657           0 :   if (NS_FAILED(rv)) {
     658           0 :     MOZ_MTLOG(ML_ERROR, "Couldn't store receiving pipeline " <<
     659             :                         static_cast<unsigned>(rv));
     660           0 :     return rv;
     661             :   }
     662             : 
     663           0 :   return NS_OK;
     664             : }
     665             : 
     666             : nsresult
     667           0 : MediaPipelineFactory::GetOrCreateAudioConduit(
     668             :     const JsepTrackPair& aTrackPair,
     669             :     const JsepTrack& aTrack,
     670             :     RefPtr<MediaSessionConduit>* aConduitp)
     671             : {
     672             : 
     673           0 :   if (!aTrack.GetNegotiatedDetails()) {
     674           0 :     MOZ_ASSERT(false, "Track is missing negotiated details");
     675             :     return NS_ERROR_INVALID_ARG;
     676             :   }
     677             : 
     678           0 :   bool receiving = aTrack.GetDirection() == sdp::kRecv;
     679             : 
     680             :   RefPtr<AudioSessionConduit> conduit =
     681           0 :     mPCMedia->GetAudioConduit(aTrackPair.mLevel);
     682             : 
     683           0 :   if (!conduit) {
     684           0 :     conduit = AudioSessionConduit::Create();
     685           0 :     if (!conduit) {
     686           0 :       MOZ_MTLOG(ML_ERROR, "Could not create audio conduit");
     687           0 :       return NS_ERROR_FAILURE;
     688             :     }
     689             : 
     690           0 :     mPCMedia->AddAudioConduit(aTrackPair.mLevel, conduit);
     691             :   }
     692             : 
     693           0 :   PtrVector<AudioCodecConfig> configs;
     694             :   nsresult rv = NegotiatedDetailsToAudioCodecConfigs(
     695           0 :       *aTrack.GetNegotiatedDetails(), &configs);
     696             : 
     697           0 :   if (NS_FAILED(rv)) {
     698           0 :     MOZ_MTLOG(ML_ERROR, "Failed to convert JsepCodecDescriptions to "
     699             :                         "AudioCodecConfigs.");
     700           0 :     return rv;
     701             :   }
     702             : 
     703           0 :   if (configs.values.empty()) {
     704           0 :     MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs");
     705           0 :     return NS_ERROR_FAILURE;
     706             :   }
     707             : 
     708           0 :   if (receiving) {
     709           0 :     auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
     710             : 
     711           0 :     if (error) {
     712           0 :       MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
     713           0 :       return NS_ERROR_FAILURE;
     714             :     }
     715             : 
     716           0 :     if (!aTrackPair.mSending) {
     717             :       // No send track, but we still need to configure an SSRC for receiver
     718             :       // reports.
     719           0 :       if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
     720           0 :         MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
     721           0 :         return NS_ERROR_FAILURE;
     722             :       }
     723             :     }
     724             :   } else {
     725           0 :     auto ssrcs = aTrack.GetSsrcs();
     726           0 :     if (!ssrcs.empty()) {
     727           0 :       if (!conduit->SetLocalSSRCs(ssrcs)) {
     728           0 :         MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
     729           0 :         return NS_ERROR_FAILURE;
     730             :       }
     731             :     }
     732             : 
     733           0 :     conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
     734             : 
     735           0 :     if (configs.values.size() > 1
     736           0 :         && configs.values.back()->mName == "telephone-event") {
     737             :       // we have a telephone event codec, so we need to make sure
     738             :       // the dynamic pt is set properly
     739           0 :       conduit->SetDtmfPayloadType(configs.values.back()->mType,
     740           0 :                                   configs.values.back()->mFreq);
     741             :     }
     742             : 
     743           0 :     auto error = conduit->ConfigureSendMediaCodec(configs.values[0]);
     744           0 :     if (error) {
     745           0 :       MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
     746           0 :       return NS_ERROR_FAILURE;
     747             :     }
     748             : 
     749             :     const SdpExtmapAttributeList::Extmap* audioLevelExt =
     750           0 :         aTrack.GetNegotiatedDetails()->GetExt(
     751           0 :             "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
     752             : 
     753           0 :     if (audioLevelExt) {
     754           0 :       MOZ_MTLOG(ML_DEBUG, "Calling EnableAudioLevelExtension");
     755           0 :       error = conduit->EnableAudioLevelExtension(true, audioLevelExt->entry);
     756             : 
     757           0 :       if (error) {
     758           0 :         MOZ_MTLOG(ML_ERROR, "EnableAudioLevelExtension failed: " << error);
     759           0 :         return NS_ERROR_FAILURE;
     760             :       }
     761             :     }
     762             :   }
     763             : 
     764           0 :   *aConduitp = conduit;
     765             : 
     766           0 :   return NS_OK;
     767             : }
     768             : 
     769             : nsresult
     770           0 : MediaPipelineFactory::GetOrCreateVideoConduit(
     771             :     const JsepTrackPair& aTrackPair,
     772             :     const JsepTrack& aTrack,
     773             :     RefPtr<MediaSessionConduit>* aConduitp)
     774             : {
     775           0 :   if (!aTrack.GetNegotiatedDetails()) {
     776           0 :     MOZ_ASSERT(false, "Track is missing negotiated details");
     777             :     return NS_ERROR_INVALID_ARG;
     778             :   }
     779             : 
     780           0 :   bool receiving = aTrack.GetDirection() == sdp::kRecv;
     781             : 
     782             :   RefPtr<VideoSessionConduit> conduit =
     783           0 :     mPCMedia->GetVideoConduit(aTrackPair.mLevel);
     784             : 
     785           0 :   if (!conduit) {
     786           0 :     conduit = VideoSessionConduit::Create(mPCMedia->mCall);
     787           0 :     if (!conduit) {
     788           0 :       MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
     789           0 :       return NS_ERROR_FAILURE;
     790             :     }
     791             : 
     792           0 :     mPCMedia->AddVideoConduit(aTrackPair.mLevel, conduit);
     793             :   }
     794             : 
     795           0 :   PtrVector<VideoCodecConfig> configs;
     796             :   nsresult rv = NegotiatedDetailsToVideoCodecConfigs(
     797           0 :       *aTrack.GetNegotiatedDetails(), &configs);
     798             : 
     799           0 :   if (NS_FAILED(rv)) {
     800           0 :     MOZ_MTLOG(ML_ERROR, "Failed to convert JsepCodecDescriptions to "
     801             :                         "VideoCodecConfigs.");
     802           0 :     return rv;
     803             :   }
     804             : 
     805           0 :   if (configs.values.empty()) {
     806           0 :     MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs");
     807           0 :     return NS_ERROR_FAILURE;
     808             :   }
     809             : 
     810             :   const std::vector<uint32_t>* ssrcs;
     811             : 
     812           0 :   const JsepTrackNegotiatedDetails* details = aTrack.GetNegotiatedDetails();
     813           0 :   std::vector<webrtc::RtpExtension> extmaps;
     814           0 :   if (details) {
     815             :     // @@NG read extmap from track
     816           0 :     details->ForEachRTPHeaderExtension(
     817           0 :       [&extmaps](const SdpExtmapAttributeList::Extmap& extmap)
     818           0 :     {
     819           0 :       extmaps.emplace_back(extmap.extensionname,extmap.entry);
     820           0 :     });
     821             :   }
     822             : 
     823           0 :   if (receiving) {
     824             :     // NOTE(pkerr) - the Call API requires the both local_ssrc and remote_ssrc be
     825             :     // set to a non-zero value or the CreateVideo...Stream call will fail.
     826           0 :     if (aTrackPair.mSending) {
     827           0 :       ssrcs = &aTrackPair.mSending->GetSsrcs();
     828           0 :       if (!ssrcs->empty()) {
     829           0 :         conduit->SetLocalSSRCs(*ssrcs);
     830             :       }
     831             :     } else {
     832             :       // No send track, but we still need to configure an SSRC for receiver
     833             :       // reports.
     834           0 :       if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
     835           0 :         MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
     836           0 :         return NS_ERROR_FAILURE;
     837             :       }
     838             :     }
     839             : 
     840           0 :     ssrcs = &aTrack.GetSsrcs();
     841             :     // NOTE(pkerr) - this is new behavior. Needed because the CreateVideoReceiveStream
     842             :     // method of the Call API will assert (in debug) and fail if a value is not provided
     843             :     // for the remote_ssrc that will be used by the far-end sender.
     844           0 :     if (!ssrcs->empty()) {
     845           0 :       conduit->SetRemoteSSRC(ssrcs->front());
     846             :     }
     847             : 
     848           0 :     if (!extmaps.empty()) {
     849           0 :       conduit->SetLocalRTPExtensions(false, extmaps);
     850             :     }
     851           0 :     auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
     852           0 :     if (error) {
     853           0 :       MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
     854           0 :       return NS_ERROR_FAILURE;
     855             :     }
     856             :   } else { //Create a send side
     857             :     // For now we only expect to have one ssrc per local track.
     858           0 :     ssrcs = &aTrack.GetSsrcs();
     859           0 :     if (ssrcs->empty()) {
     860           0 :       MOZ_MTLOG(ML_ERROR, "No SSRC set for send track");
     861           0 :       return NS_ERROR_FAILURE;
     862             :     }
     863             : 
     864           0 :     if (!conduit->SetLocalSSRCs(*ssrcs)) {
     865           0 :       MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
     866           0 :       return NS_ERROR_FAILURE;
     867             :     }
     868             : 
     869           0 :     conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
     870             : 
     871           0 :     rv = ConfigureVideoCodecMode(aTrack, *conduit);
     872           0 :     if (NS_FAILED(rv)) {
     873           0 :       return rv;
     874             :     }
     875             : 
     876           0 :     if (!extmaps.empty()) {
     877           0 :       conduit->SetLocalRTPExtensions(true, extmaps);
     878             :     }
     879           0 :     auto error = conduit->ConfigureSendMediaCodec(configs.values[0]);
     880           0 :     if (error) {
     881           0 :       MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
     882           0 :       return NS_ERROR_FAILURE;
     883             :     }
     884             :   }
     885             : 
     886           0 :   *aConduitp = conduit;
     887             : 
     888           0 :   return NS_OK;
     889             : }
     890             : 
     891             : nsresult
     892           0 : MediaPipelineFactory::ConfigureVideoCodecMode(const JsepTrack& aTrack,
     893             :                                               VideoSessionConduit& aConduit)
     894             : {
     895             :   RefPtr<LocalSourceStreamInfo> stream =
     896           0 :     mPCMedia->GetLocalStreamByTrackId(aTrack.GetTrackId());
     897             : 
     898             :   //get video track
     899             :   RefPtr<mozilla::dom::MediaStreamTrack> track =
     900           0 :     stream->GetTrackById(aTrack.GetTrackId());
     901             : 
     902             :   RefPtr<mozilla::dom::VideoStreamTrack> videotrack =
     903           0 :     track->AsVideoStreamTrack();
     904             : 
     905           0 :   if (!videotrack) {
     906           0 :     MOZ_MTLOG(ML_ERROR, "video track not available");
     907           0 :     return NS_ERROR_FAILURE;
     908             :   }
     909             : 
     910           0 :   dom::MediaSourceEnum source = videotrack->GetSource().GetMediaSource();
     911           0 :   webrtc::VideoCodecMode mode = webrtc::kRealtimeVideo;
     912           0 :   switch (source) {
     913             :     case dom::MediaSourceEnum::Browser:
     914             :     case dom::MediaSourceEnum::Screen:
     915             :     case dom::MediaSourceEnum::Application:
     916             :     case dom::MediaSourceEnum::Window:
     917           0 :       mode = webrtc::kScreensharing;
     918           0 :       break;
     919             : 
     920             :     case dom::MediaSourceEnum::Camera:
     921             :     default:
     922           0 :       mode = webrtc::kRealtimeVideo;
     923           0 :       break;
     924             :   }
     925             : 
     926           0 :   auto error = aConduit.ConfigureCodecMode(mode);
     927           0 :   if (error) {
     928           0 :     MOZ_MTLOG(ML_ERROR, "ConfigureCodecMode failed: " << error);
     929           0 :     return NS_ERROR_FAILURE;
     930             :   }
     931             : 
     932           0 :   return NS_OK;
     933             : }
     934             : 
     935             : 
     936           9 : } // namespace mozilla

Generated by: LCOV version 1.13