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];