// aTime is the time in ms the samples were inserted into MediaStreamGraph nsresult AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames) { MonitorAutoLock mon(mMonitor); if (mState == ERRORED) { return NS_ERROR_FAILURE; } NS_ASSERTION(mState == INITIALIZED || mState == STARTED || mState == RUNNING, "Stream write in unexpected state."); // Downmix to Stereo. if (mChannels > 2 && mChannels <= 8) { DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames); } else if (mChannels > 8) { return NS_ERROR_FAILURE; } if (mChannels >= 2 && mIsMonoAudioEnabled) { DownmixStereoToMono(const_cast<AudioDataValue*> (aBuf), aFrames); } const uint8_t* src = reinterpret_cast<const uint8_t*>(aBuf); uint32_t bytesToCopy = FramesToBytes(aFrames); while (bytesToCopy > 0) { uint32_t available = std::min(bytesToCopy, mBuffer.Available()); MOZ_ASSERT(available % mBytesPerFrame == 0, "Must copy complete frames."); mBuffer.AppendElements(src, available); src += available; bytesToCopy -= available; if (bytesToCopy > 0) { // If we are not playing, but our buffer is full, start playing to make // room for soon-to-be-decoded data. if (mState != STARTED && mState != RUNNING) { MOZ_LOG(gAudioStreamLog, LogLevel::Warning, ("Starting stream %p in Write (%u waiting)", this, bytesToCopy)); StartUnlocked(); if (mState == ERRORED) { return NS_ERROR_FAILURE; } } MOZ_LOG(gAudioStreamLog, LogLevel::Warning, ("Stream %p waiting in Write() (%u waiting)", this, bytesToCopy)); mon.Wait(); } } mWritten += aFrames; return NS_OK; }
bool AudioStream::Downmix(Chunk* aChunk) { if (aChunk->Rate() != mInRate) { LOGW("mismatched sample %u, mInRate=%u", aChunk->Rate(), mInRate); return false; } if (aChunk->Channels() > 8) { return false; } if (aChunk->Channels() > 2 && aChunk->Channels() <= 8) { DownmixAudioToStereo(aChunk->GetWritable(), aChunk->Channels(), aChunk->Frames()); } if (aChunk->Channels() >= 2 && mIsMonoAudioEnabled) { DownmixStereoToMono(aChunk->GetWritable(), aChunk->Frames()); } return true; }