nsresult MediaPipelineFactory::GetTransportParameters( const JsepTrackPair& aTrackPair, const JsepTrack& aTrack, size_t* aLevelOut, RefPtr<TransportFlow>* aRtpOut, RefPtr<TransportFlow>* aRtcpOut, nsAutoPtr<MediaPipelineFilter>* aFilterOut) { *aLevelOut = aTrackPair.mLevel; size_t transportLevel = aTrackPair.mBundleLevel.isSome() ? *aTrackPair.mBundleLevel : aTrackPair.mLevel; nsresult rv = CreateOrGetTransportFlow( transportLevel, false, *aTrackPair.mRtpTransport, aRtpOut); if (NS_FAILED(rv)) { return rv; } MOZ_ASSERT(aRtpOut); if (aTrackPair.mRtcpTransport) { rv = CreateOrGetTransportFlow( transportLevel, true, *aTrackPair.mRtcpTransport, aRtcpOut); if (NS_FAILED(rv)) { return rv; } MOZ_ASSERT(aRtcpOut); } if (aTrackPair.mBundleLevel.isSome()) { bool receiving = aTrack.GetDirection() == sdp::kRecv; *aFilterOut = new MediaPipelineFilter; if (receiving) { // Add remote SSRCs so we can distinguish which RTP packets actually // belong to this pipeline (also RTCP sender reports). for (auto i = aTrack.GetSsrcs().begin(); i != aTrack.GetSsrcs().end(); ++i) { (*aFilterOut)->AddRemoteSSRC(*i); } // TODO(bug 1105005): Tell the filter about the mid for this track // Add unique payload types as a last-ditch fallback auto uniquePts = aTrack.GetNegotiatedDetails()->GetUniquePayloadTypes(); for (auto i = uniquePts.begin(); i != uniquePts.end(); ++i) { (*aFilterOut)->AddUniquePT(*i); } } } return NS_OK; }
void SanityCheckTracks(const JsepTrack& a, const JsepTrack& b) const { if (!a.GetNegotiatedDetails()) { ASSERT_FALSE(!!b.GetNegotiatedDetails()); return; } ASSERT_TRUE(!!a.GetNegotiatedDetails()); ASSERT_TRUE(!!b.GetNegotiatedDetails()); ASSERT_EQ(a.GetMediaType(), b.GetMediaType()); ASSERT_EQ(a.GetStreamId(), b.GetStreamId()); ASSERT_EQ(a.GetTrackId(), b.GetTrackId()); ASSERT_EQ(a.GetCNAME(), b.GetCNAME()); ASSERT_NE(a.GetDirection(), b.GetDirection()); ASSERT_EQ(a.GetSsrcs().size(), b.GetSsrcs().size()); for (size_t i = 0; i < a.GetSsrcs().size(); ++i) { ASSERT_EQ(a.GetSsrcs()[i], b.GetSsrcs()[i]); } SanityCheckNegotiatedDetails(*a.GetNegotiatedDetails(), *b.GetNegotiatedDetails()); }
nsresult MediaPipelineFactory::GetOrCreateVideoConduit( const JsepTrackPair& aTrackPair, const JsepTrack& aTrack, RefPtr<MediaSessionConduit>* aConduitp) { if (!aTrack.GetNegotiatedDetails()) { MOZ_ASSERT(false, "Track is missing negotiated details"); return NS_ERROR_INVALID_ARG; } bool receiving = aTrack.GetDirection() == sdp::kRecv; RefPtr<VideoSessionConduit> conduit = mPCMedia->GetVideoConduit(aTrackPair.mLevel); if (!conduit) { conduit = VideoSessionConduit::Create(); if (!conduit) { MOZ_MTLOG(ML_ERROR, "Could not create video conduit"); return NS_ERROR_FAILURE; } mPCMedia->AddVideoConduit(aTrackPair.mLevel, conduit); } if (!GetBestCodec(*aTrack.GetNegotiatedDetails())) { MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs"); return NS_ERROR_FAILURE; } size_t numCodecs = aTrack.GetNegotiatedDetails()->GetCodecCount(); bool configuredH264 = false; if (receiving) { PtrVector<VideoCodecConfig> configs; for (size_t i = 0; i < numCodecs; i++) { const JsepCodecDescription* cdesc = aTrack.GetNegotiatedDetails()->GetCodec(i); // We can only handle configuring one recv H264 codec if (configuredH264 && (cdesc->mName == "H264")) { continue; } VideoCodecConfig* configRaw; nsresult rv = JsepCodecDescToCodecConfig(*cdesc, &configRaw); if (NS_FAILED(rv)) return rv; UniquePtr<VideoCodecConfig> config(configRaw); if (EnsureExternalCodec(*conduit, config.get(), false)) { continue; } if (cdesc->mName == "H264") { configuredH264 = true; } configs.values.push_back(config.release()); } auto error = conduit->ConfigureRecvMediaCodecs(configs.values); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error); return NS_ERROR_FAILURE; } if (!aTrackPair.mSending) { // No send track, but we still need to configure an SSRC for receiver // reports. if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } } else { // For now we only expect to have one ssrc per local track. auto ssrcs = aTrack.GetSsrcs(); if (!ssrcs.empty()) { if (!conduit->SetLocalSSRC(ssrcs.front())) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } conduit->SetLocalCNAME(aTrack.GetCNAME().c_str()); const JsepCodecDescription* cdesc = GetBestCodec(*aTrack.GetNegotiatedDetails()); VideoCodecConfig* configRaw; nsresult rv = JsepCodecDescToCodecConfig(*cdesc, &configRaw); if (NS_FAILED(rv)) return rv; rv = ConfigureVideoCodecMode(aTrack,*conduit); if (NS_FAILED(rv)) { return rv; } // Take possession of this pointer ScopedDeletePtr<VideoCodecConfig> config(configRaw); if (EnsureExternalCodec(*conduit, config, true)) { MOZ_MTLOG(ML_ERROR, "External codec not available"); return NS_ERROR_FAILURE; } auto error = conduit->ConfigureSendMediaCodec(config); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error); return NS_ERROR_FAILURE; } } *aConduitp = conduit; return NS_OK; }
nsresult MediaPipelineFactory::GetOrCreateAudioConduit( const JsepTrackPair& aTrackPair, const JsepTrack& aTrack, RefPtr<MediaSessionConduit>* aConduitp) { if (!aTrack.GetNegotiatedDetails()) { MOZ_ASSERT(false, "Track is missing negotiated details"); return NS_ERROR_INVALID_ARG; } bool receiving = aTrack.GetDirection() == sdp::kRecv; RefPtr<AudioSessionConduit> conduit = mPCMedia->GetAudioConduit(aTrackPair.mLevel); if (!conduit) { conduit = AudioSessionConduit::Create(); if (!conduit) { MOZ_MTLOG(ML_ERROR, "Could not create audio conduit"); return NS_ERROR_FAILURE; } mPCMedia->AddAudioConduit(aTrackPair.mLevel, conduit); } if (!GetBestCodec(*aTrack.GetNegotiatedDetails())) { MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs"); return NS_ERROR_FAILURE; } size_t numCodecs = aTrack.GetNegotiatedDetails()->GetCodecCount(); if (receiving) { PtrVector<AudioCodecConfig> configs; for (size_t i = 0; i < numCodecs; i++) { const JsepCodecDescription* cdesc = aTrack.GetNegotiatedDetails()->GetCodec(i); AudioCodecConfig* configRaw; nsresult rv = JsepCodecDescToCodecConfig(*cdesc, &configRaw); if (NS_FAILED(rv)) return rv; configs.values.push_back(configRaw); } auto error = conduit->ConfigureRecvMediaCodecs(configs.values); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error); return NS_ERROR_FAILURE; } if (!aTrackPair.mSending) { // No send track, but we still need to configure an SSRC for receiver // reports. if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } } else { // For now we only expect to have one ssrc per local track. auto ssrcs = aTrack.GetSsrcs(); if (!ssrcs.empty()) { if (!conduit->SetLocalSSRC(ssrcs.front())) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } conduit->SetLocalCNAME(aTrack.GetCNAME().c_str()); const JsepCodecDescription* cdesc = GetBestCodec(*aTrack.GetNegotiatedDetails()); AudioCodecConfig* configRaw; nsresult rv = JsepCodecDescToCodecConfig(*cdesc, &configRaw); if (NS_FAILED(rv)) return rv; ScopedDeletePtr<AudioCodecConfig> config(configRaw); auto error = conduit->ConfigureSendMediaCodec(config.get()); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error); return NS_ERROR_FAILURE; } const SdpExtmapAttributeList::Extmap* audioLevelExt = aTrack.GetNegotiatedDetails()->GetExt( "urn:ietf:params:rtp-hdrext:ssrc-audio-level"); if (audioLevelExt) { MOZ_MTLOG(ML_DEBUG, "Calling EnableAudioLevelExtension"); error = conduit->EnableAudioLevelExtension(true, audioLevelExt->entry); if (error) { MOZ_MTLOG(ML_ERROR, "EnableAudioLevelExtension failed: " << error); return NS_ERROR_FAILURE; } } } *aConduitp = conduit; return NS_OK; }
nsresult MediaPipelineFactory::GetOrCreateVideoConduit( const JsepTrackPair& aTrackPair, const JsepTrack& aTrack, RefPtr<MediaSessionConduit>* aConduitp) { if (!aTrack.GetNegotiatedDetails()) { MOZ_ASSERT(false, "Track is missing negotiated details"); return NS_ERROR_INVALID_ARG; } bool receiving = aTrack.GetDirection() == sdp::kRecv; RefPtr<VideoSessionConduit> conduit = mPCMedia->GetVideoConduit(aTrackPair.mLevel); if (!conduit) { conduit = VideoSessionConduit::Create(); if (!conduit) { MOZ_MTLOG(ML_ERROR, "Could not create video conduit"); return NS_ERROR_FAILURE; } mPCMedia->AddVideoConduit(aTrackPair.mLevel, conduit); } PtrVector<VideoCodecConfig> configs; nsresult rv = NegotiatedDetailsToVideoCodecConfigs( *aTrack.GetNegotiatedDetails(), &configs); if (NS_FAILED(rv)) { MOZ_MTLOG(ML_ERROR, "Failed to convert JsepCodecDescriptions to " "VideoCodecConfigs."); return rv; } if (configs.values.empty()) { MOZ_MTLOG(ML_ERROR, "Can't set up a conduit with 0 codecs"); return NS_ERROR_FAILURE; } if (receiving) { // Prune out stuff we cannot actually do. We should work to eliminate the // need for this. bool configuredH264 = false; for (size_t i = 0; i < configs.values.size();) { // TODO(bug 1200768): We can only handle configuring one recv H264 codec if (configuredH264 && (configs.values[i]->mName == "H264")) { delete configs.values[i]; configs.values.erase(configs.values.begin() + i); continue; } // TODO(bug 1018791): This really should be checked sooner if (EnsureExternalCodec(*conduit, configs.values[i], false)) { delete configs.values[i]; configs.values.erase(configs.values.begin() + i); continue; } if (configs.values[i]->mName == "H264") { configuredH264 = true; } ++i; } auto error = conduit->ConfigureRecvMediaCodecs(configs.values); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error); return NS_ERROR_FAILURE; } if (!aTrackPair.mSending) { // No send track, but we still need to configure an SSRC for receiver // reports. if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } } else { // For now we only expect to have one ssrc per local track. auto ssrcs = aTrack.GetSsrcs(); if (!ssrcs.empty()) { if (!conduit->SetLocalSSRC(ssrcs.front())) { MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE; } } conduit->SetLocalCNAME(aTrack.GetCNAME().c_str()); rv = ConfigureVideoCodecMode(aTrack,*conduit); if (NS_FAILED(rv)) { return rv; } // TODO(bug 1018791): This really should be checked sooner if (EnsureExternalCodec(*conduit, configs.values[0], true)) { MOZ_MTLOG(ML_ERROR, "External codec not available"); return NS_ERROR_FAILURE; } auto error = conduit->ConfigureSendMediaCodec(configs.values[0]); if (error) { MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error); return NS_ERROR_FAILURE; } } *aConduitp = conduit; return NS_OK; }