Backout 21409a401d75 (bug 821292),9587e39f9a50 (bug 820102) for conflicts and assertions respectively, on a CLOSED TREE

This commit is contained in:
Ed Morley 2012-12-21 16:15:01 +00:00
Родитель ef4b429105
Коммит 020839f9bb
12 изменённых файлов: 294 добавлений и 511 удалений

Просмотреть файл

@ -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 <algorithm>
#include <mozilla/Scoped.h>
#include <m_cpp_utils.h>
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<void *>(data_.get()),
static_cast<const void *>(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<uint8_t> data_;
size_t len_;
DISALLOW_COPY_ASSIGN(DataBuffer);
};
}
#endif

Просмотреть файл

@ -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<nsIRunnable> runnable_ref(runnable);
if (thread && (thread != nsRefPtr<nsIThread>(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<nsIThread>(do_GetCurrentThread()))) ? t->Dispatch(r, h) : r->Run())
}
#endif

Просмотреть файл

@ -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> 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<nsIEventTarget> target_;
};
@ -200,27 +183,6 @@ TEST_F(DispatchTest, TestNonMethodRet) {
ASSERT_EQ(10, z);
}
TEST_F(DispatchTest, TestDestructor) {
bool destroyed = false;
RefPtr<Destructor> 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> 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

Просмотреть файл

@ -909,7 +909,7 @@ static short vcmCreateRemoteStream_m(
hints |= nsDOMMediaStream::HINT_CONTENTS_VIDEO;
}
nsRefPtr<sipcc::RemoteSourceStreamInfo> 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<mozilla::MediaPipeline> 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<mozilla::VideoCodecConfig *> 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<mozilla::MediaPipeline> 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<mozilla::MediaPipeline> pipeline =
new mozilla::MediaPipelineTransmit(
pc.impl()->GetHandle(),
pc.impl()->GetMainThread().get(),
pc.impl()->GetSTSThread(),
stream->GetMediaStream()->GetStream(),
conduit, rtp_flow, rtcp_flow);
mozilla::RefPtr<mozilla::MediaPipelineTransmit> 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<mozilla::MediaPipeline> 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__);

Просмотреть файл

@ -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<void *>(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<TransportLayerDtls *>(
@ -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<void *>(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<void *>(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<void *>(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<TransportLayerDtls *>(
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<void *>(this)
<< " Flow : " << static_cast<void *>(rtp_transport_)
if (!(rtp_packets_sent_ % 1000)) {
MOZ_MTLOG(PR_LOG_DEBUG, "RTP packet count " << static_cast<void *>(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<void *>(this)
<< " Flow : " << static_cast<void *>(rtcp_transport_)
if (!(rtcp_packets_sent_ % 1000)) {
MOZ_MTLOG(PR_LOG_DEBUG, "RTCP packet count " << static_cast<void *>(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<void *>(this)
<< " Flow : " << static_cast<void *>(rtp_transport_)
if (!(rtp_packets_received_ % 1000)) {
MOZ_MTLOG(PR_LOG_DEBUG, "RTP packet count " << static_cast<void *>(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<void *>(this)
<< " Flow : " << static_cast<void *>(rtcp_transport_)
if (!(rtcp_packets_received_ % 1000)) {
MOZ_MTLOG(PR_LOG_DEBUG, "RTCP packet count " << static_cast<void *>(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<unsigned char> 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<void *>(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<MediaStream> 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<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
RUN_ON_THREAD(sts_thread_,
WrapRunnableRet(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpPacket_s,
buf, &ret),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
nsAutoPtr<DataBuffer> 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<unsigned char> 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<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
RUN_ON_THREAD(sts_thread_,
WrapRunnableRet(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtcpPacket_s,
buf, &ret),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
nsAutoPtr<DataBuffer> 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<unsigned char> 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<AudioSessionConduit*>(conduit_.get()),
rate, *iter);
pipeline_->ProcessAudioChunk(static_cast<AudioSessionConduit *>
(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<VideoSessionConduit*>(conduit_.get()),
rate, *iter);
pipeline_->ProcessVideoChunk(static_cast<VideoSessionConduit *>
(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<int16_t> 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<MediaStream> 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<AudioSessionConduit*>(conduit_.get())->GetAudioFrame(
static_cast<AudioSessionConduit*>(pipeline_->conduit_.get())->GetAudioFrame(
static_cast<int16_t *>(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<VideoSessionConduit *>(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;

Просмотреть файл

@ -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<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream,
nsDOMMediaStream* stream,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> 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<DataBuffer> data);
virtual nsresult SendRtcpPacket_s(nsAutoPtr<DataBuffer> data);
MediaPipeline *pipeline_; // Raw pointer to avoid cycles
nsCOMPtr<nsIEventTarget> 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<MediaStream> stream_; // A pointer to the stream we are servicing.
// Written on the main thread.
// Used on STS and MediaStreamGraph threads.
RefPtr<MediaSessionConduit> 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<MediaSessionConduit> conduit_;
RefPtr<TransportFlow> rtp_transport_;
State rtp_state_;
RefPtr<TransportFlow> rtcp_transport_;
State rtcp_state_;
// Pointers to the threads we need. Initialized at creation
// and used all over the place.
nsCOMPtr<nsIEventTarget> main_thread_;
nsCOMPtr<nsIEventTarget> sts_thread_;
// Created on Init. Referenced by the conduit and eventually
// destroyed on the STS thread.
RefPtr<PipelineTransport> transport_;
// Used only on STS thread.
bool transport_connected_;
RefPtr<SrtpFlow> rtp_send_srtp_;
RefPtr<SrtpFlow> rtcp_send_srtp_;
RefPtr<SrtpFlow> rtp_recv_srtp_;
RefPtr<SrtpFlow> 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<nsIEventTarget> main_thread,
MediaPipelineTransmit(nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream,
nsDOMMediaStream* stream,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> 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<MediaSessionConduit>& 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<MediaSessionConduit> conduit_;
volatile bool active_;
MediaPipelineTransmit *pipeline_; // Raw pointer to avoid cycles
};
friend class PipelineListener;
private:
RefPtr<PipelineListener> 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<PipelineListener> listener_;
};
@ -288,14 +229,13 @@ RefPtr<PipelineListener> listener_;
// rendering video.
class MediaPipelineReceive : public MediaPipeline {
public:
MediaPipelineReceive(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
MediaPipelineReceive(nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream,
nsDOMMediaStream* stream,
RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> 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<nsIEventTarget> main_thread,
MediaPipelineReceiveAudio(nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream,
nsDOMMediaStream* stream,
RefPtr<AudioSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> 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<MediaSessionConduit>& 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<MediaSessionConduit> conduit_;
MediaPipelineReceiveAudio *pipeline_; // Raw pointer to avoid cycles
StreamTime played_;
};
friend class PipelineListener;
nsresult Init();
RefPtr<PipelineListener> listener_;
};
@ -371,29 +314,22 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive {
// rendering video.
class MediaPipelineReceiveVideo : public MediaPipelineReceive {
public:
MediaPipelineReceiveVideo(const std::string& pc,
nsCOMPtr<nsIEventTarget> main_thread,
MediaPipelineReceiveVideo(nsCOMPtr<nsIEventTarget> main_thread,
nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream,
nsDOMMediaStream* stream,
RefPtr<VideoSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> 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<PipelineRenderer> renderer_;
};

Просмотреть файл

@ -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;

Просмотреть файл

@ -260,7 +260,19 @@ PeerConnectionImpl::MakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aRetval)
}
nsresult
PeerConnectionImpl::CreateRemoteSourceStreamInfo(uint32_t aHint, nsRefPtr<RemoteSourceStreamInfo>* 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<RemoteSourceStreamInfo> 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<Remote
static_cast<mozilla::SourceMediaStream*>(comstream->GetStream())->SetPullEnabled(true);
nsRefPtr<RemoteSourceStreamInfo> 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;
}

Просмотреть файл

@ -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<RemoteSourceStreamInfo>* aInfo);
nsresult CreateRemoteSourceStreamInfo(uint32_t aHint, RemoteSourceStreamInfo** aInfo);
// Implementation of the only observer we need
virtual void onCallEvent(

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<int, mozilla::RefPtr<mozilla::MediaPipeline> >::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<int, mozilla::RefPtr<mozilla::MediaPipeline> > mPipelines;
nsRefPtr<nsDOMMediaStream> mMediaStream;
@ -209,7 +229,7 @@ class RemoteSourceStreamInfo {
for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
mPipelines.begin(); it != mPipelines.end();
++it) {
it->second->Shutdown();
it->second->DetachMediaStream();
}
mMediaStream = NULL;
}

Просмотреть файл

@ -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<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
audio_flow_, NULL);
audio_pipeline_->Init();
audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(NULL,
test_utils->sts_target(),
audio_,
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
audio_flow_, NULL);
}
private: