Bug 1170958 - Allow MediaInputPort to lock to a specific input track. r=roc

Locking to specific tracks lets us dynamically remove and add single
tracks to a ProcessedMediaStream.

--HG--
extra : commitid : GPSNwBVyD4j
extra : rebase_source : 0b1b79077f95bbefc8c71de551c5e3483a7d6ac0
This commit is contained in:
Andreas Pehrson 2015-09-30 09:31:53 +08:00
Родитель 2802ee3e88
Коммит 53a6c38d0d
15 изменённых файлов: 110 добавлений и 28 удалений

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

@ -29,8 +29,8 @@ namespace mozilla
// We are mixing to mono until PeerConnection can accept stereo
static const uint32_t MONO = 1;
AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper)
: ProcessedMediaStream(aWrapper), mTrackCreated(false)
AudioCaptureStream::AudioCaptureStream(DOMMediaStream* aWrapper, TrackID aTrackId)
: ProcessedMediaStream(aWrapper), mTrackId(aTrackId), mTrackCreated(false)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(AudioCaptureStream);
@ -48,14 +48,14 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
uint32_t aFlags)
{
uint32_t inputCount = mInputs.Length();
StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK);
StreamBuffer::Track* track = EnsureTrack(mTrackId);
// Notify the DOM everything is in order.
if (!mTrackCreated) {
for (uint32_t i = 0; i < mListeners.Length(); i++) {
MediaStreamListener* l = mListeners[i];
AudioSegment tmp;
l->NotifyQueuedTrackChanges(
Graph(), AUDIO_TRACK, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp);
Graph(), mTrackId, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp);
l->NotifyFinishedTrackCreation(Graph());
}
mTrackCreated = true;
@ -127,6 +127,6 @@ AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer,
}
// Now we have mixed data, simply append it to out track.
EnsureTrack(AUDIO_TRACK)->Get<AudioSegment>()->AppendAndConsumeChunk(&chunk);
EnsureTrack(mTrackId)->Get<AudioSegment>()->AppendAndConsumeChunk(&chunk);
}
}

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

@ -8,6 +8,7 @@
#include "MediaStreamGraph.h"
#include "AudioMixer.h"
#include "StreamBuffer.h"
#include <algorithm>
namespace mozilla
@ -22,17 +23,17 @@ class AudioCaptureStream : public ProcessedMediaStream,
public MixerCallbackReceiver
{
public:
explicit AudioCaptureStream(DOMMediaStream* aWrapper);
explicit AudioCaptureStream(DOMMediaStream* aWrapper, TrackID aTrackId);
virtual ~AudioCaptureStream();
void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) override;
protected:
enum { AUDIO_TRACK = 1 };
void MixerCallback(AudioDataValue* aMixedBuffer, AudioSampleFormat aFormat,
uint32_t aChannels, uint32_t aFrames,
uint32_t aSampleRate) override;
AudioMixer mMixer;
TrackID mTrackId;
bool mTrackCreated;
};
}

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

@ -308,7 +308,10 @@ DOMMediaStream::InitAudioCaptureStream(nsIDOMWindow* aWindow,
{
mWindow = aWindow;
InitStreamCommon(aGraph->CreateAudioCaptureStream(this));
const TrackID AUDIO_TRACK = 1;
InitStreamCommon(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK));
CreateDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO);
}
void

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

@ -540,8 +540,7 @@ private:
mTrackUnionStream->SetAutofinish(true);
// Bind this Track Union Stream with Source Media.
mInputPort = mTrackUnionStream->AllocateInputPort(mRecorder->GetSourceMediaStream(),
0);
mInputPort = mTrackUnionStream->AllocateInputPort(mRecorder->GetSourceMediaStream());
DOMMediaStream* domStream = mRecorder->Stream();
if (domStream) {
@ -800,7 +799,7 @@ MediaRecorder::MediaRecorder(AudioNode& aSrcAudioNode,
AudioNodeStream* ns = aSrcAudioNode.GetStream();
if (ns) {
mInputPort = mPipeStream->AllocateInputPort(aSrcAudioNode.GetStream(),
0, aSrcOutput);
TRACK_ANY, 0, aSrcOutput);
}
}
mAudioNode = &aSrcAudioNode;

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

