Hook audio mixer and playout to media engine, mostly ported from GIPS change 9b8c733

Also hack Getdevice to always output hw:0,0 as "default" device is not supported by alsa

Change-Id: I899b7de3c6604561d7e3500130e486483b6c92c6
diff --git a/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.cc b/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.cc
index 88ab2f5..e6ff130 100644
--- a/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.cc
+++ b/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.cc
@@ -109,7 +109,9 @@
     _recWarning(0),
     _recError(0),
     _playBufDelay(80),
-    _playBufDelayFixed(80)
+    _playBufDelayFixed(80),
+    _playedFrames(0),
+    _recordedFrames(0)
 {
     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
                  "%s created", __FUNCTION__);
@@ -986,6 +988,12 @@
 
 WebRtc_Word32 AudioDeviceLinuxALSA::SetPlayoutDevice(WebRtc_UWord16 index)
 {
+#ifdef BRUNO
+    WEBRTC_TRACE(kTraceModuleCall, kTraceAudioDevice, _id,
+                 "Only one playout device is on Bruno. Skip SetPlayoutDevice(index=%u)", index);
+    _outputDeviceIndex = 1;
+    _outputDeviceIsSpecified = true;
+#else
     WEBRTC_TRACE(kTraceModuleCall, kTraceAudioDevice, _id,
                  "SetPlayoutDevice(index=%u)", index);
 
@@ -1007,6 +1015,7 @@
 
     _outputDeviceIndex = index;
     _outputDeviceIsSpecified = true;
+#endif  // BRUNO
 
     return 0;
 }
@@ -1215,7 +1224,13 @@
     //
     if (_handlePlayout != NULL)
     {
+#ifdef BRUNO
+        _mixerManager.GetNexusMixer()->InputDetach (_handlePlayout->GetPlayoutConnector());
+        _handlePlayout->Terminate();
+        delete _handlePlayout;
+#else
         LATE(snd_pcm_close)(_handlePlayout);
+#endif  // BRUNO
         _handlePlayout = NULL;
         _playIsInitialized = false;
         if (errVal < 0)
@@ -1234,6 +1249,16 @@
     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
                  "  InitPlayout open (%s)", deviceName);
 
+#ifdef BRUNO
+    _handlePlayout = bruno::AudioPlayoutFactory::Create();
+    if (!_handlePlayout) {
+      WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+          "Failed to create playback device: (%d)", errVal);
+        return -1;
+    }
+    errVal = _handlePlayout->Init();
+    _mixerManager.GetNexusMixer()->InputConnect (_handlePlayout->GetPlayoutConnector());
+#else
     errVal = LATE(snd_pcm_open)
                  (&_handlePlayout,
                   deviceName,
@@ -1256,6 +1281,7 @@
             }
         }
     }
+#endif  // BRUNO
     if (errVal < 0)
     {
         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
@@ -1267,6 +1293,9 @@
     }
 
     _playoutFramesIn10MS = _playoutFreq/100;
+#ifdef BRUNO
+    _handlePlayout->SetParams(bruno::AudioPlayoutInterface::PCM_FORMAT_S16_LE, _playoutFreq, _playChannels);
+#else  // BRUNO
     if ((errVal = LATE(snd_pcm_set_params)( _handlePlayout,
 #if defined(WEBRTC_BIG_ENDIAN)
         SND_PCM_FORMAT_S16_BE,
@@ -1290,7 +1319,15 @@
         _handlePlayout = NULL;
         return -1;
     }
+#endif  // BRUNO
 
+#ifdef BRUNO
+    _playoutBufferSizeInFrame = _handlePlayout->GetPlayoutBufferSize();
+
+    // Assuming _playoutPeriodSizeInFrame is just _playoutFramesIn10MS as Nexus has no facility to
+    // confirm the playout size per frame (but ALSA has)
+    _playoutPeriodSizeInFrame = _playoutFramesIn10MS;
+#else
     errVal = LATE(snd_pcm_get_params)(_handlePlayout,
         &_playoutBufferSizeInFrame, &_playoutPeriodSizeInFrame);
     if (errVal < 0)
@@ -1308,6 +1345,7 @@
                      "buffer_size:%d period_size :%d",
                      _playoutBufferSizeInFrame, _playoutPeriodSizeInFrame);
     }
+#endif  // BRUNO
 
     if (_ptrAudioBuffer)
     {
@@ -1317,8 +1355,13 @@
     }
 
     // Set play buffer size
+#ifdef BRUNO
+    _playoutBufferSizeIn10MS = _handlePlayout->Frames2Bytes(
+        _playoutFramesIn10MS);
+#else
     _playoutBufferSizeIn10MS = LATE(snd_pcm_frames_to_bytes)(
         _handlePlayout, _playoutFramesIn10MS);
+#endif  // BRUNO
 
     // Init varaibles used for play
     _playWarning = 0;
@@ -1401,6 +1444,8 @@
     // Available modes: 0 = blocking, SND_PCM_NONBLOCK, SND_PCM_ASYNC
     if (errVal == -EBUSY) // Device busy - try some more!
     {
+      WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
+          "Recording device busy (%s)", deviceName);
         for (int i=0; i < 5; i++)
         {
             sleep(1);
@@ -1755,7 +1800,11 @@
     }
     _playThreadID = threadID;
 
+#ifdef BRUNO
+    int errVal = _handlePlayout->Start();
+#else
     int errVal = LATE(snd_pcm_prepare)(_handlePlayout);
+#endif  // BRUNO
     if (errVal < 0)
     {
         WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
@@ -1808,6 +1857,12 @@
     _playoutBuffer = NULL;
 
     // stop and close pcm playout device
+#ifdef BRUNO
+    _handlePlayout->Stop();
+    _mixerManager.GetNexusMixer()->InputDetach (_handlePlayout->GetPlayoutConnector());
+    _handlePlayout->Terminate();
+    delete _handlePlayout;
+#else
     int errVal = LATE(snd_pcm_drop)(_handlePlayout);
     if (errVal < 0)
     {
@@ -1821,6 +1876,7 @@
          WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
                       "    Error closing playout sound device, error: %s",
                       LATE(snd_strerror)(errVal));
+#endif  // BRUNO
 
      // set the pcm input handle to NULL
      _playIsInitialized = false;
@@ -1954,6 +2010,46 @@
     // Device enumeration based on libjingle implementation
     // by Tristan Schmelcher at Google Inc.
 
+#ifdef BRUNO
+    // Intercept the playback requests.
+    if (playback) {
+      switch (function) {
+        case FUNC_GET_NUM_OF_DEVICE:
+          return 1;
+        case FUNC_GET_DEVICE_NAME:
+        case FUNC_GET_DEVICE_NAME_FOR_AN_ENUM:
+          if (enumDeviceNo == 0) {
+            strncpy(enumDeviceName, "default", kAdmMaxDeviceNameSize);
+            enumDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
+            return 0;
+          } else if (enumDeviceNo == 1) {
+            strncpy(enumDeviceName, "bruno", kAdmMaxDeviceNameSize);
+            enumDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
+            return 0;
+          } else {
+            // If we get here for function 1 and 2, we didn't find the specified enum device
+            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+                "GetDevicesInfo - Could not find device name or numbers %d", enumDeviceNo);
+            return -1;
+          }
+          break;
+      }
+    } else {
+      switch (function) {
+        case FUNC_GET_NUM_OF_DEVICE:
+          return 1;
+        case FUNC_GET_DEVICE_NAME:
+          strncpy(enumDeviceName, "hw", kAdmMaxDeviceNameSize);
+          enumDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
+          return 0;
+        case FUNC_GET_DEVICE_NAME_FOR_AN_ENUM:
+          strncpy(enumDeviceName, "hw:0,0", kAdmMaxDeviceNameSize);
+          enumDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
+          return 0;
+      }
+    }
+#endif  // BRUNO
+
     const char *type = playback ? "Output" : "Input";
     // dmix and dsnoop are only for playback and capture, respectively, but ALSA
     // stupidly includes them in both lists.
@@ -2210,6 +2306,17 @@
     return res;
 }
 
+#ifdef BRUNO
+WebRtc_Word32 AudioDeviceLinuxALSA::ErrorRecovery(WebRtc_Word32 error,
+    bruno::AudioPlayoutInterface* deviceHandle)
+{
+  WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+      "ErrorRecovery for Bruno is not implemented yet"
+      " and designed not to jumpinto here.");
+  assert (0);
+}
+#endif  // BRUNO
+
 // ============================================================================
 //                                  Thread Methods
 // ============================================================================
@@ -2235,7 +2342,18 @@
 
     Lock();
     //return a positive number of frames ready otherwise a negative error code
+#ifdef BRUNO
+    avail_frames =  _handlePlayout->GetAvailableFrameBuffers();
+#ifdef BRUNO_DEBUG
+    snd_pcm_sframes_t queued =  _handlePlayout->GetQueuedSize();
+    snd_pcm_sframes_t played =  _handlePlayout->GetPlayedFrames();
+    WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
+        "Playout status: avail %d, queued %d, played %d", avail_frames,
+        queued, played);
+#endif  // BRUNO_DEBUG
+#else
     avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout);
+#endif  // BRUNO
     if (avail_frames < 0)
     {
         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
@@ -2250,7 +2368,11 @@
         UnLock();
 
         //maximum tixe in milliseconds to wait, a negative value means infinity
+#ifdef BRUNO
+        err = _handlePlayout->WaitForFrameBuffers(2);
+#else
         err = LATE(snd_pcm_wait)(_handlePlayout, 2);
+#endif  // BRUNO
         if (err == 0)
         { //timeout occured
             WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
@@ -2273,12 +2395,19 @@
     if (static_cast<WebRtc_UWord32>(avail_frames) > _playoutFramesLeft)
         avail_frames = _playoutFramesLeft;
 
+#ifdef BRUNO
+    int size = _handlePlayout->Frames2Bytes(_playoutFramesLeft);
+    frames = _handlePlayout->PlayFrameBuffers(
+        &_playoutBuffer[_playoutBufferSizeIn10MS - size],
+        avail_frames);
+#else
     int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout,
         _playoutFramesLeft);
     frames = LATE(snd_pcm_writei)(
         _handlePlayout,
         &_playoutBuffer[_playoutBufferSizeIn10MS - size],
         avail_frames);
+#endif  // BRUNO
 
     if (frames < 0)
     {
@@ -2291,6 +2420,12 @@
         return true;
     }
     else {
+#ifdef BRUNO_DEBUG
+        _playedFrames += frames;
+        WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
+                     "Accumulative playout frames %d",
+                     _playedFrames);
+#endif  // BRUNO_DEBUG
         assert(frames==avail_frames);
         _playoutFramesLeft -= frames;
     }
@@ -2352,6 +2487,13 @@
     }
     else if (frames > 0)
     {
+#ifdef BRUNO_DEBUG
+        _recordedFrames += frames;
+        WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
+                     "Accumulative captured frames %d",
+                     _recordedFrames);
+#endif  // BRUNO_DEBUG
+
         assert(frames == avail_frames);
 
         int left_size = LATE(snd_pcm_frames_to_bytes)(_handleRecord,
@@ -2391,8 +2533,13 @@
             _recordingDelay = 0;
             if (_handlePlayout)
             {
+#ifdef BRUNO
+                _playoutDelay = _handlePlayout->GetDelay();
+                err = 0;  // Assume no error in Nexus
+#else
                 err = LATE(snd_pcm_delay)(_handlePlayout,
                     &_playoutDelay); // returned delay in frames
+#endif  // BRUNO
                 if (err < 0)
                 {
                     // TODO(xians): Shall we call ErrorRecovery() here?
diff --git a/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.h b/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.h
index 9a5a032..93e31bb 100644
--- a/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.h
+++ b/src/modules/audio_device/main/source/linux/audio_device_alsa_linux.h
@@ -20,6 +20,10 @@
 
 #include <alsa/asoundlib.h>
 
+#ifdef BRUNO
+#include "audioplayout.h"
+#endif  // BRUNO
+
 namespace webrtc
 {
 class EventWrapper;
@@ -168,6 +172,11 @@
                                  const WebRtc_Word32 ednLen = 0) const;
     WebRtc_Word32 ErrorRecovery(WebRtc_Word32 error, snd_pcm_t* deviceHandle);
 
+#ifdef BRUNO
+    WebRtc_Word32 ErrorRecovery(WebRtc_Word32 error,
+        bruno::AudioPlayoutInterface* deviceHandle);
+#endif  // BRUNO
+
 private:
     void Lock() { _critSect.Enter(); };
     void UnLock() { _critSect.Leave(); };
@@ -201,7 +210,11 @@
     bool _outputDeviceIsSpecified;
 
     snd_pcm_t* _handleRecord;
+#ifdef BRUNO
+    bruno::AudioPlayoutInterface* _handlePlayout;
+#else
     snd_pcm_t* _handlePlayout;
+#endif  // BRUNO
 
     snd_pcm_uframes_t _recordingBuffersizeInFrame;
     snd_pcm_uframes_t _recordingPeriodSizeInFrame;
@@ -246,6 +259,9 @@
 
     WebRtc_UWord16 _playBufDelay;                 // playback delay
     WebRtc_UWord16 _playBufDelayFixed;            // fixed playback delay
+
+    WebRtc_UWord32 _playedFrames;
+    WebRtc_UWord32 _recordedFrames;
 };
 
 }
diff --git a/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.cc b/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.cc
index 6722405..66eb5a1 100644
--- a/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.cc
+++ b/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.cc
@@ -80,6 +80,11 @@
     {
         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
                      "Closing playout mixer");
+#ifdef BRUNO
+        _outputMixerHandle->Terminate();
+        errVal = 0;
+        delete _outputMixerHandle;
+#else
         LATE(snd_mixer_free)(_outputMixerHandle);
         if (errVal < 0)
         {
@@ -101,6 +106,7 @@
                          "     Error snd_mixer_close(handleMixer) errVal=%d",
                          errVal);
         }
+#endif  // BRUNO
         _outputMixerHandle = NULL;
         _outputMixerElement = NULL;
     }
@@ -176,6 +182,9 @@
         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
                      "Closing playout mixer");
 
+#ifdef BRUNO
+        CloseSpeaker();
+#else
         LATE(snd_mixer_free)(_outputMixerHandle);
         if (errVal < 0)
         {
@@ -197,10 +206,28 @@
                          "     Error snd_mixer_close(handleMixer) errVal=%d",
                          errVal);
         }
+#endif
     }
     _outputMixerHandle = NULL;
     _outputMixerElement = NULL;
 
+#ifdef BRUNO
+    _outputMixerHandle = bruno::AudioMixerFactory::Create();
+    if (!_outputMixerHandle)
+    {
+        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+                   "new AudioMixer() - error");
+        return -1;
+    }
+    errVal = _outputMixerHandle->Init();
+    if (errVal < 0)
+    {
+        WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
+                   "AudioMixer::Init() - error");
+        return -1;
+    }
+#else
+
     errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0);
     if (errVal < 0)
     {
@@ -242,6 +269,7 @@
     {
         return -1;
     }
+#endif  // BRUNO
 
     if (_outputMixerHandle != NULL)
     {
@@ -387,6 +415,9 @@
         return -1;
     }
 
+#ifdef BRUNO
+    _outputMixerHandle->SetSpeakerVolume(volume);
+#else
     int errVal =
         LATE(snd_mixer_selem_set_playback_volume_all)(_outputMixerElement,
                                                       volume);
@@ -397,6 +428,7 @@
                      LATE(snd_strerror)(errVal));
         return -1;
     }
+#endif  // BRUNO
 
     return (0);
 }
@@ -414,13 +446,19 @@
         return -1;
     }
 
-    long int vol(0);
 
+#ifdef BRUNO
+    WebRtc_UWord32 vol(0);
+    int errVal = _outputMixerHandle->SpeakerVolume(vol);
+#else
+    long int vol(0);
     int
         errVal = LATE(snd_mixer_selem_get_playback_volume)(
             _outputMixerElement,
             (snd_mixer_selem_channel_id_t) 0,
             &vol);
+#endif  // BRUNO
+
     if (errVal < 0)
     {
         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
@@ -450,6 +488,12 @@
         return -1;
     }
 
+#ifdef BRUNO
+    uint32_t vol;
+    int32_t rc = _outputMixerHandle->MaxSpeakerVolume(vol);
+    maxVolume = static_cast<WebRtc_UWord32>(vol);
+    return rc;
+#else
     long int minVol(0);
     long int maxVol(0);
 
@@ -471,6 +515,7 @@
     maxVolume = static_cast<WebRtc_UWord32> (maxVol);
 
     return 0;
+#endif  // BRUNO
 }
 
 WebRtc_Word32 AudioMixerManagerLinuxALSA::MinSpeakerVolume(
@@ -486,6 +531,12 @@
         return -1;
     }
 
+#ifdef BRUNO
+    uint32_t vol = 0;
+    int32_t rc = _outputMixerHandle->MinSpeakerVolume(vol);
+    minVolume = static_cast<WebRtc_UWord32>(vol);
+    return rc;
+#else
     long int minVol(0);
     long int maxVol(0);
 
@@ -507,6 +558,7 @@
     minVolume = static_cast<WebRtc_UWord32> (minVol);
 
     return 0;
+#endif  // BRUNO
 }
 
 // TL: Have done testnig with these but they don't seem reliable and
@@ -626,7 +678,11 @@
         return -1;
     }
 
+#ifdef BRUNO
+    available = _outputMixerHandle->SpeakerVolumeIsAvailable();
+#else
     available = LATE(snd_mixer_selem_has_playback_volume)(_outputMixerElement);
+#endif  // BRUNO
 
     return 0;
 }
@@ -641,7 +697,11 @@
         return -1;
     }
 
+#ifdef BRUNO
+    available = _outputMixerHandle->SpeakerMuteIsAvailable();
+#else
     available = LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
+#endif  // BRUNO
 
     return 0;
 }
@@ -661,6 +721,9 @@
         return -1;
     }
 
+#ifdef BRUNO
+    return _outputMixerHandle->SetSpeakerMute(enable);
+#else
     // Ensure that the selected speaker destination has a valid mute control.
     bool available(false);
     SpeakerMuteIsAvailable(available);
@@ -684,6 +747,7 @@
     }
 
     return (0);
+#endif  // BRUNO
 }
 
 WebRtc_Word32 AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const
@@ -698,6 +762,9 @@
         return -1;
     }
 
+#ifdef BRUNO
+    return _outputMixerHandle->SpeakerMute(enabled);
+#else
     // Ensure that the selected speaker destination has a valid mute control.
     bool available =
         LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
@@ -729,6 +796,7 @@
     enabled = (bool) !value;
 
     return 0;
+#endif  // BRUNO
 }
 
 WebRtc_Word32 AudioMixerManagerLinuxALSA::MicrophoneMuteIsAvailable(
@@ -1234,6 +1302,7 @@
     return 0;
 }
 
+#ifndef BRUNO
 WebRtc_Word32 AudioMixerManagerLinuxALSA::LoadSpeakerMixerElement() const
 {
     int errVal = LATE(snd_mixer_load)(_outputMixerHandle);
@@ -1313,6 +1382,7 @@
 
     return 0;
 }
+#endif  // BRUNO
 
 void AudioMixerManagerLinuxALSA::GetControlName(char* controlName,
                                                 char* deviceName) const
diff --git a/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.h b/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.h
index 1634f94..b8dd406 100644
--- a/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.h
+++ b/src/modules/audio_device/main/source/linux/audio_mixer_manager_alsa_linux.h
@@ -18,7 +18,7 @@
 
 #ifdef BRUNO
 #include "audiomixer.h"
-#endif
+#endif  // BRUNO
 
 #include <alsa/asoundlib.h>
 
@@ -56,7 +56,11 @@
     WebRtc_Word32 CloseMicrophone();
     bool SpeakerIsInitialized() const;
     bool MicrophoneIsInitialized() const;
-
+#ifdef BRUNO
+    bruno::AudioMixerInterface* GetNexusMixer(void) const {
+      return _outputMixerHandle;
+    }
+#endif  // BRUNO
 public:
     AudioMixerManagerLinuxALSA(const WebRtc_Word32 id);
     ~AudioMixerManagerLinuxALSA();
@@ -71,7 +75,11 @@
 private:
     CriticalSectionWrapper& _critSect;
     WebRtc_Word32 _id;
+#ifdef BRUNO
+    mutable bruno::AudioMixerInterface* _outputMixerHandle;
+#else
     mutable snd_mixer_t* _outputMixerHandle;
+#endif  // BRUNO
     char _outputMixerStr[kAdmMaxDeviceNameSize];
     mutable snd_mixer_t* _inputMixerHandle;
     char _inputMixerStr[kAdmMaxDeviceNameSize];