зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1208371 - Forward declare MediaStreamGraph classes in MediaPipeline.h. r=bwc
MozReview-Commit-ID: DsDHelzMsz0 --HG-- extra : rebase_source : b83f9298795de1ae803930f17df4ba18f00e8425
This commit is contained in:
Родитель
b40a807720
Коммит
785d6859a4
|
@ -22,6 +22,7 @@
|
||||||
#include "LayersLogging.h"
|
#include "LayersLogging.h"
|
||||||
#include "ImageTypes.h"
|
#include "ImageTypes.h"
|
||||||
#include "ImageContainer.h"
|
#include "ImageContainer.h"
|
||||||
|
#include "DOMMediaStream.h"
|
||||||
#include "MediaStreamTrack.h"
|
#include "MediaStreamTrack.h"
|
||||||
#include "VideoUtils.h"
|
#include "VideoUtils.h"
|
||||||
#ifdef WEBRTC_GONK
|
#ifdef WEBRTC_GONK
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "AudioSegment.h"
|
#include "AudioSegment.h"
|
||||||
#include "MediaSegment.h"
|
#include "MediaSegment.h"
|
||||||
|
#include "MediaPipelineFilter.h"
|
||||||
#include "databuffer.h"
|
#include "databuffer.h"
|
||||||
#include "transportflow.h"
|
#include "transportflow.h"
|
||||||
#include "transportlayer.h"
|
#include "transportlayer.h"
|
||||||
|
@ -70,6 +72,44 @@ namespace mozilla {
|
||||||
|
|
||||||
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
||||||
|
|
||||||
|
MediaPipeline::MediaPipeline(const std::string& pc,
|
||||||
|
Direction direction,
|
||||||
|
nsCOMPtr<nsIEventTarget> main_thread,
|
||||||
|
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||||
|
const std::string& track_id,
|
||||||
|
int level,
|
||||||
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
|
nsAutoPtr<MediaPipelineFilter> filter)
|
||||||
|
: direction_(direction),
|
||||||
|
track_id_(track_id),
|
||||||
|
level_(level),
|
||||||
|
conduit_(conduit),
|
||||||
|
rtp_(rtp_transport, rtcp_transport ? RTP : MUX),
|
||||||
|
rtcp_(rtcp_transport ? rtcp_transport : rtp_transport,
|
||||||
|
rtcp_transport ? RTCP : MUX),
|
||||||
|
main_thread_(main_thread),
|
||||||
|
sts_thread_(sts_thread),
|
||||||
|
rtp_packets_sent_(0),
|
||||||
|
rtcp_packets_sent_(0),
|
||||||
|
rtp_packets_received_(0),
|
||||||
|
rtcp_packets_received_(0),
|
||||||
|
rtp_bytes_sent_(0),
|
||||||
|
rtp_bytes_received_(0),
|
||||||
|
pc_(pc),
|
||||||
|
description_(),
|
||||||
|
filter_(filter),
|
||||||
|
rtp_parser_(webrtc::RtpHeaderParser::Create()) {
|
||||||
|
// To indicate rtcp-mux rtcp_transport should be nullptr.
|
||||||
|
// Therefore it's an error to send in the same flow for
|
||||||
|
// both rtp and rtcp.
|
||||||
|
MOZ_ASSERT(rtp_transport != rtcp_transport);
|
||||||
|
|
||||||
|
// PipelineTransport() will access this->sts_thread_; moved here for safety
|
||||||
|
transport_ = new PipelineTransport(this);
|
||||||
|
}
|
||||||
|
|
||||||
MediaPipeline::~MediaPipeline() {
|
MediaPipeline::~MediaPipeline() {
|
||||||
ASSERT_ON_THREAD(main_thread_);
|
ASSERT_ON_THREAD(main_thread_);
|
||||||
MOZ_MTLOG(ML_INFO, "Destroying MediaPipeline: " << description_);
|
MOZ_MTLOG(ML_INFO, "Destroying MediaPipeline: " << description_);
|
||||||
|
@ -642,6 +682,119 @@ void MediaPipeline::PacketReceived(TransportLayer *layer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MediaPipelineTransmit::PipelineListener
|
||||||
|
: public MediaStreamTrackDirectListener
|
||||||
|
{
|
||||||
|
friend class MediaPipelineTransmit;
|
||||||
|
public:
|
||||||
|
explicit PipelineListener(const RefPtr<MediaSessionConduit>& conduit)
|
||||||
|
: conduit_(conduit),
|
||||||
|
track_id_(TRACK_INVALID),
|
||||||
|
mMutex("MediaPipelineTransmit::PipelineListener"),
|
||||||
|
track_id_external_(TRACK_INVALID),
|
||||||
|
active_(false),
|
||||||
|
enabled_(false),
|
||||||
|
direct_connect_(false),
|
||||||
|
packetizer_(nullptr)
|
||||||
|
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||||
|
, last_img_(-1)
|
||||||
|
#endif // MOZILLA_EXTERNAL_LINKAGE
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PipelineListener()
|
||||||
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
// release conduit on mainthread. Must use forget()!
|
||||||
|
nsresult rv = NS_DispatchToMainThread(new
|
||||||
|
ConduitDeleteEvent(conduit_.forget()));
|
||||||
|
MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conduit_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatches setting the internal TrackID to TRACK_INVALID to the media
|
||||||
|
// graph thread to keep it in sync with other MediaStreamGraph operations
|
||||||
|
// like RemoveListener() and AddListener(). The TrackID will be updated on
|
||||||
|
// the next NewData() callback.
|
||||||
|
void UnsetTrackId(MediaStreamGraphImpl* graph);
|
||||||
|
|
||||||
|
void SetActive(bool active) { active_ = active; }
|
||||||
|
void SetEnabled(bool enabled) { enabled_ = enabled; }
|
||||||
|
|
||||||
|
// Implement MediaStreamTrackListener
|
||||||
|
void NotifyQueuedChanges(MediaStreamGraph* aGraph,
|
||||||
|
StreamTime aTrackOffset,
|
||||||
|
const MediaSegment& aQueuedMedia) override;
|
||||||
|
|
||||||
|
// Implement MediaStreamTrackDirectListener
|
||||||
|
void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
|
||||||
|
StreamTime aTrackOffset,
|
||||||
|
const MediaSegment& aMedia) override;
|
||||||
|
void NotifyDirectListenerInstalled(InstallationResult aResult) override;
|
||||||
|
void NotifyDirectListenerUninstalled() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UnsetTrackIdImpl() {
|
||||||
|
MutexAutoLock lock(mMutex);
|
||||||
|
track_id_ = track_id_external_ = TRACK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewData(MediaStreamGraph* graph,
|
||||||
|
StreamTime offset,
|
||||||
|
const MediaSegment& media);
|
||||||
|
|
||||||
|
virtual void ProcessAudioChunk(AudioSessionConduit *conduit,
|
||||||
|
TrackRate rate, AudioChunk& chunk);
|
||||||
|
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||||
|
virtual void ProcessVideoChunk(VideoSessionConduit *conduit,
|
||||||
|
VideoChunk& chunk);
|
||||||
|
#endif // MOZILLA_EXTERNAL_LINKAGE
|
||||||
|
RefPtr<MediaSessionConduit> conduit_;
|
||||||
|
|
||||||
|
// May be TRACK_INVALID until we see data from the track
|
||||||
|
TrackID track_id_; // this is the current TrackID this listener is attached to
|
||||||
|
Mutex mMutex;
|
||||||
|
// protected by mMutex
|
||||||
|
// May be TRACK_INVALID until we see data from the track
|
||||||
|
TrackID track_id_external_; // this is queried from other threads
|
||||||
|
|
||||||
|
// active is true if there is a transport to send on
|
||||||
|
mozilla::Atomic<bool> active_;
|
||||||
|
// enabled is true if the media access control permits sending
|
||||||
|
// actual content; when false you get black/silence
|
||||||
|
mozilla::Atomic<bool> enabled_;
|
||||||
|
|
||||||
|
// Written and read on the MediaStreamGraph thread
|
||||||
|
bool direct_connect_;
|
||||||
|
|
||||||
|
nsAutoPtr<AudioPacketizer<int16_t, int16_t>> packetizer_;
|
||||||
|
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||||
|
int32_t last_img_; // serial number of last Image
|
||||||
|
#endif // MOZILLA_EXTERNAL_LINKAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaPipelineTransmit::MediaPipelineTransmit(
|
||||||
|
const std::string& pc,
|
||||||
|
nsCOMPtr<nsIEventTarget> main_thread,
|
||||||
|
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||||
|
dom::MediaStreamTrack* domtrack,
|
||||||
|
const std::string& track_id,
|
||||||
|
int level,
|
||||||
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
|
nsAutoPtr<MediaPipelineFilter> filter) :
|
||||||
|
MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, track_id, level,
|
||||||
|
conduit, rtp_transport, rtcp_transport, filter),
|
||||||
|
listener_(new PipelineListener(conduit)),
|
||||||
|
domtrack_(domtrack)
|
||||||
|
{}
|
||||||
|
|
||||||
nsresult MediaPipelineTransmit::Init() {
|
nsresult MediaPipelineTransmit::Init() {
|
||||||
AttachToTrack(track_id_);
|
AttachToTrack(track_id_);
|
||||||
|
|
||||||
|
@ -1315,19 +1468,29 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsresult MediaPipelineReceiveAudio::Init() {
|
class TrackAddedCallback {
|
||||||
ASSERT_ON_THREAD(main_thread_);
|
public:
|
||||||
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
virtual void TrackAdded(TrackTicks current_ticks) = 0;
|
||||||
|
|
||||||
description_ = pc_ + "| Receive audio[";
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackAddedCallback);
|
||||||
description_ += track_id_;
|
|
||||||
description_ += "]";
|
|
||||||
|
|
||||||
listener_->AddSelf(new AudioSegment());
|
protected:
|
||||||
|
virtual ~TrackAddedCallback() {}
|
||||||
|
};
|
||||||
|
|
||||||
return MediaPipelineReceive::Init();
|
class GenericReceiveListener;
|
||||||
}
|
|
||||||
|
|
||||||
|
class GenericReceiveCallback : public TrackAddedCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit GenericReceiveCallback(GenericReceiveListener* listener)
|
||||||
|
: listener_(listener) {}
|
||||||
|
|
||||||
|
void TrackAdded(TrackTicks time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<GenericReceiveListener> listener_;
|
||||||
|
};
|
||||||
|
|
||||||
// Add a track and listener on the MSG thread using the MSG command queue
|
// Add a track and listener on the MSG thread using the MSG command queue
|
||||||
static void AddTrackAndListener(MediaStream* source,
|
static void AddTrackAndListener(MediaStream* source,
|
||||||
|
@ -1415,14 +1578,38 @@ static void AddTrackAndListener(MediaStream* source,
|
||||||
" on MediaStream " << source);
|
" on MediaStream " << source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericReceiveListener::AddSelf(MediaSegment* segment) {
|
class GenericReceiveListener : public MediaStreamListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericReceiveListener(SourceMediaStream *source, TrackID track_id,
|
||||||
|
TrackRate track_rate, bool queue_track)
|
||||||
|
: source_(source),
|
||||||
|
track_id_(track_id),
|
||||||
|
track_rate_(track_rate),
|
||||||
|
played_ticks_(0),
|
||||||
|
queue_track_(queue_track),
|
||||||
|
principal_handle_(PRINCIPAL_HANDLE_NONE) {}
|
||||||
|
|
||||||
|
virtual ~GenericReceiveListener() {}
|
||||||
|
|
||||||
|
void AddSelf(MediaSegment* segment)
|
||||||
|
{
|
||||||
RefPtr<TrackAddedCallback> callback = new GenericReceiveCallback(this);
|
RefPtr<TrackAddedCallback> callback = new GenericReceiveCallback(this);
|
||||||
AddTrackAndListener(source_, track_id_, track_rate_, this, segment, callback,
|
AddTrackAndListener(source_, track_id_, track_rate_, this, segment, callback,
|
||||||
queue_track_);
|
queue_track_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetPlayedTicks(TrackTicks time) {
|
||||||
|
played_ticks_ = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndTrack() {
|
||||||
|
source_->EndTrack(track_id_);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef USE_FAKE_MEDIA_STREAMS
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
void GenericReceiveListener::SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
|
// Must be called on the main thread
|
||||||
|
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
|
||||||
{
|
{
|
||||||
class Message : public ControlMessage
|
class Message : public ControlMessage
|
||||||
{
|
{
|
||||||
|
@ -1430,7 +1617,9 @@ void GenericReceiveListener::SetPrincipalHandle_m(const PrincipalHandle& princip
|
||||||
Message(GenericReceiveListener* listener,
|
Message(GenericReceiveListener* listener,
|
||||||
MediaStream* stream,
|
MediaStream* stream,
|
||||||
const PrincipalHandle& principal_handle)
|
const PrincipalHandle& principal_handle)
|
||||||
: ControlMessage(stream), listener_(listener), principal_handle_(principal_handle)
|
: ControlMessage(stream),
|
||||||
|
listener_(listener),
|
||||||
|
principal_handle_(principal_handle)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void Run() override {
|
void Run() override {
|
||||||
|
@ -1444,23 +1633,90 @@ void GenericReceiveListener::SetPrincipalHandle_m(const PrincipalHandle& princip
|
||||||
source_->GraphImpl()->AppendMessage(MakeUnique<Message>(this, source_, principal_handle));
|
source_->GraphImpl()->AppendMessage(MakeUnique<Message>(this, source_, principal_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericReceiveListener::SetPrincipalHandle_msg(const PrincipalHandle& principal_handle)
|
// Must be called on the MediaStreamGraph thread
|
||||||
|
void SetPrincipalHandle_msg(const PrincipalHandle& principal_handle)
|
||||||
{
|
{
|
||||||
principal_handle_ = principal_handle;
|
principal_handle_ = principal_handle;
|
||||||
}
|
}
|
||||||
#endif // USE_FAKE_MEDIA_STREAMS
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
MediaPipelineReceiveAudio::PipelineListener::PipelineListener(
|
protected:
|
||||||
SourceMediaStream * source, TrackID track_id,
|
SourceMediaStream *source_;
|
||||||
const RefPtr<MediaSessionConduit>& conduit, bool queue_track)
|
TrackID track_id_;
|
||||||
|
TrackRate track_rate_;
|
||||||
|
TrackTicks played_ticks_;
|
||||||
|
bool queue_track_;
|
||||||
|
PrincipalHandle principal_handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void GenericReceiveCallback::TrackAdded(TrackTicks time)
|
||||||
|
{
|
||||||
|
listener_->SetPlayedTicks(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPipelineReceive::MediaPipelineReceive(
|
||||||
|
const std::string& pc,
|
||||||
|
nsCOMPtr<nsIEventTarget> main_thread,
|
||||||
|
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||||
|
SourceMediaStream *stream,
|
||||||
|
const std::string& track_id,
|
||||||
|
int level,
|
||||||
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
|
nsAutoPtr<MediaPipelineFilter> filter) :
|
||||||
|
MediaPipeline(pc, RECEIVE, main_thread, sts_thread,
|
||||||
|
track_id, level, conduit, rtp_transport,
|
||||||
|
rtcp_transport, filter),
|
||||||
|
stream_(stream),
|
||||||
|
segments_added_(0)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(stream_);
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPipelineReceive::~MediaPipelineReceive()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!stream_); // Check that we have shut down already.
|
||||||
|
}
|
||||||
|
|
||||||
|
class MediaPipelineReceiveAudio::PipelineListener
|
||||||
|
: public GenericReceiveListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PipelineListener(SourceMediaStream * source, TrackID track_id,
|
||||||
|
const RefPtr<MediaSessionConduit>& conduit,
|
||||||
|
bool queue_track)
|
||||||
: GenericReceiveListener(source, track_id, DEFAULT_SAMPLE_RATE, queue_track), // XXX rate assumption
|
: GenericReceiveListener(source, track_id, DEFAULT_SAMPLE_RATE, queue_track), // XXX rate assumption
|
||||||
conduit_(conduit)
|
conduit_(conduit)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(track_rate_%100 == 0);
|
MOZ_ASSERT(track_rate_%100 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPipelineReceiveAudio::PipelineListener::
|
~PipelineListener()
|
||||||
NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
{
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
// release conduit on mainthread. Must use forget()!
|
||||||
|
nsresult rv = NS_DispatchToMainThread(new
|
||||||
|
ConduitDeleteEvent(conduit_.forget()));
|
||||||
|
MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conduit_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement MediaStreamListener
|
||||||
|
void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
|
||||||
|
StreamTime offset,
|
||||||
|
uint32_t events,
|
||||||
|
const MediaSegment& queued_media,
|
||||||
|
MediaStream* input_stream,
|
||||||
|
TrackID input_tid) override {}
|
||||||
|
|
||||||
|
void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) override
|
||||||
|
{
|
||||||
MOZ_ASSERT(source_);
|
MOZ_ASSERT(source_);
|
||||||
if (!source_) {
|
if (!source_) {
|
||||||
MOZ_MTLOG(ML_ERROR, "NotifyPull() called from a non-SourceMediaStream");
|
MOZ_MTLOG(ML_ERROR, "NotifyPull() called from a non-SourceMediaStream");
|
||||||
|
@ -1542,27 +1798,64 @@ NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaPipelineReceiveVideo::Init() {
|
private:
|
||||||
|
RefPtr<MediaSessionConduit> conduit_;
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaPipelineReceiveAudio::MediaPipelineReceiveAudio(
|
||||||
|
const std::string& pc,
|
||||||
|
nsCOMPtr<nsIEventTarget> main_thread,
|
||||||
|
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||||
|
SourceMediaStream* stream,
|
||||||
|
const std::string& media_stream_track_id,
|
||||||
|
TrackID numeric_track_id,
|
||||||
|
int level,
|
||||||
|
RefPtr<AudioSessionConduit> conduit,
|
||||||
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
|
nsAutoPtr<MediaPipelineFilter> filter,
|
||||||
|
bool queue_track) :
|
||||||
|
MediaPipelineReceive(pc, main_thread, sts_thread,
|
||||||
|
stream, media_stream_track_id, level, conduit,
|
||||||
|
rtp_transport, rtcp_transport, filter),
|
||||||
|
listener_(new PipelineListener(stream, numeric_track_id, conduit,
|
||||||
|
queue_track))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void MediaPipelineReceiveAudio::DetachMedia()
|
||||||
|
{
|
||||||
|
ASSERT_ON_THREAD(main_thread_);
|
||||||
|
if (stream_) {
|
||||||
|
stream_->RemoveListener(listener_);
|
||||||
|
stream_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult MediaPipelineReceiveAudio::Init() {
|
||||||
ASSERT_ON_THREAD(main_thread_);
|
ASSERT_ON_THREAD(main_thread_);
|
||||||
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
||||||
|
|
||||||
description_ = pc_ + "| Receive video[";
|
description_ = pc_ + "| Receive audio[";
|
||||||
description_ += track_id_;
|
description_ += track_id_;
|
||||||
description_ += "]";
|
description_ += "]";
|
||||||
|
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
listener_->AddSelf(new AudioSegment());
|
||||||
listener_->AddSelf(new VideoSegment());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Always happens before we can DetachMedia()
|
|
||||||
static_cast<VideoSessionConduit *>(conduit_.get())->
|
|
||||||
AttachRenderer(renderer_);
|
|
||||||
|
|
||||||
return MediaPipelineReceive::Init();
|
return MediaPipelineReceive::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaPipelineReceiveVideo::PipelineListener::PipelineListener(
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
SourceMediaStream* source, TrackID track_id, bool queue_track)
|
void MediaPipelineReceiveAudio::SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
|
||||||
|
{
|
||||||
|
listener_->SetPrincipalHandle_m(principal_handle);
|
||||||
|
}
|
||||||
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
|
class MediaPipelineReceiveVideo::PipelineListener
|
||||||
|
: public GenericReceiveListener {
|
||||||
|
public:
|
||||||
|
PipelineListener(SourceMediaStream * source, TrackID track_id,
|
||||||
|
bool queue_track)
|
||||||
: GenericReceiveListener(source, track_id, source->GraphRate(), queue_track),
|
: GenericReceiveListener(source, track_id, source->GraphRate(), queue_track),
|
||||||
width_(640),
|
width_(640),
|
||||||
height_(480),
|
height_(480),
|
||||||
|
@ -1570,31 +1863,80 @@ MediaPipelineReceiveVideo::PipelineListener::PipelineListener(
|
||||||
image_container_(),
|
image_container_(),
|
||||||
image_(),
|
image_(),
|
||||||
#endif
|
#endif
|
||||||
monitor_("Video PipelineListener") {
|
monitor_("Video PipelineListener")
|
||||||
|
{
|
||||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||||
image_container_ = LayerManager::CreateImageContainer();
|
image_container_ = LayerManager::CreateImageContainer();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
|
|
||||||
const unsigned char* buffer,
|
// Implement MediaStreamListener
|
||||||
|
void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
|
||||||
|
StreamTime offset,
|
||||||
|
uint32_t events,
|
||||||
|
const MediaSegment& queued_media,
|
||||||
|
MediaStream* input_stream,
|
||||||
|
TrackID input_tid) override {}
|
||||||
|
void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) override
|
||||||
|
{
|
||||||
|
ReentrantMonitorAutoEnter enter(monitor_);
|
||||||
|
|
||||||
|
#if defined(MOZILLA_INTERNAL_API)
|
||||||
|
RefPtr<Image> image = image_;
|
||||||
|
// our constructor sets track_rate_ to the graph rate
|
||||||
|
MOZ_ASSERT(track_rate_ == source_->GraphRate());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MOZILLA_INTERNAL_API)
|
||||||
|
StreamTime delta = desired_time - played_ticks_;
|
||||||
|
|
||||||
|
// Don't append if we've already provided a frame that supposedly
|
||||||
|
// goes past the current aDesiredTime Doing so means a negative
|
||||||
|
// delta and thus messes up handling of the graph
|
||||||
|
if (delta > 0) {
|
||||||
|
VideoSegment segment;
|
||||||
|
segment.AppendFrame(image.forget(), delta, IntSize(width_, height_),
|
||||||
|
principal_handle_);
|
||||||
|
// Handle track not actually added yet or removed/finished
|
||||||
|
if (source_->AppendToTrack(track_id_, &segment)) {
|
||||||
|
played_ticks_ = desired_time;
|
||||||
|
} else {
|
||||||
|
MOZ_MTLOG(ML_ERROR, "AppendToTrack failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessors for external writes from the renderer
|
||||||
|
void FrameSizeChange(unsigned int width,
|
||||||
|
unsigned int height,
|
||||||
|
unsigned int number_of_streams) {
|
||||||
|
ReentrantMonitorAutoEnter enter(monitor_);
|
||||||
|
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderVideoFrame(const unsigned char* buffer,
|
||||||
size_t buffer_size,
|
size_t buffer_size,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time,
|
int64_t render_time,
|
||||||
const RefPtr<Image>& video_image) {
|
const RefPtr<layers::Image>& video_image)
|
||||||
|
{
|
||||||
RenderVideoFrame(buffer, buffer_size, width_, (width_ + 1) >> 1,
|
RenderVideoFrame(buffer, buffer_size, width_, (width_ + 1) >> 1,
|
||||||
time_stamp, render_time, video_image);
|
time_stamp, render_time, video_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
|
void RenderVideoFrame(const unsigned char* buffer,
|
||||||
const unsigned char* buffer,
|
|
||||||
size_t buffer_size,
|
size_t buffer_size,
|
||||||
uint32_t y_stride,
|
uint32_t y_stride,
|
||||||
uint32_t cbcr_stride,
|
uint32_t cbcr_stride,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time,
|
int64_t render_time,
|
||||||
const RefPtr<Image>& video_image) {
|
const RefPtr<layers::Image>& video_image)
|
||||||
|
{
|
||||||
#ifdef MOZILLA_INTERNAL_API
|
#ifdef MOZILLA_INTERNAL_API
|
||||||
ReentrantMonitorAutoEnter enter(monitor_);
|
ReentrantMonitorAutoEnter enter(monitor_);
|
||||||
#endif // MOZILLA_INTERNAL_API
|
#endif // MOZILLA_INTERNAL_API
|
||||||
|
@ -1639,36 +1981,125 @@ void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
|
||||||
#endif // MOZILLA_INTERNAL_API
|
#endif // MOZILLA_INTERNAL_API
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaPipelineReceiveVideo::PipelineListener::
|
private:
|
||||||
NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
|
int width_;
|
||||||
ReentrantMonitorAutoEnter enter(monitor_);
|
int height_;
|
||||||
|
#if defined(MOZILLA_INTERNAL_API)
|
||||||
|
RefPtr<layers::ImageContainer> image_container_;
|
||||||
|
RefPtr<layers::Image> image_;
|
||||||
|
#endif
|
||||||
|
mozilla::ReentrantMonitor monitor_; // Monitor for processing WebRTC frames.
|
||||||
|
// Protects image_ against:
|
||||||
|
// - Writing from the GIPS thread
|
||||||
|
// - Reading from the MSG thread
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaPipelineReceiveVideo::PipelineRenderer : public VideoRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PipelineRenderer(MediaPipelineReceiveVideo *pipeline) :
|
||||||
|
pipeline_(pipeline) {}
|
||||||
|
|
||||||
|
void Detach() { pipeline_ = nullptr; }
|
||||||
|
|
||||||
|
// Implement VideoRenderer
|
||||||
|
void FrameSizeChange(unsigned int width,
|
||||||
|
unsigned int height,
|
||||||
|
unsigned int number_of_streams) override
|
||||||
|
{
|
||||||
|
pipeline_->listener_->FrameSizeChange(width, height, number_of_streams);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderVideoFrame(const unsigned char* buffer,
|
||||||
|
size_t buffer_size,
|
||||||
|
uint32_t time_stamp,
|
||||||
|
int64_t render_time,
|
||||||
|
const ImageHandle& handle) override
|
||||||
|
{
|
||||||
|
pipeline_->listener_->RenderVideoFrame(buffer, buffer_size,
|
||||||
|
time_stamp, render_time,
|
||||||
|
handle.GetImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderVideoFrame(const unsigned char* buffer,
|
||||||
|
size_t buffer_size,
|
||||||
|
uint32_t y_stride,
|
||||||
|
uint32_t cbcr_stride,
|
||||||
|
uint32_t time_stamp,
|
||||||
|
int64_t render_time,
|
||||||
|
const ImageHandle& handle) override
|
||||||
|
{
|
||||||
|
pipeline_->listener_->RenderVideoFrame(buffer, buffer_size,
|
||||||
|
y_stride, cbcr_stride,
|
||||||
|
time_stamp, render_time,
|
||||||
|
handle.GetImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MediaPipelineReceiveVideo *pipeline_; // Raw pointer to avoid cycles
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
MediaPipelineReceiveVideo::MediaPipelineReceiveVideo(
|
||||||
|
const std::string& pc,
|
||||||
|
nsCOMPtr<nsIEventTarget> main_thread,
|
||||||
|
nsCOMPtr<nsIEventTarget> sts_thread,
|
||||||
|
SourceMediaStream *stream,
|
||||||
|
const std::string& media_stream_track_id,
|
||||||
|
TrackID numeric_track_id,
|
||||||
|
int level,
|
||||||
|
RefPtr<VideoSessionConduit> conduit,
|
||||||
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
|
nsAutoPtr<MediaPipelineFilter> filter,
|
||||||
|
bool queue_track) :
|
||||||
|
MediaPipelineReceive(pc, main_thread, sts_thread,
|
||||||
|
stream, media_stream_track_id, level, conduit,
|
||||||
|
rtp_transport, rtcp_transport, filter),
|
||||||
|
renderer_(new PipelineRenderer(this)),
|
||||||
|
listener_(new PipelineListener(stream, numeric_track_id, queue_track))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void MediaPipelineReceiveVideo::DetachMedia()
|
||||||
|
{
|
||||||
|
ASSERT_ON_THREAD(main_thread_);
|
||||||
|
|
||||||
|
listener_->EndTrack();
|
||||||
|
// stop generating video and thus stop invoking the PipelineRenderer
|
||||||
|
// and PipelineListener - the renderer has a raw ptr to the Pipeline to
|
||||||
|
// avoid cycles, and the render callbacks are invoked from a different
|
||||||
|
// thread so simple null-checks would cause TSAN bugs without locks.
|
||||||
|
static_cast<VideoSessionConduit*>(conduit_.get())->DetachRenderer();
|
||||||
|
if (stream_) {
|
||||||
|
stream_->RemoveListener(listener_);
|
||||||
|
stream_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult MediaPipelineReceiveVideo::Init() {
|
||||||
|
ASSERT_ON_THREAD(main_thread_);
|
||||||
|
MOZ_MTLOG(ML_DEBUG, __FUNCTION__);
|
||||||
|
|
||||||
|
description_ = pc_ + "| Receive video[";
|
||||||
|
description_ += track_id_;
|
||||||
|
description_ += "]";
|
||||||
|
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
#if defined(MOZILLA_INTERNAL_API)
|
||||||
RefPtr<Image> image = image_;
|
listener_->AddSelf(new VideoSegment());
|
||||||
// our constructor sets track_rate_ to the graph rate
|
|
||||||
MOZ_ASSERT(track_rate_ == source_->GraphRate());
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
// Always happens before we can DetachMedia()
|
||||||
StreamTime delta = desired_time - played_ticks_;
|
static_cast<VideoSessionConduit *>(conduit_.get())->
|
||||||
|
AttachRenderer(renderer_);
|
||||||
|
|
||||||
// Don't append if we've already provided a frame that supposedly
|
return MediaPipelineReceive::Init();
|
||||||
// goes past the current aDesiredTime Doing so means a negative
|
|
||||||
// delta and thus messes up handling of the graph
|
|
||||||
if (delta > 0) {
|
|
||||||
VideoSegment segment;
|
|
||||||
segment.AppendFrame(image.forget(), delta, IntSize(width_, height_),
|
|
||||||
principal_handle_);
|
|
||||||
// Handle track not actually added yet or removed/finished
|
|
||||||
if (source_->AppendToTrack(track_id_, &segment)) {
|
|
||||||
played_ticks_ = desired_time;
|
|
||||||
} else {
|
|
||||||
MOZ_MTLOG(ML_ERROR, "AppendToTrack failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
|
void MediaPipelineReceiveVideo::SetPrincipalHandle_m(const PrincipalHandle& principal_handle)
|
||||||
|
{
|
||||||
|
listener_->SetPrincipalHandle_m(principal_handle);
|
||||||
|
}
|
||||||
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
|
@ -12,14 +12,8 @@
|
||||||
|
|
||||||
#ifdef USE_FAKE_MEDIA_STREAMS
|
#ifdef USE_FAKE_MEDIA_STREAMS
|
||||||
#include "FakeMediaStreams.h"
|
#include "FakeMediaStreams.h"
|
||||||
#else
|
|
||||||
#include "DOMMediaStream.h"
|
|
||||||
#include "MediaStreamGraph.h"
|
|
||||||
#include "VideoUtils.h"
|
|
||||||
#endif
|
#endif
|
||||||
#include "MediaConduitInterface.h"
|
#include "MediaConduitInterface.h"
|
||||||
#include "MediaPipelineFilter.h"
|
|
||||||
#include "AudioSegment.h"
|
|
||||||
#include "mozilla/ReentrantMonitor.h"
|
#include "mozilla/ReentrantMonitor.h"
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "SrtpFlow.h"
|
#include "SrtpFlow.h"
|
||||||
|
@ -27,17 +21,24 @@
|
||||||
#include "runnable_utils.h"
|
#include "runnable_utils.h"
|
||||||
#include "transportflow.h"
|
#include "transportflow.h"
|
||||||
#include "AudioPacketizer.h"
|
#include "AudioPacketizer.h"
|
||||||
|
#include "StreamBuffer.h"
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
|
||||||
#include "VideoSegment.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
|
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
|
||||||
|
|
||||||
namespace mozilla {
|
class nsIPrincipal;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
class MediaPipelineFilter;
|
||||||
class PeerIdentity;
|
class PeerIdentity;
|
||||||
|
|
||||||
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
|
namespace dom {
|
||||||
|
class MediaStreamTrack;
|
||||||
|
} // namespace dom
|
||||||
|
|
||||||
|
class SourceMediaStream;
|
||||||
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
// A class that represents the pipeline of audio and video
|
// A class that represents the pipeline of audio and video
|
||||||
// The dataflow looks like:
|
// The dataflow looks like:
|
||||||
//
|
//
|
||||||
|
@ -82,34 +83,7 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||||
RefPtr<MediaSessionConduit> conduit,
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
RefPtr<TransportFlow> rtp_transport,
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
RefPtr<TransportFlow> rtcp_transport,
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
nsAutoPtr<MediaPipelineFilter> filter)
|
nsAutoPtr<MediaPipelineFilter> filter);
|
||||||
: direction_(direction),
|
|
||||||
track_id_(track_id),
|
|
||||||
level_(level),
|
|
||||||
conduit_(conduit),
|
|
||||||
rtp_(rtp_transport, rtcp_transport ? RTP : MUX),
|
|
||||||
rtcp_(rtcp_transport ? rtcp_transport : rtp_transport,
|
|
||||||
rtcp_transport ? RTCP : MUX),
|
|
||||||
main_thread_(main_thread),
|
|
||||||
sts_thread_(sts_thread),
|
|
||||||
rtp_packets_sent_(0),
|
|
||||||
rtcp_packets_sent_(0),
|
|
||||||
rtp_packets_received_(0),
|
|
||||||
rtcp_packets_received_(0),
|
|
||||||
rtp_bytes_sent_(0),
|
|
||||||
rtp_bytes_received_(0),
|
|
||||||
pc_(pc),
|
|
||||||
description_(),
|
|
||||||
filter_(filter),
|
|
||||||
rtp_parser_(webrtc::RtpHeaderParser::Create()) {
|
|
||||||
// To indicate rtcp-mux rtcp_transport should be nullptr.
|
|
||||||
// Therefore it's an error to send in the same flow for
|
|
||||||
// both rtp and rtcp.
|
|
||||||
MOZ_ASSERT(rtp_transport != rtcp_transport);
|
|
||||||
|
|
||||||
// PipelineTransport() will access this->sts_thread_; moved here for safety
|
|
||||||
transport_ = new PipelineTransport(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be called on the STS thread. Must be called after ShutdownMedia_m().
|
// Must be called on the STS thread. Must be called after ShutdownMedia_m().
|
||||||
void DetachTransport_s();
|
void DetachTransport_s();
|
||||||
|
@ -301,73 +275,6 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||||
bool IsRtp(const unsigned char *data, size_t len);
|
bool IsRtp(const unsigned char *data, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GenericReceiveListener : public MediaStreamListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericReceiveListener(SourceMediaStream *source, TrackID track_id,
|
|
||||||
TrackRate track_rate, bool queue_track)
|
|
||||||
: source_(source),
|
|
||||||
track_id_(track_id),
|
|
||||||
track_rate_(track_rate),
|
|
||||||
played_ticks_(0),
|
|
||||||
queue_track_(queue_track),
|
|
||||||
principal_handle_(PRINCIPAL_HANDLE_NONE) {}
|
|
||||||
|
|
||||||
virtual ~GenericReceiveListener() {}
|
|
||||||
|
|
||||||
void AddSelf(MediaSegment* segment);
|
|
||||||
|
|
||||||
void SetPlayedTicks(TrackTicks time) {
|
|
||||||
played_ticks_ = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndTrack() {
|
|
||||||
source_->EndTrack(track_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef USE_FAKE_MEDIA_STREAMS
|
|
||||||
// Must be called on the main thread
|
|
||||||
void SetPrincipalHandle_m(const PrincipalHandle& aPrincipal);
|
|
||||||
|
|
||||||
// Must be called on the MediaStreamGraph thread
|
|
||||||
void SetPrincipalHandle_msg(const PrincipalHandle& aPrincipal);
|
|
||||||
#endif // USE_FAKE_MEDIA_STREAMS
|
|
||||||
|
|
||||||
protected:
|
|
||||||
SourceMediaStream *source_;
|
|
||||||
TrackID track_id_;
|
|
||||||
TrackRate track_rate_;
|
|
||||||
TrackTicks played_ticks_;
|
|
||||||
bool queue_track_;
|
|
||||||
PrincipalHandle principal_handle_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TrackAddedCallback {
|
|
||||||
public:
|
|
||||||
virtual void TrackAdded(TrackTicks current_ticks) = 0;
|
|
||||||
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackAddedCallback);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~TrackAddedCallback() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class GenericReceiveListener;
|
|
||||||
|
|
||||||
class GenericReceiveCallback : public TrackAddedCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit GenericReceiveCallback(GenericReceiveListener* listener)
|
|
||||||
: listener_(listener) {}
|
|
||||||
|
|
||||||
void TrackAdded(TrackTicks time) {
|
|
||||||
listener_->SetPlayedTicks(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<GenericReceiveListener> listener_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConduitDeleteEvent: public nsRunnable
|
class ConduitDeleteEvent: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -394,12 +301,7 @@ public:
|
||||||
RefPtr<MediaSessionConduit> conduit,
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
RefPtr<TransportFlow> rtp_transport,
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
RefPtr<TransportFlow> rtcp_transport,
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
nsAutoPtr<MediaPipelineFilter> filter) :
|
nsAutoPtr<MediaPipelineFilter> filter);
|
||||||
MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, track_id, level,
|
|
||||||
conduit, rtp_transport, rtcp_transport, filter),
|
|
||||||
listener_(new PipelineListener(conduit)),
|
|
||||||
domtrack_(domtrack)
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Initialize (stuff here may fail)
|
// Initialize (stuff here may fail)
|
||||||
nsresult Init() override;
|
nsresult Init() override;
|
||||||
|
@ -430,101 +332,8 @@ public:
|
||||||
// multiple tracks of a type in a stream yet). bug 1056650
|
// multiple tracks of a type in a stream yet). bug 1056650
|
||||||
virtual nsresult ReplaceTrack(dom::MediaStreamTrack& domtrack);
|
virtual nsresult ReplaceTrack(dom::MediaStreamTrack& domtrack);
|
||||||
|
|
||||||
|
|
||||||
// Separate class to allow ref counting
|
// Separate class to allow ref counting
|
||||||
class PipelineListener : public MediaStreamTrackDirectListener {
|
class PipelineListener;
|
||||||
friend class MediaPipelineTransmit;
|
|
||||||
public:
|
|
||||||
explicit PipelineListener(const RefPtr<MediaSessionConduit>& conduit)
|
|
||||||
: conduit_(conduit),
|
|
||||||
track_id_(TRACK_INVALID),
|
|
||||||
mMutex("MediaPipelineTransmit::PipelineListener"),
|
|
||||||
track_id_external_(TRACK_INVALID),
|
|
||||||
active_(false),
|
|
||||||
enabled_(false),
|
|
||||||
direct_connect_(false),
|
|
||||||
packetizer_(nullptr)
|
|
||||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
|
||||||
, last_img_(-1)
|
|
||||||
#endif // MOZILLA_INTERNAL_API
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~PipelineListener()
|
|
||||||
{
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
// release conduit on mainthread. Must use forget()!
|
|
||||||
nsresult rv = NS_DispatchToMainThread(new
|
|
||||||
ConduitDeleteEvent(conduit_.forget()));
|
|
||||||
MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
MOZ_CRASH();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conduit_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatches setting the internal TrackID to TRACK_INVALID to the media
|
|
||||||
// graph thread to keep it in sync with other MediaStreamGraph operations
|
|
||||||
// like RemoveListener() and AddListener(). The TrackID will be updated on
|
|
||||||
// the next NewData() callback.
|
|
||||||
void UnsetTrackId(MediaStreamGraphImpl* graph);
|
|
||||||
|
|
||||||
void SetActive(bool active) { active_ = active; }
|
|
||||||
void SetEnabled(bool enabled) { enabled_ = enabled; }
|
|
||||||
|
|
||||||
// Implement MediaStreamTrackListener
|
|
||||||
void NotifyQueuedChanges(MediaStreamGraph* aGraph,
|
|
||||||
StreamTime aTrackOffset,
|
|
||||||
const MediaSegment& aQueuedMedia) override;
|
|
||||||
|
|
||||||
// Implement MediaStreamTrackDirectListener
|
|
||||||
void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
|
|
||||||
StreamTime aTrackOffset,
|
|
||||||
const MediaSegment& aMedia) override;
|
|
||||||
void NotifyDirectListenerInstalled(InstallationResult aResult) override;
|
|
||||||
void NotifyDirectListenerUninstalled() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void UnsetTrackIdImpl() {
|
|
||||||
MutexAutoLock lock(mMutex);
|
|
||||||
track_id_ = track_id_external_ = TRACK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewData(MediaStreamGraph* graph,
|
|
||||||
StreamTime offset,
|
|
||||||
const MediaSegment& media);
|
|
||||||
|
|
||||||
virtual void ProcessAudioChunk(AudioSessionConduit *conduit,
|
|
||||||
TrackRate rate, AudioChunk& chunk);
|
|
||||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
|
||||||
virtual void ProcessVideoChunk(VideoSessionConduit *conduit,
|
|
||||||
VideoChunk& chunk);
|
|
||||||
#endif
|
|
||||||
RefPtr<MediaSessionConduit> conduit_;
|
|
||||||
|
|
||||||
// May be TRACK_INVALID until we see data from the track
|
|
||||||
TrackID track_id_; // this is the current TrackID this listener is attached to
|
|
||||||
Mutex mMutex;
|
|
||||||
// protected by mMutex
|
|
||||||
// May be TRACK_INVALID until we see data from the track
|
|
||||||
TrackID track_id_external_; // this is queried from other threads
|
|
||||||
|
|
||||||
// active is true if there is a transport to send on
|
|
||||||
mozilla::Atomic<bool> active_;
|
|
||||||
// enabled is true if the media access control permits sending
|
|
||||||
// actual content; when false you get black/silence
|
|
||||||
mozilla::Atomic<bool> enabled_;
|
|
||||||
|
|
||||||
// Written and read on the MediaStreamGraph thread
|
|
||||||
bool direct_connect_;
|
|
||||||
|
|
||||||
nsAutoPtr<AudioPacketizer<int16_t, int16_t>> packetizer_;
|
|
||||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
|
||||||
int32_t last_img_; // serial number of last Image
|
|
||||||
#endif // MOZILLA_INTERNAL_API
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<PipelineListener> listener_;
|
RefPtr<PipelineListener> listener_;
|
||||||
|
@ -546,14 +355,7 @@ class MediaPipelineReceive : public MediaPipeline {
|
||||||
RefPtr<MediaSessionConduit> conduit,
|
RefPtr<MediaSessionConduit> conduit,
|
||||||
RefPtr<TransportFlow> rtp_transport,
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
RefPtr<TransportFlow> rtcp_transport,
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
nsAutoPtr<MediaPipelineFilter> filter) :
|
nsAutoPtr<MediaPipelineFilter> filter);
|
||||||
MediaPipeline(pc, RECEIVE, main_thread, sts_thread,
|
|
||||||
track_id, level, conduit, rtp_transport,
|
|
||||||
rtcp_transport, filter),
|
|
||||||
stream_(stream),
|
|
||||||
segments_added_(0) {
|
|
||||||
MOZ_ASSERT(stream_);
|
|
||||||
}
|
|
||||||
|
|
||||||
int segments_added() const { return segments_added_; }
|
int segments_added() const { return segments_added_; }
|
||||||
|
|
||||||
|
@ -563,9 +365,7 @@ class MediaPipelineReceive : public MediaPipeline {
|
||||||
virtual void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) = 0;
|
virtual void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) = 0;
|
||||||
#endif // USE_FAKE_MEDIA_STREAMS
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
protected:
|
protected:
|
||||||
~MediaPipelineReceive() {
|
~MediaPipelineReceive();
|
||||||
MOZ_ASSERT(!stream_); // Check that we have shut down already.
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<SourceMediaStream> stream_;
|
RefPtr<SourceMediaStream> stream_;
|
||||||
int segments_added_;
|
int segments_added_;
|
||||||
|
@ -594,67 +394,20 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive {
|
||||||
RefPtr<TransportFlow> rtp_transport,
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
RefPtr<TransportFlow> rtcp_transport,
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
nsAutoPtr<MediaPipelineFilter> filter,
|
nsAutoPtr<MediaPipelineFilter> filter,
|
||||||
bool queue_track) :
|
bool queue_track);
|
||||||
MediaPipelineReceive(pc, main_thread, sts_thread,
|
|
||||||
stream, media_stream_track_id, level, conduit,
|
|
||||||
rtp_transport, rtcp_transport, filter),
|
|
||||||
listener_(new PipelineListener(stream, numeric_track_id, conduit,
|
|
||||||
queue_track)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void DetachMedia() override {
|
void DetachMedia() override;
|
||||||
ASSERT_ON_THREAD(main_thread_);
|
|
||||||
if (stream_) {
|
|
||||||
stream_->RemoveListener(listener_);
|
|
||||||
stream_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Init() override;
|
nsresult Init() override;
|
||||||
bool IsVideo() const override { return false; }
|
bool IsVideo() const override { return false; }
|
||||||
|
|
||||||
#ifndef USE_FAKE_MEDIA_STREAMS
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) override
|
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) override;
|
||||||
{
|
|
||||||
listener_->SetPrincipalHandle_m(principal_handle);
|
|
||||||
}
|
|
||||||
#endif // USE_FAKE_MEDIA_STREAMS
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Separate class to allow ref counting
|
// Separate class to allow ref counting
|
||||||
class PipelineListener : public GenericReceiveListener {
|
class PipelineListener;
|
||||||
public:
|
|
||||||
PipelineListener(SourceMediaStream * source, TrackID track_id,
|
|
||||||
const RefPtr<MediaSessionConduit>& conduit,
|
|
||||||
bool queue_track);
|
|
||||||
|
|
||||||
~PipelineListener()
|
|
||||||
{
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
// release conduit on mainthread. Must use forget()!
|
|
||||||
nsresult rv = NS_DispatchToMainThread(new
|
|
||||||
ConduitDeleteEvent(conduit_.forget()));
|
|
||||||
MOZ_ASSERT(!NS_FAILED(rv),"Could not dispatch conduit shutdown to main");
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
MOZ_CRASH();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conduit_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement MediaStreamListener
|
|
||||||
void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
|
|
||||||
StreamTime offset,
|
|
||||||
uint32_t events,
|
|
||||||
const MediaSegment& queued_media,
|
|
||||||
MediaStream* input_stream,
|
|
||||||
TrackID input_tid) override {}
|
|
||||||
void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<MediaSessionConduit> conduit_;
|
|
||||||
};
|
|
||||||
|
|
||||||
RefPtr<PipelineListener> listener_;
|
RefPtr<PipelineListener> listener_;
|
||||||
};
|
};
|
||||||
|
@ -680,139 +433,29 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive {
|
||||||
RefPtr<TransportFlow> rtp_transport,
|
RefPtr<TransportFlow> rtp_transport,
|
||||||
RefPtr<TransportFlow> rtcp_transport,
|
RefPtr<TransportFlow> rtcp_transport,
|
||||||
nsAutoPtr<MediaPipelineFilter> filter,
|
nsAutoPtr<MediaPipelineFilter> filter,
|
||||||
bool queue_track) :
|
bool queue_track);
|
||||||
MediaPipelineReceive(pc, main_thread, sts_thread,
|
|
||||||
stream, media_stream_track_id, level, conduit,
|
|
||||||
rtp_transport, rtcp_transport, filter),
|
|
||||||
renderer_(new PipelineRenderer(this)),
|
|
||||||
listener_(new PipelineListener(stream, numeric_track_id, queue_track)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called on the main thread.
|
// Called on the main thread.
|
||||||
void DetachMedia() override {
|
void DetachMedia() override;
|
||||||
ASSERT_ON_THREAD(main_thread_);
|
|
||||||
|
|
||||||
listener_->EndTrack();
|
|
||||||
// stop generating video and thus stop invoking the PipelineRenderer
|
|
||||||
// and PipelineListener - the renderer has a raw ptr to the Pipeline to
|
|
||||||
// avoid cycles, and the render callbacks are invoked from a different
|
|
||||||
// thread so simple null-checks would cause TSAN bugs without locks.
|
|
||||||
static_cast<VideoSessionConduit*>(conduit_.get())->DetachRenderer();
|
|
||||||
if (stream_) {
|
|
||||||
stream_->RemoveListener(listener_);
|
|
||||||
stream_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Init() override;
|
nsresult Init() override;
|
||||||
bool IsVideo() const override { return true; }
|
bool IsVideo() const override { return true; }
|
||||||
|
|
||||||
#ifndef USE_FAKE_MEDIA_STREAMS
|
#ifndef USE_FAKE_MEDIA_STREAMS
|
||||||
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) override
|
void SetPrincipalHandle_m(const PrincipalHandle& principal_handle) override;
|
||||||
{
|
|
||||||
listener_->SetPrincipalHandle_m(principal_handle);
|
|
||||||
}
|
|
||||||
#endif // USE_FAKE_MEDIA_STREAMS
|
#endif // USE_FAKE_MEDIA_STREAMS
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class PipelineRenderer : public VideoRenderer {
|
class PipelineRenderer;
|
||||||
public:
|
friend class PipelineRenderer;
|
||||||
explicit PipelineRenderer(MediaPipelineReceiveVideo *pipeline) :
|
|
||||||
pipeline_(pipeline) {}
|
|
||||||
|
|
||||||
void Detach() { pipeline_ = nullptr; }
|
|
||||||
|
|
||||||
// Implement VideoRenderer
|
|
||||||
void FrameSizeChange(unsigned int width,
|
|
||||||
unsigned int height,
|
|
||||||
unsigned int number_of_streams) override {
|
|
||||||
pipeline_->listener_->FrameSizeChange(width, height, number_of_streams);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderVideoFrame(const unsigned char* buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
uint32_t time_stamp,
|
|
||||||
int64_t render_time,
|
|
||||||
const ImageHandle& handle) override {
|
|
||||||
pipeline_->listener_->RenderVideoFrame(buffer, buffer_size,
|
|
||||||
time_stamp, render_time,
|
|
||||||
handle.GetImage());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderVideoFrame(const unsigned char* buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
uint32_t y_stride,
|
|
||||||
uint32_t cbcr_stride,
|
|
||||||
uint32_t time_stamp,
|
|
||||||
int64_t render_time,
|
|
||||||
const ImageHandle& handle) override {
|
|
||||||
pipeline_->listener_->RenderVideoFrame(buffer, buffer_size,
|
|
||||||
y_stride, cbcr_stride,
|
|
||||||
time_stamp, render_time,
|
|
||||||
handle.GetImage());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MediaPipelineReceiveVideo *pipeline_; // Raw pointer to avoid cycles
|
|
||||||
};
|
|
||||||
|
|
||||||
// Separate class to allow ref counting
|
// Separate class to allow ref counting
|
||||||
class PipelineListener : public GenericReceiveListener {
|
class PipelineListener;
|
||||||
public:
|
|
||||||
PipelineListener(SourceMediaStream * source, TrackID track_id,
|
|
||||||
bool queue_track);
|
|
||||||
|
|
||||||
// Implement MediaStreamListener
|
|
||||||
void NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid,
|
|
||||||
StreamTime offset,
|
|
||||||
uint32_t events,
|
|
||||||
const MediaSegment& queued_media,
|
|
||||||
MediaStream* input_stream,
|
|
||||||
TrackID input_tid) override {}
|
|
||||||
void NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) override;
|
|
||||||
|
|
||||||
// Accessors for external writes from the renderer
|
|
||||||
void FrameSizeChange(unsigned int width,
|
|
||||||
unsigned int height,
|
|
||||||
unsigned int number_of_streams) {
|
|
||||||
ReentrantMonitorAutoEnter enter(monitor_);
|
|
||||||
|
|
||||||
width_ = width;
|
|
||||||
height_ = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderVideoFrame(const unsigned char* buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
uint32_t time_stamp,
|
|
||||||
int64_t render_time,
|
|
||||||
const RefPtr<layers::Image>& video_image);
|
|
||||||
void RenderVideoFrame(const unsigned char* buffer,
|
|
||||||
size_t buffer_size,
|
|
||||||
uint32_t y_stride,
|
|
||||||
uint32_t cbcr_stride,
|
|
||||||
uint32_t time_stamp,
|
|
||||||
int64_t render_time,
|
|
||||||
const RefPtr<layers::Image>& video_image);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int width_;
|
|
||||||
int height_;
|
|
||||||
#if defined(MOZILLA_INTERNAL_API)
|
|
||||||
RefPtr<layers::ImageContainer> image_container_;
|
|
||||||
RefPtr<layers::Image> image_;
|
|
||||||
#endif
|
|
||||||
mozilla::ReentrantMonitor monitor_; // Monitor for processing WebRTC frames.
|
|
||||||
// Protects image_ against:
|
|
||||||
// - Writing from the GIPS thread
|
|
||||||
// - Reading from the MSG thread
|
|
||||||
};
|
|
||||||
|
|
||||||
friend class PipelineRenderer;
|
|
||||||
|
|
||||||
RefPtr<PipelineRenderer> renderer_;
|
RefPtr<PipelineRenderer> renderer_;
|
||||||
RefPtr<PipelineListener> listener_;
|
RefPtr<PipelineListener> listener_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // end namespace
|
} // namespace mozilla
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "PeerConnectionImpl.h"
|
#include "PeerConnectionImpl.h"
|
||||||
#include "PeerConnectionMedia.h"
|
#include "PeerConnectionMedia.h"
|
||||||
#include "MediaPipelineFactory.h"
|
#include "MediaPipelineFactory.h"
|
||||||
|
#include "MediaPipelineFilter.h"
|
||||||
#include "transportflow.h"
|
#include "transportflow.h"
|
||||||
#include "transportlayer.h"
|
#include "transportlayer.h"
|
||||||
#include "transportlayerdtls.h"
|
#include "transportlayerdtls.h"
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
#include "FakeMediaStreams.h"
|
#include "FakeMediaStreams.h"
|
||||||
#else
|
#else
|
||||||
#include "MediaSegment.h"
|
#include "MediaSegment.h"
|
||||||
|
#ifdef MOZILLA_INTERNAL_API
|
||||||
|
#include "MediaStreamGraph.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nsNetCID.h"
|
#include "nsNetCID.h"
|
||||||
|
|
Загрузка…
Ссылка в новой задаче