@ -2430,8 +2430,39 @@ MediaInputPort::SetGraphImpl(MediaStreamGraphImpl* aGraph)
mGraph = aGraph;
}
void
MediaInputPort::BlockTrackIdImpl(TrackID aTrackId)
{
mBlockedTracks.AppendElement(aTrackId);
}
void
MediaInputPort::BlockTrackId(TrackID aTrackId)
{
class Message : public ControlMessage {
public:
explicit Message(MediaInputPort* aPort, TrackID aTrackId)
: ControlMessage(aPort->GetDestination()),
mPort(aPort), mTrackId(aTrackId) {}
virtual void Run()
{
mPort->BlockTrackIdImpl(mTrackId);
}
virtual void RunDuringShutdown()
{
Run();
}
nsRefPtr<MediaInputPort> mPort;
TrackID mTrackId;
};
MOZ_ASSERT(aTrackId != TRACK_NONE && aTrackId != TRACK_INVALID && aTrackId != TRACK_ANY,
"Only explicit TrackID is allowed");
GraphImpl()->AppendMessage(new Message(this, aTrackId));
}
already_AddRefed<MediaInputPort>
ProcessedMediaStream::AllocateInputPort(MediaStream* aStream,
ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, TrackID aTrackID,
uint16_t aInputNumber, uint16_t aOutputNumber)
{
// This method creates two references to the MediaInputPort: one for
@ -2454,7 +2485,10 @@ ProcessedMediaStream::AllocateInputPort(MediaStream* aStream,
}
nsRefPtr<MediaInputPort> mPort;
};
nsRefPtr<MediaInputPort> port = new MediaInputPort(aStream, this,
MOZ_ASSERT(aTrackID != TRACK_NONE && aTrackID != TRACK_INVALID,
"Only TRACK_ANY and explicit ID are allowed");
nsRefPtr<MediaInputPort> port = new MediaInputPort(aStream, aTrackID, this,
aInputNumber, aOutputNumber);
port->SetGraphImpl(GraphImpl());
GraphImpl()->AppendMessage(new Message(port));
@ -2765,9 +2799,10 @@ MediaStreamGraph::CreateTrackUnionStream(DOMMediaStream* aWrapper)
}
ProcessedMediaStream*
MediaStreamGraph::CreateAudioCaptureStream(DOMMediaStream* aWrapper)
MediaStreamGraph::CreateAudioCaptureStream(DOMMediaStream* aWrapper,
TrackID aTrackId)
{
AudioCaptureStream* stream = new AudioCaptureStream(aWrapper);
AudioCaptureStream* stream = new AudioCaptureStream(aWrapper, aTrackId);
AddStream(stream);
return stream;
}

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

@ -919,6 +919,10 @@ protected:
* We make these refcounted so that stream-related messages with MediaInputPort*
* pointers can be sent to the main thread safely.
*
* A port can be locked to a specific track in the source stream, in which case
* only this track will be forwarded to the destination stream. TRACK_ANY
* can used to signal that all tracks shall be forwarded.
*
* When a port's source or destination stream dies, the stream's DestroyImpl
* calls MediaInputPort::Disconnect to disconnect the port from
* the source and destination streams.
@ -934,9 +938,11 @@ class MediaInputPort final
{
private:
// Do not call this constructor directly. Instead call aDest->AllocateInputPort.
MediaInputPort(MediaStream* aSource, ProcessedMediaStream* aDest,
MediaInputPort(MediaStream* aSource, TrackID& aSourceTrack,
ProcessedMediaStream* aDest,
uint16_t aInputNumber, uint16_t aOutputNumber)
: mSource(aSource)
, mSourceTrack(aSourceTrack)
, mDest(aDest)
, mInputNumber(aInputNumber)
, mOutputNumber(aOutputNumber)
@ -969,8 +975,22 @@ public:
// Any thread
MediaStream* GetSource() { return mSource; }
TrackID GetSourceTrackId() { return mSourceTrack; }
ProcessedMediaStream* GetDestination() { return mDest; }
// Block aTrackId in the port. Consumers will interpret this track as ended.
void BlockTrackId(TrackID aTrackId);
private:
void BlockTrackIdImpl(TrackID aTrackId);
public:
// Returns true if aTrackId has not been blocked and this port has not
// been locked to another track.
bool PassTrackThrough(TrackID aTrackId) {
return !mBlockedTracks.Contains(aTrackId) &&
(mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
}
uint16_t InputNumber() const { return mInputNumber; }
uint16_t OutputNumber() const { return mOutputNumber; }
@ -1016,11 +1036,13 @@ private:
friend class ProcessedMediaStream;
// Never modified after Init()
MediaStream* mSource;
TrackID mSourceTrack;
ProcessedMediaStream* mDest;
// The input and output numbers are optional, and are currently only used by
// Web Audio.
const uint16_t mInputNumber;
const uint16_t mOutputNumber;
nsTArray<TrackID> mBlockedTracks;
// Our media stream graph
MediaStreamGraphImpl* mGraph;
@ -1042,8 +1064,13 @@ public:
/**
* Allocates a new input port attached to source aStream.
* This stream can be removed by calling MediaInputPort::Remove().
* The input port is tied to aTrackID in the source stream.
* aTrackID can be set to TRACK_ANY to automatically forward all tracks from
* aStream. To end a track in the destination stream forwarded with TRACK_ANY,
* it can be blocked in the input port through MediaInputPort::BlockTrackId().
*/
already_AddRefed<MediaInputPort> AllocateInputPort(MediaStream* aStream,
TrackID aTrackID = TRACK_ANY,
uint16_t aInputNumber = 0,
uint16_t aOutputNumber = 0);
/**
@ -1190,7 +1217,8 @@ public:
/**
* Create a stream that will mix all its audio input.
*/
ProcessedMediaStream* CreateAudioCaptureStream(DOMMediaStream* aWrapper);
ProcessedMediaStream* CreateAudioCaptureStream(DOMMediaStream* aWrapper,
TrackID aTrackId);
enum {
ADD_STREAM_SUSPENDED = 0x01

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

@ -19,6 +19,7 @@ namespace mozilla {
typedef int32_t TrackID;
const TrackID TRACK_NONE = 0;
const TrackID TRACK_INVALID = -1;
const TrackID TRACK_ANY = -2;
inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
TrackRate aInRate,

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

@ -96,18 +96,19 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) {
bool trackFinished;
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
if (!outputTrack || outputTrack->IsEnded()) {
found = true;
if (!outputTrack || outputTrack->IsEnded() ||
!mInputs[i]->PassTrackThrough(tracks->GetID())) {
trackFinished = true;
} else {
CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished);
}
mappedTracksFinished[j] = trackFinished;
mappedTracksWithMatchingInputTracks[j] = true;
found = true;
break;
}
}
if (!found) {
if (!found && mInputs[i]->PassTrackThrough(tracks->GetID())) {
bool trackFinished = false;
trackAdded = true;
uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom);
@ -191,7 +192,8 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(Graph(), id, outputStart,
MediaStreamListener::TRACK_EVENT_CREATED,
*segment);
*segment,
aPort->GetSource(), aTrack->GetID());
}
segment->AppendNullData(outputStart);
StreamBuffer::Track* track =
@ -223,7 +225,9 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
segment = outputTrack->GetSegment()->CreateEmptyClone();
l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(), offset,
MediaStreamListener::TRACK_EVENT_ENDED,
*segment);
*segment,
mTrackMap[aIndex].mInputPort->GetSource(),
mTrackMap[aIndex].mInputTrackID);
}
outputTrack->SetEnded();
}

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

@ -225,7 +225,8 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
MOZ_ASSERT(aInput <= UINT16_MAX, "Unexpected large input port number");
MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
input->mStreamPort = destinationStream->
AllocateInputPort(mStream, static_cast<uint16_t>(aInput),
AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK,
static_cast<uint16_t>(aInput),
static_cast<uint16_t>(aOutput));
}
aDestination.NotifyInputsChanged();
@ -267,7 +268,8 @@ AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
// Setup our stream as an input to the AudioParam's stream
MOZ_ASSERT(aOutput <= UINT16_MAX, "Unexpected large output port number");
input->mStreamPort =
ps->AllocateInputPort(mStream, 0, static_cast<uint16_t>(aOutput));
ps->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK,
0, static_cast<uint16_t>(aOutput));
}
}

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

@ -142,6 +142,10 @@ AudioNodeExternalInputStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
for (StreamBuffer::TrackIter tracks(source->mBuffer, MediaSegment::AUDIO);
!tracks.IsEnded(); tracks.Next()) {
const StreamBuffer::Track& inputTrack = *tracks;
if (!mInputs[0]->PassTrackThrough(tracks->GetID())) {
continue;
}
const AudioSegment& inputSegment =
*static_cast<AudioSegment*>(inputTrack.GetSegment());
if (inputSegment.IsNull()) {

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

@ -114,7 +114,8 @@ AudioParam::Stream()
// Setup the AudioParam's stream as an input to the owner AudioNode's stream
AudioNodeStream* nodeStream = mNode->GetStream();
if (nodeStream) {
mNodeStreamPort = nodeStream->AllocateInputPort(mStream);
mNodeStreamPort =
nodeStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
}
// Send the stream to the timeline on the MSG side.

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

@ -41,7 +41,7 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
AudioNodeEngine* engine = new AudioNodeEngine(this);
mStream = AudioNodeStream::Create(aContext, engine,
AudioNodeStream::EXTERNAL_OUTPUT);
mPort = outputStream->AllocateInputPort(mStream);
mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc();
if (doc) {

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

@ -8,6 +8,7 @@
#include "mozilla/dom/MediaStreamAudioSourceNodeBinding.h"
#include "AudioNodeEngine.h"
#include "AudioNodeExternalInputStream.h"
#include "AudioStreamTrack.h"
#include "nsIDocument.h"
#include "mozilla/CORSMode.h"

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

@ -44,7 +44,8 @@ class MediaStreamAudioSourceNode : public AudioNode,
public DOMMediaStream::PrincipalChangeObserver
{
public:
MediaStreamAudioSourceNode(AudioContext* aContext, DOMMediaStream* aMediaStream);
MediaStreamAudioSourceNode(AudioContext* aContext,
DOMMediaStream* aMediaStream);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioSourceNode, AudioNode)

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

@ -21,6 +21,8 @@
extern PRLogModuleInfo* GetSpeechSynthLog();
#define LOG(type, msg) MOZ_LOG(GetSpeechSynthLog(), type, msg)
#define AUDIO_TRACK 1
namespace mozilla {
namespace dom {
@ -193,7 +195,7 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
mChannels = aChannels;
AudioSegment* segment = new AudioSegment();
mStream->AddAudioTrack(1, aRate, 0, segment);
mStream->AddAudioTrack(AUDIO_TRACK, aRate, 0, segment);
mStream->AddAudioOutput(this);
mStream->SetAudioOutputVolume(this, mVolume);