StreamBuffer::Track* AudioNodeStream::EnsureTrack() { StreamBuffer::Track* track = mBuffer.FindTrack(AUDIO_NODE_STREAM_TRACK_ID); if (!track) { nsAutoPtr<MediaSegment> segment(new AudioSegment()); for (uint32_t j = 0; j < mListeners.Length(); ++j) { MediaStreamListener* l = mListeners[j]; l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0, MediaStreamListener::TRACK_EVENT_CREATED, *segment); } track = &mBuffer.AddTrack(AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0, segment.forget()); } return track; }
void AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream, double aStreamTime) { StreamTime streamTime = std::max<MediaTime>(0, SecondsToMediaTime(aStreamTime)); GraphTime graphTime = aRelativeToStream->StreamTimeToGraphTime(streamTime); StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime); TrackTicks ticks = TimeToTicksRoundDown(IdealAudioRate(), thisStreamTime); mEngine->SetStreamTimeParameter(aIndex, ticks); }
// The MediaStreamGraph guarantees that this is actually one block, for // AudioNodeStreams. void AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo) { if (mMarkAsFinishedAfterThisBlock) { // This stream was finished the last time that we looked at it, and all // of the depending streams have finished their output as well, so now // it's time to mark this stream as finished. FinishOutput(); } StreamBuffer::Track* track = EnsureTrack(); AudioSegment* segment = track->Get<AudioSegment>(); mLastChunks.SetLength(1); mLastChunks[0].SetNull(0); if (mInCycle) { // XXX DelayNode not supported yet so just produce silence mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE); } else { // We need to generate at least one input uint16_t maxInputs = std::max(uint16_t(1), mEngine->InputCount()); OutputChunks inputChunks; inputChunks.SetLength(maxInputs); for (uint16_t i = 0; i < maxInputs; ++i) { ObtainInputBlock(inputChunks[i], i); } bool finished = false; if (maxInputs <= 1 && mEngine->OutputCount() <= 1) { mEngine->ProduceAudioBlock(this, inputChunks[0], &mLastChunks[0], &finished); } else { mEngine->ProduceAudioBlocksOnPorts(this, inputChunks, mLastChunks, &finished); } if (finished) { mMarkAsFinishedAfterThisBlock = true; } } if (mKind == MediaStreamGraph::EXTERNAL_STREAM) { segment->AppendAndConsumeChunk(&mLastChunks[0]); } else { segment->AppendNullData(mLastChunks[0].GetDuration()); } for (uint32_t j = 0; j < mListeners.Length(); ++j) { MediaStreamListener* l = mListeners[j]; AudioChunk copyChunk = mLastChunks[0]; AudioSegment tmpSegment; tmpSegment.AppendAndConsumeChunk(©Chunk); l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), segment->GetDuration(), 0, tmpSegment); } }
static int64_t Convert(double aTime, void* aClosure) { TrackRate sampleRate = IdealAudioRate(); ConvertTimeToTickHelper* This = static_cast<ConvertTimeToTickHelper*> (aClosure); TrackTicks tick = This->mSourceStream->GetCurrentPosition(); StreamTime streamTime = TicksToTimeRoundDown(sampleRate, tick); GraphTime graphTime = This->mSourceStream->StreamTimeToGraphTime(streamTime); StreamTime destinationStreamTime = This->mDestinationStream->GraphTimeToStreamTime(graphTime); return TimeToTicksRoundDown(sampleRate, destinationStreamTime + SecondsToMediaTime(aTime)); }
void AudioNodeStream::FinishOutput() { if (IsFinishedOnGraphThread()) { return; } StreamBuffer::Track* track = EnsureTrack(); track->SetEnded(); FinishOnGraphThread(); for (uint32_t j = 0; j < mListeners.Length(); ++j) { MediaStreamListener* l = mListeners[j]; AudioSegment emptySegment; l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), track->GetSegment()->GetDuration(), MediaStreamListener::TRACK_EVENT_ENDED, emptySegment); } }
// The MediaStreamGraph guarantees that this is actually one block, for // AudioNodeStreams. void AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo) { StreamBuffer::Track* track = EnsureTrack(); AudioChunk outputChunk; AudioSegment* segment = track->Get<AudioSegment>(); outputChunk.SetNull(0); if (mInCycle) { // XXX DelayNode not supported yet so just produce silence outputChunk.SetNull(WEBAUDIO_BLOCK_SIZE); } else { AudioChunk tmpChunk; AudioChunk* inputChunk = ObtainInputBlock(&tmpChunk); bool finished = false; mEngine->ProduceAudioBlock(this, *inputChunk, &outputChunk, &finished); if (finished) { FinishOutput(); } } mLastChunk = outputChunk; if (mKind == MediaStreamGraph::EXTERNAL_STREAM) { segment->AppendAndConsumeChunk(&outputChunk); } else { segment->AppendNullData(outputChunk.GetDuration()); } for (uint32_t j = 0; j < mListeners.Length(); ++j) { MediaStreamListener* l = mListeners[j]; AudioChunk copyChunk = outputChunk; AudioSegment tmpSegment; tmpSegment.AppendAndConsumeChunk(©Chunk); l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), segment->GetDuration(), 0, tmpSegment); } }