Bug 1392837 - Support multichannel audio input on gUM. r?padenot draft
authorAlex Chronopoulos <achronop@gmail.com>
Mon, 04 Sep 2017 17:26:03 +0300
changeset 659038 cb58b478b4f63326a324c718c2ee55a8be78c1d5
parent 658813 1401e3eec44df87963d3af329ef8a4183ab0483f
child 729863 e72f77b00633b0d8aeecb275b15f6ffc7bba37e2
push id77993
push userachronop@gmail.com
push dateTue, 05 Sep 2017 11:40:57 +0000
reviewerspadenot
bugs1392837
milestone57.0a1
Bug 1392837 - Support multichannel audio input on gUM. r?padenot MozReview-Commit-ID: FKCIAo4a8jy
dom/media/GraphDriver.cpp
dom/media/webrtc/MediaEngineWebRTC.h
dom/media/webrtc/MediaEngineWebRTCAudio.cpp
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -667,17 +667,17 @@ AudioCallbackDriver::Init()
   input.channels = mInputChannels;
   input.layout = CUBEB_LAYOUT_UNDEFINED;
 
 #ifdef MOZ_WEBRTC
   if (mGraphImpl->mInputWanted) {
     StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
     uint32_t userChannels = 0;
     AudioInputCubeb::GetUserChannelCount(mGraphImpl->mInputDeviceID, userChannels);
-    input.channels = mInputChannels = userChannels;
+    input.channels = mInputChannels = std::min<uint32_t>(8, userChannels);
   }
 #endif
 
   cubeb_stream* stream = nullptr;
   CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;
   // We have to translate the deviceID values to cubeb devid's since those can be
   // freed whenever enumerate is called.
   {
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -640,16 +640,18 @@ private:
   nsTArray<int16_t> mInputBuffer;
   // mSkipProcessing is true if none of the processing passes are enabled,
   // because of prefs or constraints. This allows simply copying the audio into
   // the MSG, skipping resampling and the whole webrtc.org code.
   bool mSkipProcessing;
 
   // To only update microphone when needed, we keep track of previous settings.
   MediaEnginePrefs mLastPrefs;
+
+  AlignedShortBuffer mInputDownmixBuffer;
 };
 
 class MediaEngineWebRTC : public MediaEngine
 {
   typedef MediaEngine Super;
 public:
   explicit MediaEngineWebRTC(MediaEnginePrefs& aPrefs);
 
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -201,16 +201,17 @@ MediaEngineWebRTCMicrophoneSource::Media
   , mTrackID(TRACK_NONE)
   , mStarted(false)
   , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE)
   , mTotalFrames(0)
   , mLastLogFrames(0)
   , mPlayoutDelay(0)
   , mNullTransport(nullptr)
   , mSkipProcessing(false)
+  , mInputDownmixBuffer(MAX_SAMPLING_FREQ * MAX_CHANNELS / 100)
 {
   MOZ_ASSERT(aVoiceEnginePtr);
   MOZ_ASSERT(aAudioInput);
   mDeviceName.Assign(NS_ConvertUTF8toUTF16(name));
   mDeviceUUID.Assign(uuid);
   mListener = new mozilla::WebRTCAudioDataListener(this);
   mSettings->mEchoCancellation.Construct(0);
   mSettings->mAutoGainControl.Construct(0);
@@ -618,17 +619,26 @@ MediaEngineWebRTCMicrophoneSource::Packe
     uint32_t samplesPerPacket = mPacketizer->PacketSize() *
       mPacketizer->Channels();
     if (mInputBuffer.Length() < samplesPerPacket) {
       mInputBuffer.SetLength(samplesPerPacket);
     }
     int16_t* packet = mInputBuffer.Elements();
     mPacketizer->Output(packet);
 
-    mVoERender->ExternalRecordingInsertData(packet, samplesPerPacket, aRate, 0);
+    if (aChannels > MAX_CHANNELS) {
+      AudioConverter converter(AudioConfig(aChannels, 0, AudioConfig::FORMAT_S16),
+                               AudioConfig(MAX_CHANNELS, 0, AudioConfig::FORMAT_S16));
+      converter.Process(mInputDownmixBuffer, packet, mPacketizer->PacketSize());
+      mVoERender->ExternalRecordingInsertData(mInputDownmixBuffer.Data(),
+                                              mPacketizer->PacketSize() * MAX_CHANNELS,
+                                              aRate, 0);
+    } else {
+      mVoERender->ExternalRecordingInsertData(packet, samplesPerPacket, aRate, 0);
+    }
   }
 }
 
 template<typename T>
 void
 MediaEngineWebRTCMicrophoneSource::InsertInGraph(const T* aBuffer,
                                                  size_t aFrames,
                                                  uint32_t aChannels)
@@ -656,18 +666,18 @@ MediaEngineWebRTCMicrophoneSource::Inser
     TimeStamp insertTime;
     // Make sure we include the stream and the track.
     // The 0:1 is a flag to note when we've done the final insert for a given input block.
     LogTime(AsyncLatencyLogger::AudioTrackInsertion,
             LATENCY_STREAM_ID(mSources[i].get(), mTrackID),
             (i+1 < len) ? 0 : 1, insertTime);
 
     // Bug 971528 - Support stereo capture in gUM
-    MOZ_ASSERT(aChannels == 1 || aChannels == 2,
-        "GraphDriver only supports mono and stereo audio for now");
+    MOZ_ASSERT(aChannels >= 1 && aChannels <= 8,
+               "Support up to 8 channels");
 
     nsAutoPtr<AudioSegment> segment(new AudioSegment());
     RefPtr<SharedBuffer> buffer =
       SharedBuffer::Create(aFrames * aChannels * sizeof(T));
     AutoTArray<const T*, 8> channels;
     if (aChannels == 1) {
       PodCopy(static_cast<T*>(buffer->Data()), aBuffer, aFrames);
       channels.AppendElement(static_cast<T*>(buffer->Data()));
@@ -843,17 +853,18 @@ MediaEngineWebRTCMicrophoneSource::Alloc
         // Set "codec" to PCM, 32kHz on device's channels
         ScopedCustomReleasePtr<webrtc::VoECodec> ptrVoECodec(webrtc::VoECodec::GetInterface(mVoiceEngine));
         if (ptrVoECodec) {
           webrtc::CodecInst codec;
           strcpy(codec.plname, ENCODING);
           codec.channels = CHANNELS;
           uint32_t maxChannels = 0;
           if (mAudioInput->GetMaxAvailableChannels(maxChannels) == 0) {
-            codec.channels = maxChannels;
+            MOZ_ASSERT(maxChannels);
+            codec.channels = std::min<uint32_t>(maxChannels, MAX_CHANNELS);
           }
           MOZ_ASSERT(mSampleFrequency == 16000 || mSampleFrequency == 32000);
           codec.rate = SAMPLE_RATE(mSampleFrequency);
           codec.plfreq = mSampleFrequency;
           codec.pacsize = SAMPLE_LENGTH(mSampleFrequency);
           codec.pltype = 0; // Default payload type
 
           if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {