From 020839f9bbdc85f3cba131af6f78da6d89f90e36 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Fri, 21 Dec 2012 16:15:01 +0000 Subject: [PATCH] Backout 21409a401d75 (bug 821292),9587e39f9a50 (bug 820102) for conflicts and assertions respectively, on a CLOSED TREE --- media/mtransport/databuffer.h | 46 --- media/mtransport/runnable_utils.h | 22 +- .../test/runnable_utils_unittest.cpp | 46 +-- .../signaling/src/media/VcmSIPCCBinding.cpp | 80 ++---- .../src/mediapipeline/MediaPipeline.cpp | 265 +++++++----------- .../src/mediapipeline/MediaPipeline.h | 233 ++++++--------- .../src/peerconnection/PeerConnectionCtx.cpp | 2 - .../src/peerconnection/PeerConnectionImpl.cpp | 29 +- .../src/peerconnection/PeerConnectionImpl.h | 4 +- .../peerconnection/PeerConnectionMedia.cpp | 23 ++ .../src/peerconnection/PeerConnectionMedia.h | 28 +- .../signaling/test/mediapipeline_unittest.cpp | 27 +- 12 files changed, 294 insertions(+), 511 deletions(-) delete mode 100644 media/mtransport/databuffer.h diff --git a/media/mtransport/databuffer.h b/media/mtransport/databuffer.h deleted file mode 100644 index f8f890b7f9a9..000000000000 --- a/media/mtransport/databuffer.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Original author: ekr@rtfm.com - -#ifndef databuffer_h__ -#define databuffer_h__ -#include -#include -#include - -namespace mozilla { - -class DataBuffer { - public: - DataBuffer() : data_(nullptr), len_(0) {} - DataBuffer(const uint8_t *data, size_t len) { - Assign(data, len); - } - - void Assign(const uint8_t *data, size_t len) { - data_ = new unsigned char[ len ? len : 1]; // Don't depend on new [0]. - memcpy(static_cast(data_.get()), - static_cast(data), len); - len_ = len; - } - - const uint8_t *data() const { return data_; } - size_t len() const { return len_; } - const bool empty() const { return len_ != 0; } - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataBuffer) - -private: - ScopedDeleteArray data_; - size_t len_; - - DISALLOW_COPY_ASSIGN(DataBuffer); -}; - -} - -#endif diff --git a/media/mtransport/runnable_utils.h b/media/mtransport/runnable_utils.h index e45d2ddfe58a..09d0715ac953 100644 --- a/media/mtransport/runnable_utils.h +++ b/media/mtransport/runnable_utils.h @@ -10,13 +10,13 @@ #define runnable_utils_h__ #include "nsThreadUtils.h" -#include "mozilla/RefPtr.h" // Abstract base class for all of our templates namespace mozilla { class runnable_args_base : public nsRunnable { public: + NS_IMETHOD Run() = 0; }; @@ -39,25 +39,7 @@ class runnable_args_base : public nsRunnable { #include "runnable_utils_generated.h" // Temporary hack. Really we want to have a template which will do this -static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flags) { - RefPtr runnable_ref(runnable); - - if (thread && (thread != nsRefPtr(do_GetCurrentThread()))) { - return thread->Dispatch(runnable_ref, flags); - } - - return runnable_ref->Run(); -} - -#define ASSERT_ON_THREAD(t) do { \ - if (t) { \ - bool on; \ - nsresult rv; \ - rv = t->IsOnCurrentThread(&on); \ - MOZ_ASSERT(NS_SUCCEEDED(rv)); \ - MOZ_ASSERT(on); \ - } \ - } while(0) +#define RUN_ON_THREAD(t, r, h) ((t && (t != nsRefPtr(do_GetCurrentThread()))) ? t->Dispatch(r, h) : r->Run()) } #endif diff --git a/media/mtransport/test/runnable_utils_unittest.cpp b/media/mtransport/test/runnable_utils_unittest.cpp index e1616cce7135..b90273b51a12 100644 --- a/media/mtransport/test/runnable_utils_unittest.cpp +++ b/media/mtransport/test/runnable_utils_unittest.cpp @@ -1,3 +1,4 @@ + /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public @@ -14,7 +15,6 @@ #include "nsXPCOM.h" #include "nsXPCOMGlue.h" -#include "mozilla/RefPtr.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" #include "nsIIOService.h" @@ -37,20 +37,6 @@ MtransportTestUtils *test_utils; namespace { -class Destructor { - public: - Destructor(bool* destroyed) : destroyed_(destroyed) {} - ~Destructor() { - std::cerr << "Destructor called" << std::endl; - *destroyed_ = true; - } - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Destructor); - - private: - bool *destroyed_; -}; - class TargetClass { public: TargetClass(int *ran) : ran_(ran) {} @@ -73,16 +59,10 @@ class TargetClass { std::cerr << __FUNCTION__ << std::endl; return x; } - void destructor_target(Destructor*) { - } - - void destructor_target_ref(RefPtr destructor) { - } int *ran_; }; - class RunnableArgsTest : public ::testing::Test { public: RunnableArgsTest() : ran_(0), cl_(&ran_){} @@ -104,6 +84,7 @@ class RunnableArgsTest : public ::testing::Test { TargetClass cl_; }; + class DispatchTest : public ::testing::Test { public: DispatchTest() : ran_(0), cl_(&ran_) {} @@ -145,6 +126,8 @@ class DispatchTest : public ::testing::Test { protected: int ran_; TargetClass cl_; + + private: nsCOMPtr target_; }; @@ -200,27 +183,6 @@ TEST_F(DispatchTest, TestNonMethodRet) { ASSERT_EQ(10, z); } -TEST_F(DispatchTest, TestDestructor) { - bool destroyed = false; - RefPtr destructor = new Destructor(&destroyed); - target_->Dispatch(WrapRunnable(&cl_, &TargetClass::destructor_target, - destructor), - NS_DISPATCH_SYNC); - ASSERT_FALSE(destroyed); - destructor = nullptr; - ASSERT_TRUE(destroyed); -} - -TEST_F(DispatchTest, TestDestructorRef) { - bool destroyed = false; - RefPtr destructor = new Destructor(&destroyed); - target_->Dispatch(WrapRunnable(&cl_, &TargetClass::destructor_target_ref, - destructor), - NS_DISPATCH_SYNC); - ASSERT_FALSE(destroyed); - destructor = nullptr; - ASSERT_TRUE(destroyed); -} } // end of namespace diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index d8a17bdfd0c6..defc3d6307bd 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -909,7 +909,7 @@ static short vcmCreateRemoteStream_m( hints |= nsDOMMediaStream::HINT_CONTENTS_VIDEO; } - nsRefPtr info; + sipcc::RemoteSourceStreamInfo* info; res = pc.impl()->CreateRemoteSourceStreamInfo(hints, &info); if (NS_FAILED(res)) { return VCM_ERROR; @@ -1329,26 +1329,14 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id, if (conduit->ConfigureRecvMediaCodecs(configs)) return VCM_ERROR; - // Now we have all the pieces, create the pipeline - mozilla::RefPtr pipeline = + stream->StorePipeline(pc_track_id, new mozilla::MediaPipelineReceiveAudio( - pc.impl()->GetHandle(), pc.impl()->GetMainThread().get(), pc.impl()->GetSTSThread(), - stream->GetMediaStream()->GetStream(), - conduit, rtp_flow, rtcp_flow); + stream->GetMediaStream(), + conduit, rtp_flow, rtcp_flow)); - nsresult res = pipeline->Init(); - if (NS_FAILED(res)) { - CSFLogError(logTag, "Failure initializing audio pipeline"); - return VCM_ERROR; - } - - CSFLogDebug(logTag, "Created audio pipeline %p, conduit=%p, pc_stream=%d pc_track=%d", - pipeline.get(), conduit.get(), pc_stream_id, pc_track_id); - - stream->StorePipeline(pc_track_id, pipeline); } else if (CC_IS_VIDEO(mcap_id)) { std::vector configs; @@ -1374,24 +1362,13 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id, return VCM_ERROR; // Now we have all the pieces, create the pipeline - mozilla::RefPtr pipeline = - new mozilla::MediaPipelineReceiveVideo( - pc.impl()->GetHandle(), - pc.impl()->GetMainThread().get(), - pc.impl()->GetSTSThread(), - stream->GetMediaStream()->GetStream(), - conduit, rtp_flow, rtcp_flow); + stream->StorePipeline(pc_track_id, + new mozilla::MediaPipelineReceiveVideo( + pc.impl()->GetMainThread().get(), + pc.impl()->GetSTSThread(), + stream->GetMediaStream(), + conduit, rtp_flow, rtcp_flow)); - nsresult res = pipeline->Init(); - if (NS_FAILED(res)) { - CSFLogError(logTag, "Failure initializing video pipeline"); - return VCM_ERROR; - } - - CSFLogDebug(logTag, "Created video pipeline %p, conduit=%p, pc_stream=%d pc_track=%d", - pipeline.get(), conduit.get(), pc_stream_id, pc_track_id); - - stream->StorePipeline(pc_track_id, pipeline); } else { CSFLogError(logTag, "%s: mcap_id unrecognized", __FUNCTION__); return VCM_ERROR; @@ -1959,23 +1936,16 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id, if (!conduit || conduit->ConfigureSendMediaCodec(config)) return VCM_ERROR; - mozilla::RefPtr pipeline = - new mozilla::MediaPipelineTransmit( - pc.impl()->GetHandle(), - pc.impl()->GetMainThread().get(), - pc.impl()->GetSTSThread(), - stream->GetMediaStream()->GetStream(), - conduit, rtp_flow, rtcp_flow); + mozilla::RefPtr pipeline = + new mozilla::MediaPipelineTransmit( + pc.impl()->GetMainThread().get(), + pc.impl()->GetSTSThread(), + stream->GetMediaStream(), + conduit, rtp_flow, rtcp_flow); - nsresult res = pipeline->Init(); - if (NS_FAILED(res)) { - CSFLogError(logTag, "Failure initializing audio pipeline"); - return VCM_ERROR; - } CSFLogDebug(logTag, "Created audio pipeline %p, conduit=%p, pc_stream=%d pc_track=%d", pipeline.get(), conduit.get(), pc_stream_id, pc_track_id); - // Now we have all the pieces, create the pipeline stream->StorePipeline(pc_track_id, pipeline); @@ -1998,24 +1968,18 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id, if (!conduit || conduit->ConfigureSendMediaCodec(config)) return VCM_ERROR; - // Now we have all the pieces, create the pipeline + // Create the pipeline mozilla::RefPtr pipeline = new mozilla::MediaPipelineTransmit( - pc.impl()->GetHandle(), - pc.impl()->GetMainThread().get(), - pc.impl()->GetSTSThread(), - stream->GetMediaStream()->GetStream(), - conduit, rtp_flow, rtcp_flow); - - nsresult res = pipeline->Init(); - if (NS_FAILED(res)) { - CSFLogError(logTag, "Failure initializing video pipeline"); - return VCM_ERROR; - } + pc.impl()->GetMainThread().get(), + pc.impl()->GetSTSThread(), + stream->GetMediaStream(), + conduit, rtp_flow, rtcp_flow); CSFLogDebug(logTag, "Created video pipeline %p, conduit=%p, pc_stream=%d pc_track=%d", pipeline.get(), conduit.get(), pc_stream_id, pc_track_id); + // Now we have all the pieces, create the pipeline stream->StorePipeline(pc_track_id, pipeline); } else { CSFLogError(logTag, "%s: mcap_id unrecognized", __FUNCTION__); diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index 0efe968ac1ee..b8c90101bf8f 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -23,7 +23,6 @@ #include "nsError.h" #include "AudioSegment.h" #include "MediaSegment.h" -#include "databuffer.h" #include "transportflow.h" #include "transportlayer.h" #include "transportlayerdtls.h" @@ -33,14 +32,6 @@ using namespace mozilla; -#ifdef DEBUG -// Dial up pipeline logging in debug mode -#define MP_LOG_INFO PR_LOG_WARN -#else -#define MP_LOG_INFO PR_LOG_INFO -#endif - - // Logging context MOZ_MTLOG_MODULE("mediapipeline"); @@ -49,7 +40,6 @@ namespace mozilla { static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp"; nsresult MediaPipeline::Init() { - ASSERT_ON_THREAD(main_thread_); conduit_->AttachTransport(transport_); MOZ_ASSERT(rtp_transport_); @@ -62,10 +52,7 @@ nsresult MediaPipeline::Init() { if (rtp_transport_->state() == TransportLayer::TS_OPEN) { res = TransportReady(rtp_transport_); - if (NS_FAILED(res)) { - MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady()"); - return res; - } + NS_ENSURE_SUCCESS(res, res); } else { if (!muxed_) { rtcp_transport_->SignalStateChange.connect(this, @@ -73,10 +60,7 @@ nsresult MediaPipeline::Init() { if (rtcp_transport_->state() == TransportLayer::TS_OPEN) { res = TransportReady(rtcp_transport_); - if (NS_FAILED(res)) { - MOZ_MTLOG(PR_LOG_ERROR, "Error calling TransportReady()"); - return res; - } + NS_ENSURE_SUCCESS(res, res); } } } @@ -86,9 +70,7 @@ nsresult MediaPipeline::Init() { // Disconnect us from the transport so that we can cleanly destruct // the pipeline on the main thread. -void MediaPipeline::DetachTransport_s() { - ASSERT_ON_THREAD(sts_thread_); - +void MediaPipeline::DetachTransportInt() { transport_->Detach(); rtp_transport_ = NULL; rtcp_transport_ = NULL; @@ -96,13 +78,13 @@ void MediaPipeline::DetachTransport_s() { void MediaPipeline::DetachTransport() { RUN_ON_THREAD(sts_thread_, - WrapRunnable(this, &MediaPipeline::DetachTransport_s), + WrapRunnable(this, &MediaPipeline::DetachTransportInt), NS_DISPATCH_SYNC); } void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) { if (state == TransportLayer::TS_OPEN) { - MOZ_MTLOG(MP_LOG_INFO, "Flow is ready"); + MOZ_MTLOG(PR_LOG_DEBUG, "Flow is ready"); TransportReady(flow); } else if (state == TransportLayer::TS_CLOSED || state == TransportLayer::TS_ERROR) { @@ -126,21 +108,18 @@ nsresult MediaPipeline::TransportReady(TransportFlow *flow) { } nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) { - MOZ_ASSERT(!description_.empty()); bool rtcp = !(flow == rtp_transport_); State *state = rtcp ? &rtcp_state_ : &rtp_state_; if (*state != MP_CONNECTING) { MOZ_MTLOG(PR_LOG_ERROR, "Transport ready for flow in wrong state:" << - description_ << ": " << (rtcp ? "rtcp" : "rtp")); + (rtcp ? "rtcp" : "rtp")); return NS_ERROR_FAILURE; } nsresult res; - MOZ_MTLOG(MP_LOG_INFO, "Transport ready for pipeline " << - static_cast(this) << " flow " << description_ << ": " << - (rtcp ? "rtcp" : "rtp")); + MOZ_MTLOG(PR_LOG_DEBUG, "Transport ready for flow " << (rtcp ? "rtcp" : "rtp")); // Now instantiate the SRTP objects TransportLayerDtls *dtls = static_cast( @@ -213,14 +192,14 @@ nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) { rtcp_send_srtp_ = rtp_send_srtp_; rtcp_recv_srtp_ = rtp_recv_srtp_; - MOZ_MTLOG(MP_LOG_INFO, "Listening for packets received on " << + MOZ_MTLOG(PR_LOG_DEBUG, "Listening for packets received on " << static_cast(dtls->downward())); dtls->downward()->SignalPacketReceived.connect(this, &MediaPipeline:: PacketReceived); } else { - MOZ_MTLOG(MP_LOG_INFO, "Listening for RTP packets received on " << + MOZ_MTLOG(PR_LOG_DEBUG, "Listening for RTP packets received on " << static_cast(dtls->downward())); dtls->downward()->SignalPacketReceived.connect(this, @@ -240,7 +219,7 @@ nsresult MediaPipeline::TransportReadyInt(TransportFlow *flow) { return NS_ERROR_FAILURE; } - MOZ_MTLOG(MP_LOG_INFO, "Listening for RTCP packets received on " << + MOZ_MTLOG(PR_LOG_DEBUG, "Listening for RTCP packets received on " << static_cast(dtls->downward())); // Start listening @@ -260,7 +239,7 @@ nsresult MediaPipeline::TransportFailed(TransportFlow *flow) { *state = MP_CLOSED; - MOZ_MTLOG(MP_LOG_INFO, "Transport closed for flow " << (rtcp ? "rtcp" : "rtp")); + MOZ_MTLOG(PR_LOG_DEBUG, "Transport closed for flow " << (rtcp ? "rtcp" : "rtp")); NS_WARNING( "MediaPipeline Transport failed. This is not properly cleaned up yet"); @@ -275,10 +254,25 @@ nsresult MediaPipeline::TransportFailed(TransportFlow *flow) { } +// Wrapper to send a packet on the STS thread. nsresult MediaPipeline::SendPacket(TransportFlow *flow, const void *data, int len) { - ASSERT_ON_THREAD(sts_thread_); + nsresult rv; + nsresult res; + rv = RUN_ON_THREAD(sts_thread_, + WrapRunnableRet(this, &MediaPipeline::SendPacketInt, flow, data, len, &res), + NS_DISPATCH_SYNC); + + // res is invalid unless the dispatch succeeded + if (NS_FAILED(rv)) + return rv; + + return res; +} + +nsresult MediaPipeline::SendPacketInt(TransportFlow *flow, const void *data, + int len) { // Note that we bypass the DTLS layer here TransportLayerDtls *dtls = static_cast( flow->GetLayer(TransportLayerDtls::ID())); @@ -301,45 +295,37 @@ nsresult MediaPipeline::SendPacket(TransportFlow *flow, const void *data, void MediaPipeline::increment_rtp_packets_sent() { ++rtp_packets_sent_; - - if (!(rtp_packets_sent_ % 100)) { - MOZ_MTLOG(MP_LOG_INFO, "RTP sent packet count for " << description_ - << " Pipeline " << static_cast(this) - << " Flow : " << static_cast(rtp_transport_) + if (!(rtp_packets_sent_ % 1000)) { + MOZ_MTLOG(PR_LOG_DEBUG, "RTP packet count " << static_cast(this) << ": " << rtp_packets_sent_); } } void MediaPipeline::increment_rtcp_packets_sent() { ++rtcp_packets_sent_; - if (!(rtcp_packets_sent_ % 100)) { - MOZ_MTLOG(MP_LOG_INFO, "RTCP sent packet count for " << description_ - << " Pipeline " << static_cast(this) - << " Flow : " << static_cast(rtcp_transport_) + if (!(rtcp_packets_sent_ % 1000)) { + MOZ_MTLOG(PR_LOG_DEBUG, "RTCP packet count " << static_cast(this) << ": " << rtcp_packets_sent_); } } void MediaPipeline::increment_rtp_packets_received() { ++rtp_packets_received_; - if (!(rtp_packets_received_ % 100)) { - MOZ_MTLOG(MP_LOG_INFO, "RTP received packet count for " << description_ - << " Pipeline " << static_cast(this) - << " Flow : " << static_cast(rtp_transport_) + if (!(rtp_packets_received_ % 1000)) { + MOZ_MTLOG(PR_LOG_DEBUG, "RTP packet count " << static_cast(this) << ": " << rtp_packets_received_); } } void MediaPipeline::increment_rtcp_packets_received() { ++rtcp_packets_received_; - if (!(rtcp_packets_received_ % 100)) { - MOZ_MTLOG(MP_LOG_INFO, "RTCP received packet count for " << description_ - << " Pipeline " << static_cast(this) - << " Flow : " << static_cast(rtcp_transport_) + if (!(rtcp_packets_received_ % 1000)) { + MOZ_MTLOG(PR_LOG_DEBUG, "RTCP packet count " << static_cast(this) << ": " << rtcp_packets_received_); } } + void MediaPipeline::RtpPacketReceived(TransportLayer *layer, const unsigned char *data, size_t len) { @@ -348,10 +334,9 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer, return; } - if (!conduit_) { - MOZ_MTLOG(PR_LOG_DEBUG, "Discarding incoming packet; media disconnected"); - return; - } + // TODO(ekr@rtfm.com): filter for DTLS here and in RtcpPacketReceived + // TODO(ekr@rtfm.com): filter on SSRC for bundle + increment_rtp_packets_received(); MOZ_ASSERT(rtp_recv_srtp_); // This should never happen @@ -361,10 +346,6 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer, return; } - // TODO(ekr@rtfm.com): filter for DTLS here and in RtcpPacketReceived - // TODO(ekr@rtfm.com): filter on SSRC for bundle - increment_rtp_packets_received(); - // Make a copy rather than cast away constness ScopedDeletePtr inner_data( new unsigned char[len]); @@ -386,17 +367,6 @@ void MediaPipeline::RtcpPacketReceived(TransportLayer *layer, return; } - if (!conduit_) { - MOZ_MTLOG(PR_LOG_DEBUG, "Discarding incoming packet; media disconnected"); - return; - } - - if (direction_ == RECEIVE) { - // Discard any RTCP that is being transmitted to us - // This will be unnecessary when we have SSRC filtering. - return; - } - increment_rtcp_packets_received(); MOZ_ASSERT(rtcp_recv_srtp_); // This should never happen @@ -464,55 +434,25 @@ void MediaPipeline::PacketReceived(TransportLayer *layer, } nsresult MediaPipelineTransmit::Init() { - ASSERT_ON_THREAD(main_thread_); - - description_ = pc_ + "| "; - description_ += conduit_->type() == MediaSessionConduit::AUDIO ? - "Transmit audio" : "Transmit video"; - // TODO(ekr@rtfm.com): Check for errors MOZ_MTLOG(PR_LOG_DEBUG, "Attaching pipeline to stream " << static_cast(stream_) << " conduit type=" << (conduit_->type() == MediaSessionConduit::AUDIO ? - "audio" : "video")); + "audio" : "video") << + " hints=" << stream_->GetHintContents()); - stream_->AddListener(listener_); - - return MediaPipeline::Init(); -} - -nsresult MediaPipelineTransmit::TransportReady(TransportFlow *flow) { - // Call base ready function. - MediaPipeline::TransportReady(flow); - - if (flow == rtp_transport_) { - // TODO(ekr@rtfm.com): Move onto MSG thread. - listener_->SetActive(true); - } - - return NS_OK; + // Force this to be a refptr so that we are holding a strong reference + // to the media stream. + nsRefPtr stream (stream_->GetStream()); + return RUN_ON_THREAD(main_thread_, WrapRunnable(stream, + &MediaStream::AddListener, + listener_), + NS_DISPATCH_NORMAL); } nsresult MediaPipeline::PipelineTransport::SendRtpPacket( const void *data, int len) { - nsresult ret; - - nsAutoPtr buf(new DataBuffer(static_cast(data), - len)); - - RUN_ON_THREAD(sts_thread_, - WrapRunnableRet( - RefPtr(this), - &MediaPipeline::PipelineTransport::SendRtpPacket_s, - buf, &ret), - NS_DISPATCH_NORMAL); - - return NS_OK; -} - -nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s( - nsAutoPtr data) { if (!pipeline_) return NS_OK; // Detached @@ -527,15 +467,14 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s( // libsrtp enciphers in place, so we need a new, big enough // buffer. // XXX. allocates and deletes one buffer per packet sent. - // Bug 822129 - int max_len = data->len() + SRTP_MAX_EXPANSION; + int max_len = len + SRTP_MAX_EXPANSION; ScopedDeletePtr inner_data( new unsigned char[max_len]); - memcpy(inner_data, data->data(), data->len()); + memcpy(inner_data, data, len); int out_len; nsresult res = pipeline_->rtp_send_srtp_->ProtectRtp(inner_data, - data->len(), + len, max_len, &out_len); if (!NS_SUCCEEDED(res)) @@ -548,23 +487,6 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s( nsresult MediaPipeline::PipelineTransport::SendRtcpPacket( const void *data, int len) { - nsresult ret; - - nsAutoPtr buf(new DataBuffer(static_cast(data), - len)); - - RUN_ON_THREAD(sts_thread_, - WrapRunnableRet( - RefPtr(this), - &MediaPipeline::PipelineTransport::SendRtcpPacket_s, - buf, &ret), - NS_DISPATCH_NORMAL); - - return NS_OK; -} - -nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s( - nsAutoPtr data) { if (!pipeline_) return NS_OK; // Detached @@ -579,15 +501,14 @@ nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s( // libsrtp enciphers in place, so we need a new, big enough // buffer. // XXX. allocates and deletes one buffer per packet sent. - // Bug 822129. - int max_len = data->len() + SRTP_MAX_EXPANSION; + int max_len = len + SRTP_MAX_EXPANSION; ScopedDeletePtr inner_data( new unsigned char[max_len]); - memcpy(inner_data, data->data(), data->len()); + memcpy(inner_data, data, len); int out_len; nsresult res = pipeline_->rtcp_send_srtp_->ProtectRtcp(inner_data, - data->len(), + len, max_len, &out_len); if (!NS_SUCCEEDED(res)) @@ -604,18 +525,22 @@ NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, TrackTicks offset, uint32_t events, const MediaSegment& queued_media) { + if (!pipeline_) + return; // Detached + MOZ_MTLOG(PR_LOG_DEBUG, "MediaPipeline::NotifyQueuedTrackChanges()"); - if (!active_) { - MOZ_MTLOG(PR_LOG_DEBUG, "Discarding packets because transport not ready"); + // Return early if we are not connected to avoid queueing stuff + // up in the conduit + if (pipeline_->rtp_transport_->state() != TransportLayer::TS_OPEN) { + MOZ_MTLOG(PR_LOG_DEBUG, "Transport not ready yet, dropping packets"); return; } // TODO(ekr@rtfm.com): For now assume that we have only one // track type and it's destined for us - // See bug 784517 if (queued_media.GetType() == MediaSegment::AUDIO) { - if (conduit_->type() != MediaSessionConduit::AUDIO) { + if (pipeline_->conduit_->type() != MediaSessionConduit::AUDIO) { // Ignore data in case we have a muxed stream return; } @@ -624,13 +549,14 @@ NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, AudioSegment::ChunkIterator iter(*audio); while(!iter.IsEnded()) { - ProcessAudioChunk(static_cast(conduit_.get()), - rate, *iter); + pipeline_->ProcessAudioChunk(static_cast + (pipeline_->conduit_.get()), + rate, *iter); iter.Next(); } } else if (queued_media.GetType() == MediaSegment::VIDEO) { #ifdef MOZILLA_INTERNAL_API - if (conduit_->type() != MediaSessionConduit::VIDEO) { + if (pipeline_->conduit_->type() != MediaSessionConduit::VIDEO) { // Ignore data in case we have a muxed stream return; } @@ -639,8 +565,9 @@ NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, VideoSegment::ChunkIterator iter(*video); while(!iter.IsEnded()) { - ProcessVideoChunk(static_cast(conduit_.get()), - rate, *iter); + pipeline_->ProcessVideoChunk(static_cast + (pipeline_->conduit_.get()), + rate, *iter); iter.Next(); } #endif @@ -649,10 +576,9 @@ NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, } } -void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( - AudioSessionConduit *conduit, - TrackRate rate, - AudioChunk& chunk) { +void MediaPipelineTransmit::ProcessAudioChunk(AudioSessionConduit *conduit, + TrackRate rate, + AudioChunk& chunk) { // TODO(ekr@rtfm.com): Do more than one channel nsAutoArrayPtr samples(new int16_t[chunk.mDuration]); @@ -686,10 +612,9 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( } #ifdef MOZILLA_INTERNAL_API -void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( - VideoSessionConduit* conduit, - TrackRate rate, - VideoChunk& chunk) { +void MediaPipelineTransmit::ProcessVideoChunk(VideoSessionConduit *conduit, + TrackRate rate, + VideoChunk& chunk) { // We now need to send the video frame to the other side layers::Image *img = chunk.mFrame.GetImage(); if (!img) { @@ -742,20 +667,27 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( #endif nsresult MediaPipelineReceiveAudio::Init() { - ASSERT_ON_THREAD(main_thread_); MOZ_MTLOG(PR_LOG_DEBUG, __FUNCTION__); - description_ = pc_ + "| Receive audio"; - - stream_->AddListener(listener_); - - return MediaPipelineReceive::Init(); + // Force this to be a refptr so that we are holding a strong reference + // to the media stream. + nsRefPtr stream (stream_->GetStream()); + return RUN_ON_THREAD(main_thread_, WrapRunnable(stream, + &MediaStream::AddListener, + listener_), + NS_DISPATCH_NORMAL); } void MediaPipelineReceiveAudio::PipelineListener:: NotifyPull(MediaStreamGraph* graph, StreamTime total) { - MOZ_ASSERT(source_); - if (!source_) { + if (!pipeline_) + return; // Detached + + SourceMediaStream *source = + pipeline_->stream_->GetStream()->AsSourceStream(); + + MOZ_ASSERT(source); + if (!source) { MOZ_MTLOG(PR_LOG_ERROR, "NotifyPull() called from a non-SourceMediaStream"); return; } @@ -783,7 +715,7 @@ NotifyPull(MediaStreamGraph* graph, StreamTime total) { int samples_length; MediaConduitErrorCode err = - static_cast(conduit_.get())->GetAudioFrame( + static_cast(pipeline_->conduit_.get())->GetAudioFrame( static_cast(samples->Data()), 16000, // Sampling rate fixed at 16 kHz for now 0, // TODO(ekr@rtfm.com): better estimate of capture delay @@ -799,21 +731,20 @@ NotifyPull(MediaStreamGraph* graph, StreamTime total) { segment.AppendFrames(samples.forget(), samples_length, 0, samples_length, AUDIO_FORMAT_S16); - source_->AppendToTrack(1, // TODO(ekr@rtfm.com): Track ID - &segment); + char buf[32]; + PR_snprintf(buf, 32, "%p", source); + source->AppendToTrack(1, // TODO(ekr@rtfm.com): Track ID + &segment); } } nsresult MediaPipelineReceiveVideo::Init() { - ASSERT_ON_THREAD(main_thread_); MOZ_MTLOG(PR_LOG_DEBUG, __FUNCTION__); - description_ = pc_ + "| Receive video"; - static_cast(conduit_.get())-> AttachRenderer(renderer_); - return MediaPipelineReceive::Init(); + return NS_OK; } MediaPipelineReceiveVideo::PipelineRenderer::PipelineRenderer( @@ -824,7 +755,7 @@ MediaPipelineReceiveVideo::PipelineRenderer::PipelineRenderer( #ifdef MOZILLA_INTERNAL_API image_container_ = layers::LayerManager::CreateImageContainer(); SourceMediaStream *source = - pipeline_->stream_->AsSourceStream(); + pipeline_->stream_->GetStream()->AsSourceStream(); source->AddTrack(1 /* Track ID */, 30, 0, new VideoSegment()); source->AdvanceKnownTracksTime(STREAM_TIME_MAX); #endif @@ -837,7 +768,7 @@ void MediaPipelineReceiveVideo::PipelineRenderer::RenderVideoFrame( int64_t render_time) { #ifdef MOZILLA_INTERNAL_API SourceMediaStream *source = - pipeline_->stream_->AsSourceStream(); + pipeline_->stream_->GetStream()->AsSourceStream(); // Create a video frame and append it to the track. ImageFormat format = PLANAR_YCBCR; diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h index 787b75f47995..c1738b78ae89 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h @@ -17,8 +17,6 @@ #include "MediaConduitInterface.h" #include "AudioSegment.h" #include "SrtpFlow.h" -#include "databuffer.h" -#include "runnable_utils.h" #include "transportflow.h" #ifdef MOZILLA_INTERNAL_API @@ -37,35 +35,14 @@ namespace mozilla { // network -> transport -> [us] -> conduit -> [us] -> stream -> Playout // // The boxes labeled [us] are just bridge logic implemented in this class -// -// We have to deal with a number of threads: -// -// GSM: -// * Assembles the pipeline -// SocketTransportService -// * Receives notification that ICE and DTLS have completed -// * Processes incoming network data and passes it to the conduit -// * Processes outgoing RTP and RTCP -// MediaStreamGraph -// * Receives outgoing data from the MediaStreamGraph -// * Receives pull requests for more data from the -// MediaStreamGraph -// One or another GIPS threads -// * Receives RTCP messages to send to the other side -// * Processes video frames GIPS wants to render -// -// For a transmitting conduit, "output" is RTP and "input" is RTCP. -// For a receiving conduit, "input" is RTP and "output" is RTCP. -// class MediaPipeline : public sigslot::has_slots<> { public: enum Direction { TRANSMIT, RECEIVE }; enum State { MP_CONNECTING, MP_OPEN, MP_CLOSED }; - MediaPipeline(const std::string& pc, - Direction direction, + MediaPipeline(Direction direction, nsCOMPtr main_thread, nsCOMPtr sts_thread, - MediaStream *stream, + nsDOMMediaStream* stream, RefPtr conduit, RefPtr rtp_transport, RefPtr rtcp_transport) @@ -87,31 +64,21 @@ class MediaPipeline : public sigslot::has_slots<> { rtcp_packets_sent_(0), rtp_packets_received_(0), rtcp_packets_received_(0), - muxed_((rtcp_transport_ == NULL) || (rtp_transport_ == rtcp_transport_)), - pc_(pc), - description_() { + muxed_((rtcp_transport_ == NULL) || (rtp_transport_ == rtcp_transport_)) { + Init(); } virtual ~MediaPipeline() { - MOZ_ASSERT(!stream_); // Check that we have shut down already. - } - - void Shutdown() { - ASSERT_ON_THREAD(main_thread_); - // First shut down networking and then disconnect from - // the media streams. DetachTransport() is sync so - // we are sure that the transport is shut down before - // we touch stream_ or conduit_. DetachTransport(); - if (stream_) { - DetachMediaStream(); - } } virtual nsresult Init(); virtual Direction direction() const { return direction_; } + virtual void DetachMediaStream() {} + virtual void DetachTransport(); + int rtp_packets_sent() const { return rtp_packets_sent_; } int rtcp_packets_sent() const { return rtp_packets_sent_; } int rtp_packets_received() const { return rtp_packets_received_; } @@ -120,17 +87,13 @@ class MediaPipeline : public sigslot::has_slots<> { // Thread counting NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline) - protected: - virtual void DetachMediaStream() {} - + protected: // Separate class to allow ref counting class PipelineTransport : public TransportInterface { public: // Implement the TransportInterface functions PipelineTransport(MediaPipeline *pipeline) - : pipeline_(pipeline), - sts_thread_(pipeline->sts_thread_) {} - + : pipeline_(pipeline) {} void Detach() { pipeline_ = NULL; } MediaPipeline *pipeline() const { return pipeline_; } @@ -138,11 +101,7 @@ class MediaPipeline : public sigslot::has_slots<> { virtual nsresult SendRtcpPacket(const void* data, int len); private: - virtual nsresult SendRtpPacket_s(nsAutoPtr data); - virtual nsresult SendRtcpPacket_s(nsAutoPtr data); - MediaPipeline *pipeline_; // Raw pointer to avoid cycles - nsCOMPtr sts_thread_; }; friend class PipelineTransport; @@ -165,51 +124,31 @@ class MediaPipeline : public sigslot::has_slots<> { void PacketReceived(TransportLayer *layer, const unsigned char *data, size_t len); - Direction direction_; - RefPtr stream_; // A pointer to the stream we are servicing. - // Written on the main thread. - // Used on STS and MediaStreamGraph threads. - RefPtr conduit_; // Our conduit. Written on the main - // thread. Read on STS thread. - // The transport objects. Read/written on STS thread. + Direction direction_; + nsDOMMediaStream* stream_; + RefPtr conduit_; RefPtr rtp_transport_; State rtp_state_; RefPtr rtcp_transport_; State rtcp_state_; - - // Pointers to the threads we need. Initialized at creation - // and used all over the place. nsCOMPtr main_thread_; nsCOMPtr sts_thread_; - - // Created on Init. Referenced by the conduit and eventually - // destroyed on the STS thread. RefPtr transport_; - - // Used only on STS thread. + bool transport_connected_; RefPtr rtp_send_srtp_; RefPtr rtcp_send_srtp_; RefPtr rtp_recv_srtp_; RefPtr rtcp_recv_srtp_; - - // Written only on STS thread. May be read on other - // threads but since there is no mutex, the values - // will only be approximate. int rtp_packets_sent_; int rtcp_packets_sent_; int rtp_packets_received_; int rtcp_packets_received_; - - // Written on Init. Read on STS thread. bool muxed_; - std::string pc_; - std::string description_; private: - void DetachTransport(); - void DetachTransport_s(); - + virtual void DetachTransportInt(); + nsresult SendPacketInt(TransportFlow *flow, const void* data, int len); nsresult TransportReadyInt(TransportFlow *flow); bool IsRtp(const unsigned char *data, size_t len); @@ -220,44 +159,47 @@ class MediaPipeline : public sigslot::has_slots<> { // and transmitting to the network. class MediaPipelineTransmit : public MediaPipeline { public: - MediaPipelineTransmit(const std::string& pc, - nsCOMPtr main_thread, + MediaPipelineTransmit(nsCOMPtr main_thread, nsCOMPtr sts_thread, - MediaStream *stream, + nsDOMMediaStream* stream, RefPtr conduit, RefPtr rtp_transport, RefPtr rtcp_transport) : - MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, + MediaPipeline(TRANSMIT, main_thread, sts_thread, stream, conduit, rtp_transport, rtcp_transport), - listener_(new PipelineListener(conduit)) {} - - // Initialize (stuff here may fail) - virtual nsresult Init(); - - // Called on the main thread. - virtual void DetachMediaStream() { - ASSERT_ON_THREAD(main_thread_); - stream_->RemoveListener(listener_); - // Remove our reference so that when the MediaStreamGraph - // releases the listener, it will be destroyed. - listener_ = nullptr; - stream_ = nullptr; + listener_(new PipelineListener(this)) { + Init(); // TODO(ekr@rtfm.com): ignoring error } - // Override MediaPipeline::TransportReady. - virtual nsresult TransportReady(TransportFlow *flow); + // Initialize (stuff here may fail) + nsresult Init(); + + virtual ~MediaPipelineTransmit() { + if (stream_ && listener_){ + stream_->GetStream()->RemoveListener(listener_); + + // These shouldn't be necessary, but just to make sure + // that if we have messed up ownership somehow the + // interfaces just abort. + listener_->Detach(); + } + } + + virtual void DetachMediaStream() { + // TODO(ekr@rtfm.com): Are multiple removes a problem? + stream_->GetStream()->RemoveListener(listener_); + stream_ = NULL; + listener_->Detach(); + } // Separate class to allow ref counting class PipelineListener : public MediaStreamListener { public: - PipelineListener(const RefPtr& conduit) - : conduit_(conduit), active_(false) {} + PipelineListener(MediaPipelineTransmit *pipeline) : + pipeline_(pipeline) {} + void Detach() { pipeline_ = NULL; } - // XXX. This is not thread-safe but the hazard is just - // that active_ = true takes a while to propagate. Revisit - // when 823600 lands. - void SetActive(bool active) { active_ = active; } // Implement MediaStreamListener virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, @@ -268,19 +210,18 @@ class MediaPipelineTransmit : public MediaPipeline { virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) {} private: - virtual void ProcessAudioChunk(AudioSessionConduit *conduit, - TrackRate rate, AudioChunk& chunk); -#ifdef MOZILLA_INTERNAL_API - virtual void ProcessVideoChunk(VideoSessionConduit *conduit, - TrackRate rate, VideoChunk& chunk); -#endif - RefPtr conduit_; - volatile bool active_; + MediaPipelineTransmit *pipeline_; // Raw pointer to avoid cycles }; + friend class PipelineListener; private: -RefPtr listener_; - + virtual void ProcessAudioChunk(AudioSessionConduit *conduit, + TrackRate rate, AudioChunk& chunk); +#ifdef MOZILLA_INTERNAL_API + virtual void ProcessVideoChunk(VideoSessionConduit *conduit, + TrackRate rate, VideoChunk& chunk); +#endif + RefPtr listener_; }; @@ -288,14 +229,13 @@ RefPtr listener_; // rendering video. class MediaPipelineReceive : public MediaPipeline { public: - MediaPipelineReceive(const std::string& pc, - nsCOMPtr main_thread, + MediaPipelineReceive(nsCOMPtr main_thread, nsCOMPtr sts_thread, - MediaStream *stream, + nsDOMMediaStream* stream, RefPtr conduit, RefPtr rtp_transport, RefPtr rtcp_transport) : - MediaPipeline(pc, RECEIVE, main_thread, sts_thread, + MediaPipeline(RECEIVE, main_thread, sts_thread, stream, conduit, rtp_transport, rtcp_transport), segments_added_(0) { @@ -314,40 +254,41 @@ class MediaPipelineReceive : public MediaPipeline { // rendering audio. class MediaPipelineReceiveAudio : public MediaPipelineReceive { public: - MediaPipelineReceiveAudio(const std::string& pc, - nsCOMPtr main_thread, + MediaPipelineReceiveAudio(nsCOMPtr main_thread, nsCOMPtr sts_thread, - MediaStream *stream, + nsDOMMediaStream* stream, RefPtr conduit, RefPtr rtp_transport, RefPtr rtcp_transport) : - MediaPipelineReceive(pc, main_thread, sts_thread, + MediaPipelineReceive(main_thread, sts_thread, stream, conduit, rtp_transport, rtcp_transport), - listener_(new PipelineListener(stream->AsSourceStream(), - conduit)) { + listener_(new PipelineListener(this)) { + Init(); + } + + ~MediaPipelineReceiveAudio() { + if (stream_ && listener_) { + stream_->GetStream()->RemoveListener(listener_); + listener_->Detach(); + } } virtual void DetachMediaStream() { - ASSERT_ON_THREAD(main_thread_); - stream_->RemoveListener(listener_); - // Remove our reference so that when the MediaStreamGraph - // releases the listener, it will be destroyed. - listener_ = nullptr; - stream_ = nullptr; + // TODO(ekr@rtfm.com): Are multiple removes a problem? + stream_->GetStream()->RemoveListener(listener_); + stream_ = NULL; + listener_->Detach(); } - virtual nsresult Init(); - private: // Separate class to allow ref counting class PipelineListener : public MediaStreamListener { public: - PipelineListener(SourceMediaStream * source, - const RefPtr& conduit) - : source_(source), - conduit_(conduit), - played_(0) {} + PipelineListener(MediaPipelineReceiveAudio *pipeline) + : pipeline_(pipeline), + played_(0) {} + void Detach() { pipeline_ = NULL; } // Implement MediaStreamListener virtual void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, @@ -358,10 +299,12 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive { virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime); private: - SourceMediaStream *source_; - RefPtr conduit_; + MediaPipelineReceiveAudio *pipeline_; // Raw pointer to avoid cycles StreamTime played_; }; + friend class PipelineListener; + + nsresult Init(); RefPtr listener_; }; @@ -371,29 +314,22 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive { // rendering video. class MediaPipelineReceiveVideo : public MediaPipelineReceive { public: - MediaPipelineReceiveVideo(const std::string& pc, - nsCOMPtr main_thread, + MediaPipelineReceiveVideo(nsCOMPtr main_thread, nsCOMPtr sts_thread, - MediaStream *stream, + nsDOMMediaStream* stream, RefPtr conduit, RefPtr rtp_transport, RefPtr rtcp_transport) : - MediaPipelineReceive(pc, main_thread, sts_thread, + MediaPipelineReceive(main_thread, sts_thread, stream, conduit, rtp_transport, rtcp_transport), renderer_(new PipelineRenderer(this)) { + Init(); } - // Called on the main thread. - virtual void DetachMediaStream() { - ASSERT_ON_THREAD(main_thread_); - conduit_ = nullptr; // Force synchronous destruction so we - // stop generating video. - stream_ = nullptr; + ~MediaPipelineReceiveVideo() { } - virtual nsresult Init(); - private: class PipelineRenderer : public VideoRenderer { public: @@ -424,6 +360,7 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive { }; friend class PipelineRenderer; + nsresult Init(); RefPtr renderer_; }; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp index cc7e2b72596a..29e13a9089fa 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp @@ -31,9 +31,7 @@ nsresult PeerConnectionCtx::InitializeGlobal(nsIThread *mainThread) { gMainThread = mainThread; CSF::VcmSIPCCBinding::setMainThread(gMainThread); } else { -#ifdef MOZILLA_INTERNAL_API MOZ_ASSERT(gMainThread == mainThread); -#endif } nsresult res; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index b9930600ff06..55417fe2cc95 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -260,7 +260,19 @@ PeerConnectionImpl::MakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aRetval) } nsresult -PeerConnectionImpl::CreateRemoteSourceStreamInfo(uint32_t aHint, nsRefPtr* aInfo) +PeerConnectionImpl::MakeRemoteSource(nsDOMMediaStream* aStream, RemoteSourceStreamInfo** aInfo) +{ + MOZ_ASSERT(aInfo); + MOZ_ASSERT(aStream); + + // TODO(ekr@rtfm.com): Add the track info with the first segment + nsRefPtr remote = new RemoteSourceStreamInfo(aStream); + NS_ADDREF(*aInfo = remote); + return NS_OK; +} + +nsresult +PeerConnectionImpl::CreateRemoteSourceStreamInfo(uint32_t aHint, RemoteSourceStreamInfo** aInfo) { MOZ_ASSERT(aInfo); PC_AUTO_ENTER_API_CALL_NO_CHECK(); @@ -276,8 +288,19 @@ PeerConnectionImpl::CreateRemoteSourceStreamInfo(uint32_t aHint, nsRefPtr(comstream->GetStream())->SetPullEnabled(true); nsRefPtr remote; - remote = new RemoteSourceStreamInfo(comstream); - *aInfo = remote; + if (!mThread || NS_IsMainThread()) { + remote = new RemoteSourceStreamInfo(comstream); + NS_ADDREF(*aInfo = remote); + return NS_OK; + } + + mThread->Dispatch(WrapRunnableNMRet( + &PeerConnectionImpl::MakeRemoteSource, comstream, aInfo, &res + ), NS_DISPATCH_SYNC); + + if (NS_FAILED(res)) { + return res; + } return NS_OK; } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index f393a2c16df6..57f9f5231201 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -119,14 +119,14 @@ public: static nsresult ConvertConstraints( const JS::Value& aConstraints, MediaConstraints* aObj, JSContext* aCx); static nsresult MakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aStream); + static nsresult MakeRemoteSource(nsDOMMediaStream* aStream, RemoteSourceStreamInfo** aInfo); Role GetRole() const { PC_AUTO_ENTER_API_CALL_NO_CHECK(); return mRole; } - nsresult CreateRemoteSourceStreamInfo(uint32_t aHint, - nsRefPtr* aInfo); + nsresult CreateRemoteSourceStreamInfo(uint32_t aHint, RemoteSourceStreamInfo** aInfo); // Implementation of the only observer we need virtual void onCallEvent( diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index 774e849858a6..c7c404e41dbd 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -28,6 +28,22 @@ static const char* logTag = "PeerConnectionMedia"; static const mozilla::TrackID TRACK_AUDIO = 0; static const mozilla::TrackID TRACK_VIDEO = 1; +/* We get this callback in order to find out which tracks are audio and which + * are video. We should get this callback right away for existing streams after + * we add this class as a listener. + */ +void +LocalSourceStreamInfo::NotifyQueuedTrackChanges( + mozilla::MediaStreamGraph* aGraph, + mozilla::TrackID aID, + mozilla::TrackRate aTrackRate, + mozilla::TrackTicks aTrackOffset, + uint32_t aTrackEvents, + const mozilla::MediaSegment& aQueuedMedia) +{ + /* TODO: use this callback to keep track of changes to the MediaStream */ +} + /* If the ExpectAudio hint is on we will add a track at the default first * audio track ID (0) * FIX - Do we need to iterate over the tracks instead of taking these hints? @@ -181,6 +197,13 @@ PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream localSourceStream->ExpectVideo(TRACK_VIDEO); } + // Make it the listener for info from the MediaStream and add it to the list + mozilla::MediaStream *plainMediaStream = stream->GetStream(); + + if (plainMediaStream) { + plainMediaStream->AddListener(localSourceStream); + } + mLocalSourceStreams.AppendElement(localSourceStream); PR_Unlock(mLocalSourceStreamsLock); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h index 38b76580e379..f46cb8eabf2b 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h @@ -157,7 +157,7 @@ class Fake_VideoGenerator { }; #endif -class LocalSourceStreamInfo { +class LocalSourceStreamInfo : public mozilla::MediaStreamListener { public: LocalSourceStreamInfo(nsDOMMediaStream* aMediaStream) : mMediaStream(aMediaStream) {} @@ -165,6 +165,24 @@ public: mMediaStream = NULL; } + /** + * Notify that changes to one of the stream tracks have been queued. + * aTrackEvents can be any combination of TRACK_EVENT_CREATED and + * TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track + * at aTrackOffset (relative to the start of the stream). + */ + virtual void NotifyQueuedTrackChanges( + mozilla::MediaStreamGraph* aGraph, + mozilla::TrackID aID, + mozilla::TrackRate aTrackRate, + mozilla::TrackTicks aTrackOffset, + uint32_t aTrackEvents, + const mozilla::MediaSegment& aQueuedMedia + ); + + virtual void NotifyPull(mozilla::MediaStreamGraph* aGraph, + mozilla::StreamTime aDesiredTime) {} + nsDOMMediaStream* GetMediaStream() { return mMediaStream; } @@ -176,16 +194,18 @@ public: unsigned VideoTrackCount(); void Detach() { + // Disconnect my own listener + GetMediaStream()->GetStream()->RemoveListener(this); + // walk through all the MediaPipelines and disconnect them. for (std::map >::iterator it = mPipelines.begin(); it != mPipelines.end(); ++it) { - it->second->Shutdown(); + it->second->DetachMediaStream(); } mMediaStream = NULL; } - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo) private: std::map > mPipelines; nsRefPtr mMediaStream; @@ -209,7 +229,7 @@ class RemoteSourceStreamInfo { for (std::map >::iterator it = mPipelines.begin(); it != mPipelines.end(); ++it) { - it->second->Shutdown(); + it->second->DetachMediaStream(); } mMediaStream = NULL; } diff --git a/media/webrtc/signaling/test/mediapipeline_unittest.cpp b/media/webrtc/signaling/test/mediapipeline_unittest.cpp index 072962a1a3b5..908efe99f082 100644 --- a/media/webrtc/signaling/test/mediapipeline_unittest.cpp +++ b/media/webrtc/signaling/test/mediapipeline_unittest.cpp @@ -137,15 +137,9 @@ class TestAgentSend : public TestAgent { ConfigureSendMediaCodec(&audio_config_); EXPECT_EQ(mozilla::kMediaConduitNoError, err); - std::string test_pc("PC"); - - audio_pipeline_ = new mozilla::MediaPipelineTransmit( - test_pc, - NULL, - test_utils->sts_target(), - audio_->GetStream(), audio_conduit_, audio_flow_, NULL); - - audio_pipeline_->Init(); + audio_pipeline_ = new mozilla::MediaPipelineTransmit(NULL, + test_utils->sts_target(), + audio_, audio_conduit_, audio_flow_, NULL); // video_ = new Fake_nsDOMMediaStream(new Fake_VideoStreamSource()); // video_pipeline_ = new mozilla::MediaPipelineTransmit(video_, video_conduit_, &video_flow_, &video_flow_); @@ -176,16 +170,11 @@ class TestAgentReceive : public TestAgent { ConfigureRecvMediaCodecs(codecs); EXPECT_EQ(mozilla::kMediaConduitNoError, err); - std::string test_pc("PC"); - audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio( - test_pc, - NULL, - test_utils->sts_target(), - audio_->GetStream(), - static_cast(audio_conduit_.get()), - audio_flow_, NULL); - - audio_pipeline_->Init(); + audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(NULL, + test_utils->sts_target(), + audio_, + static_cast(audio_conduit_.get()), + audio_flow_, NULL); } private: