diff --git a/content/media/webrtc/MediaEngineDefault.cpp b/content/media/webrtc/MediaEngineDefault.cpp index 96bb84a53014..6b48ac172cc0 100644 --- a/content/media/webrtc/MediaEngineDefault.cpp +++ b/content/media/webrtc/MediaEngineDefault.cpp @@ -22,7 +22,7 @@ #define VIDEO_RATE USECS_PER_S #define AUDIO_RATE 16000 - +#define AUDIO_FRAME_LENGTH ((AUDIO_RATE * MediaEngine::DEFAULT_AUDIO_TIMER_MS) / 1000) namespace mozilla { NS_IMPL_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback) @@ -258,6 +258,51 @@ MediaEngineDefaultVideoSource::NotifyPull(MediaStreamGraph* aGraph, } } +// generate 1k sine wave per second +class SineWaveGenerator : public RefCounted +{ +public: + static const int bytesPerSample = 2; + static const int millisecondsPerSecond = 1000; + static const int frequency = 1000; + + SineWaveGenerator(int aSampleRate) : + mTotalLength(aSampleRate / frequency), + mReadLength(0) { + MOZ_ASSERT(mTotalLength * frequency == aSampleRate); + mAudioBuffer = new int16_t[mTotalLength]; + for(int i = 0; i < mTotalLength; i++) { + // Set volume to -20db. It's from 32768.0 * 10^(-20/20) = 3276.8 + mAudioBuffer[i] = (3276.8f * sin(2 * M_PI * i / mTotalLength)); + } + } + + void generate(int16_t* aBuffer, int16_t aLengthInSamples) { + int16_t remaining = aLengthInSamples; + + while (remaining) { + int16_t processSamples = 0; + + if (mTotalLength - mReadLength >= remaining) { + processSamples = remaining; + } else { + processSamples = mTotalLength - mReadLength; + } + memcpy(aBuffer, mAudioBuffer + mReadLength, processSamples * bytesPerSample); + aBuffer += processSamples; + mReadLength += processSamples; + remaining -= processSamples; + if (mReadLength == mTotalLength) { + mReadLength = 0; + } + } + } + +private: + nsAutoArrayPtr mAudioBuffer; + int16_t mTotalLength; + int16_t mReadLength; +}; /** * Default audio source. @@ -295,6 +340,8 @@ MediaEngineDefaultAudioSource::Allocate(const MediaEnginePrefs &aPrefs) } mState = kAllocated; + // generate 1Khz sine wave + mSineGenerator = new SineWaveGenerator(AUDIO_RATE); return NS_OK; } @@ -334,7 +381,7 @@ MediaEngineDefaultAudioSource::Start(SourceMediaStream* aStream, TrackID aID) // 1 Audio frame per 10ms mTimer->InitWithCallback(this, MediaEngine::DEFAULT_AUDIO_TIMER_MS, - nsITimer::TYPE_REPEATING_SLACK); + nsITimer::TYPE_REPEATING_PRECISE); mState = kStarted; return NS_OK; @@ -370,10 +417,13 @@ NS_IMETHODIMP MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer) { AudioSegment segment; + nsRefPtr buffer = SharedBuffer::Create(AUDIO_FRAME_LENGTH * sizeof(int16_t)); + int16_t* dest = static_cast(buffer->Data()); - // Notify timer is set every DEFAULT_AUDIO_TIMER_MS milliseconds. - segment.InsertNullDataAtStart((AUDIO_RATE * MediaEngine::DEFAULT_AUDIO_TIMER_MS) / 1000); - + mSineGenerator->generate(dest, AUDIO_FRAME_LENGTH); + nsAutoTArray channels; + channels.AppendElement(dest); + segment.AppendFrames(buffer.forget(), channels, AUDIO_FRAME_LENGTH); mSource->AppendToTrack(mTrackID, &segment); return NS_OK; diff --git a/content/media/webrtc/MediaEngineDefault.h b/content/media/webrtc/MediaEngineDefault.h index e69aba111c79..ef19c6ad0099 100644 --- a/content/media/webrtc/MediaEngineDefault.h +++ b/content/media/webrtc/MediaEngineDefault.h @@ -81,6 +81,8 @@ protected: int mCr; }; +class SineWaveGenerator; + class MediaEngineDefaultAudioSource : public nsITimerCallback, public MediaEngineAudioSource { @@ -117,6 +119,7 @@ protected: nsCOMPtr mTimer; SourceMediaStream* mSource; + nsRefPtr mSineGenerator; };