summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McNeil <sean.mcneil@windriver.com>2009-02-26 11:54:15 +0700
committerSean McNeil <sean.mcneil@windriver.com>2009-02-26 11:54:15 +0700
commit6186b61b05256f91ccba70edee935f3a2b3f475a (patch)
treeeabe300d8c484c9bfb0b068bd7d66d984743297e
parent8eafdf7f47151d26ea6b1276d527d0f3a1911e9a (diff)
downloadalsa_sound-6186b61b05256f91ccba70edee935f3a2b3f475a.tar.gz
Run through bcpp program to eliminate tabs and cleanup format.
Update to build with new AudioHardwareBase. Fix problem with Zoom not supporting buffer allocation based on sample time. Allow device to provide multiple routes instead of just first encountered.
-rw-r--r--Android.mk11
-rw-r--r--AudioHardwareALSA.cpp1016
-rw-r--r--AudioHardwareALSA.h444
-rw-r--r--AudioHardwareInterface.cpp230
-rw-r--r--AudioHardwareStub.cpp175
-rw-r--r--AudioHardwareStub.h95
6 files changed, 797 insertions, 1174 deletions
diff --git a/Android.mk b/Android.mk
index 14c0216..52a9adb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,23 +10,22 @@ ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
- LOCAL_CFLAGS = -fno-short-enums
+ LOCAL_CFLAGS := -D_POSIX_SOURCE
LOCAL_WHOLE_STATIC_LIBRARIES := libasound
LOCAL_C_INCLUDES += external/alsa-lib/include
- LOCAL_SRC_FILES := \
- AudioHardwareInterface.cpp \
- AudioHardwareStub.cpp \
- AudioHardwareALSA.cpp
+ LOCAL_SRC_FILES := AudioHardwareALSA.cpp
LOCAL_MODULE := libaudio
+ LOCAL_STATIC_LIBRARIES += libaudiointerface
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia \
- libhardware \
+ libhardware_legacy \
libdl \
libc
diff --git a/AudioHardwareALSA.cpp b/AudioHardwareALSA.cpp
index 5fe7fd1..3d7b77d 100644
--- a/AudioHardwareALSA.cpp
+++ b/AudioHardwareALSA.cpp
@@ -1,19 +1,19 @@
/* AudioHardwareALSA.cpp
-**
-** Copyright 2008 Wind River Systems
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ **
+ ** Copyright 2008-2009 Wind River Systems
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
#include <errno.h>
#include <stdarg.h>
@@ -30,39 +30,54 @@
#include <cutils/properties.h>
#include <media/AudioRecord.h>
-#include <hardware/power.h>
+#include <hardware_legacy/power.h>
#include <alsa/asoundlib.h>
#include "AudioHardwareALSA.h"
#define SND_MIXER_VOL_RANGE_MIN (0)
-#define SND_MIXER_VOL_RANGE_MAX (1000)
-
-extern "C" {
+#define SND_MIXER_VOL_RANGE_MAX (100)
-extern int ffs(int i);
+#define ALSA_NAME_MAX 128
-//
-// Make sure this prototype is consistent with what's in
-// external/libasound/alsa-lib-1.0.16/src/pcm/pcm_null.c!
-//
-extern int snd_pcm_null_open(snd_pcm_t **pcmp,
- const char *name,
- snd_pcm_stream_t stream,
- int mode);
+#define ALSA_STRCAT(x,y) \
+ if (strlen(x) + strlen(y) < ALSA_NAME_MAX) \
+ strcat(x, y);
-//
-// Function for dlsym() to look up for creating a new AudioHardwareInterface.
-//
-android::AudioHardwareInterface *createAudioHardware(void)
+extern "C"
{
- return new android::AudioHardwareALSA();
-}
-} // extern "C"
+ extern int ffs(int i);
+ //
+ // Make sure this prototype is consistent with what's in
+ // external/libasound/alsa-lib-1.0.16/src/pcm/pcm_null.c!
+ //
+ extern int snd_pcm_null_open(snd_pcm_t **pcmp,
+ const char *name,
+ snd_pcm_stream_t stream,
+ int mode);
-namespace android {
+ //
+ // Function for dlsym() to look up for creating a new AudioHardwareInterface.
+ //
+ android::AudioHardwareInterface *createAudioHardware(void) {
+ return new android::AudioHardwareALSA();
+ }
+
+} // extern "C"
+
+namespace android
+{
+
+typedef AudioSystem::audio_routes audio_routes;
+
+#define ROUTE_ALL AudioSystem::ROUTE_ALL
+#define ROUTE_EARPIECE AudioSystem::ROUTE_EARPIECE
+#define ROUTE_SPEAKER AudioSystem::ROUTE_SPEAKER
+#define ROUTE_BLUETOOTH_SCO AudioSystem::ROUTE_BLUETOOTH_SCO
+#define ROUTE_HEADSET AudioSystem::ROUTE_HEADSET
+#define ROUTE_BLUETOOTH_A2DP AudioSystem::ROUTE_BLUETOOTH_A2DP
// ----------------------------------------------------------------------------
@@ -89,52 +104,68 @@ static void ALSAErrorHandler(const char *file,
// ----------------------------------------------------------------------------
-struct alsa_properties_t {
- const char *propName;
- const char *propDefault;
-};
-
-static const alsa_properties_t masterPlaybackProp = {
- "alsa.mixer.playback.master", "PCM"
-};
-
-static const alsa_properties_t masterCaptureProp = {
- "alsa.mixer.capture.master", "Capture"
-};
-
/* The following table(s) need to match in order of the route bits
*/
static const char *deviceSuffix[] = {
- /* ROUTE_EARPIECE */ "_Earpiece",
- /* ROUTE_SPEAKER */ "_Speaker",
- /* ROUTE_BLUETOOTH */ "_Bluetooth",
- /* ROUTE_HEADSET */ "_Headset",
+ /* ROUTE_EARPIECE */ "_Earpiece",
+ /* ROUTE_SPEAKER */ "_Speaker",
+ /* ROUTE_BLUETOOTH_SCO */ "_Bluetooth",
+ /* ROUTE_HEADSET */ "_Headset",
+ /* ROUTE_BLUETOOTH_A2DP */ "_Bluetooth-A2DP",
};
static const int deviceSuffixLen = (sizeof(deviceSuffix) / sizeof(char *));
-static const alsa_properties_t
- mixerMasterProp[SND_PCM_STREAM_LAST+1] =
+struct mixer_info_t;
+
+struct alsa_properties_t
{
- { "alsa.mixer.playback.master", "PCM" },
- { "alsa.mixer.capture.master", "Capture" }
+ const audio_routes routes;
+ const char *propName;
+ const char *propDefault;
+ mixer_info_t *mInfo;
};
-static const alsa_properties_t
- mixerProp[SND_PCM_STREAM_LAST+1][ALSAMixer::MIXER_LAST+1] =
-{
+static alsa_properties_t masterPlaybackProp = {
+ ROUTE_ALL, "alsa.mixer.playback.master", "PCM", NULL
+};
+
+static alsa_properties_t masterCaptureProp = {
+ ROUTE_ALL, "alsa.mixer.capture.master", "Capture", NULL
+};
+
+static alsa_properties_t
+mixerMasterProp[SND_PCM_STREAM_LAST+1] = {
+ { ROUTE_ALL, "alsa.mixer.playback.master", "PCM", NULL},
+ { ROUTE_ALL, "alsa.mixer.capture.master", "Capture", NULL}
+};
+
+static alsa_properties_t
+mixerProp[][SND_PCM_STREAM_LAST+1] = {
+ {
+ {ROUTE_EARPIECE, "alsa.mixer.playback.earpiece", "Earpiece", NULL},
+ {ROUTE_EARPIECE, "alsa.mixer.capture.earpiece", "Capture", NULL}
+ },
+ {
+ {ROUTE_SPEAKER, "alsa.mixer.playback.speaker", "Speaker", NULL},
+ {ROUTE_SPEAKER, "alsa.mixer.capture.speaker", "", NULL}
+ },
+ {
+ {ROUTE_BLUETOOTH_SCO, "alsa.mixer.playback.bluetooth.sco", "Bluetooth", NULL},
+ {ROUTE_BLUETOOTH_SCO, "alsa.mixer.capture.bluetooth.sco", "Bluetooth Capture", NULL}
+ },
+ {
+ {ROUTE_HEADSET, "alsa.mixer.playback.headset", "Headphone", NULL},
+ {ROUTE_HEADSET, "alsa.mixer.capture.headset", "Capture", NULL}
+ },
{
- {"alsa.mixer.playback.earpiece", "Earpiece"},
- {"alsa.mixer.playback.speaker", "Speaker"},
- {"alsa.mixer.playback.bluetooth", "Bluetooth"},
- {"alsa.mixer.playback.headset", "Headphone"}
- },
- {
- {"alsa.mixer.capture.earpiece", "Capture"},
- {"alsa.mixer.capture.speaker", ""},
- {"alsa.mixer.capture.bluetooth", "Bluetooth Capture"},
- {"alsa.mixer.capture.headset", "Capture"}
- }
+ {ROUTE_BLUETOOTH_A2DP, "alsa.mixer.playback.bluetooth.a2dp", "Bluetooth A2DP", NULL},
+ {ROUTE_BLUETOOTH_A2DP, "alsa.mixer.capture.bluetooth.a2dp", "Bluetooth A2DP Capture", NULL}
+ },
+ {
+ {static_cast<audio_routes>(0), NULL, NULL, NULL},
+ {static_cast<audio_routes>(0), NULL, NULL, NULL}
+ }
};
// ----------------------------------------------------------------------------
@@ -156,16 +187,16 @@ AudioHardwareALSA::~AudioHardwareALSA()
status_t AudioHardwareALSA::initCheck()
{
- if (mMixer && mMixer->isValid())
- return NO_ERROR;
- else
- return NO_INIT;
+ if (mMixer && mMixer->isValid())
+ return NO_ERROR;
+ else
+ return NO_INIT;
}
status_t AudioHardwareALSA::standby()
{
- if (mOutput)
- return mOutput->standby();
+ if (mOutput)
+ return mOutput->standby();
return NO_ERROR;
}
@@ -173,62 +204,75 @@ status_t AudioHardwareALSA::standby()
status_t AudioHardwareALSA::setVoiceVolume(float volume)
{
// The voice volume is used by the VOICE_CALL audio stream.
- if (mMixer)
- return mMixer->setVolume(ALSAMixer::MIXER_EARPIECE, volume);
- else
- return INVALID_OPERATION;
+ if (mMixer)
+ return mMixer->setVolume(ROUTE_EARPIECE, volume);
+ else
+ return INVALID_OPERATION;
}
status_t AudioHardwareALSA::setMasterVolume(float volume)
{
- if (mMixer)
- return mMixer->setMasterVolume(volume);
- else
- return INVALID_OPERATION;
+ if (mMixer)
+ return mMixer->setMasterVolume(volume);
+ else
+ return INVALID_OPERATION;
}
-AudioStreamOut *AudioHardwareALSA::openOutputStream(int format,
- int channelCount,
- uint32_t sampleRate)
+AudioStreamOut *
+AudioHardwareALSA::openOutputStream(int format,
+ int channelCount,
+ uint32_t sampleRate,
+ status_t *status)
{
AutoMutex lock(mLock);
// only one output stream allowed
- if (mOutput)
+ if (mOutput) {
+ *status = ALREADY_EXISTS;
return 0;
+ }
AudioStreamOutALSA *out = new AudioStreamOutALSA(this);
- if (out->set(format, channelCount, sampleRate) == NO_ERROR) {
+ *status = out->set(format, channelCount, sampleRate);
+
+ if (*status == NO_ERROR) {
mOutput = out;
// Some information is expected to be available immediately after
// the device is open.
- uint32_t routes = mRoutes[mMode];
+ uint32_t routes = mRoutes[mMode];
mOutput->setDevice(mMode, routes);
- } else {
+ }
+ else {
delete out;
}
return mOutput;
}
-AudioStreamIn *AudioHardwareALSA::openInputStream(int format,
- int channelCount,
- uint32_t sampleRate)
+AudioStreamIn *
+AudioHardwareALSA::openInputStream(int format,
+ int channelCount,
+ uint32_t sampleRate,
+ status_t *status)
{
AutoMutex lock(mLock);
// only one input stream allowed
- if (mInput)
+ if (mInput) {
+ *status = ALREADY_EXISTS;
return 0;
+ }
AudioStreamInALSA *in = new AudioStreamInALSA(this);
- if (in->set(format, channelCount, sampleRate) == NO_ERROR) {
+ *status = in->set(format, channelCount, sampleRate);
+ if (*status == NO_ERROR) {
mInput = in;
// Now, actually open the device. Only 1 route used
mInput->setDevice(0, 0);
- } else {
+ }
+ else {
delete in;
}
return mInput;
@@ -249,22 +293,16 @@ status_t AudioHardwareALSA::doRouting()
status_t AudioHardwareALSA::setMicMute(bool state)
{
- ALSAMixer::mixer_types mixer_type =
- static_cast<ALSAMixer::mixer_types>(ffs(AudioSystem::ROUTE_EARPIECE) - 1);
-
if (mMixer)
- return mMixer->setCaptureMuteState(mixer_type, state);
+ return mMixer->setCaptureMuteState(ROUTE_EARPIECE, state);
return NO_INIT;
}
status_t AudioHardwareALSA::getMicMute(bool *state)
{
- ALSAMixer::mixer_types mixer_type =
- static_cast<ALSAMixer::mixer_types>(ffs(AudioSystem::ROUTE_EARPIECE) - 1);
-
if (mMixer)
- return mMixer->getCaptureMuteState(mixer_type, state);
+ return mMixer->getCaptureMuteState(ROUTE_EARPIECE, state);
return NO_ERROR;
}
@@ -281,7 +319,7 @@ ALSAStreamOps::ALSAStreamOps() :
mHardwareParams(0),
mSoftwareParams(0),
mMode(-1),
- mDevice(-1)
+ mDevice(0)
{
if (snd_pcm_hw_params_malloc(&mHardwareParams) < 0) {
LOG_ALWAYS_FATAL("Failed to allocate ALSA hardware parameters!");
@@ -294,7 +332,7 @@ ALSAStreamOps::ALSAStreamOps() :
ALSAStreamOps::~ALSAStreamOps()
{
- AutoMutex lock(mLock);
+ AutoMutex lock(mLock);
close();
@@ -316,23 +354,24 @@ status_t ALSAStreamOps::set(int format,
mDefaults->sampleRate = rate;
switch(format) {
- case AudioSystem::DEFAULT: // format == 0
- break;
+ // format == 0
+ case AudioSystem::DEFAULT:
+ break;
- case AudioSystem::PCM_16_BIT:
- mDefaults->format = SND_PCM_FORMAT_S16_LE;
- break;
+ case AudioSystem::PCM_16_BIT:
+ mDefaults->format = SND_PCM_FORMAT_S16_LE;
+ break;
- case AudioSystem::PCM_8_BIT:
- mDefaults->format = SND_PCM_FORMAT_S8;
- break;
+ case AudioSystem::PCM_8_BIT:
+ mDefaults->format = SND_PCM_FORMAT_S8;
+ break;
- default:
- LOGE("Unknown PCM format %i. Forcing default", format);
- break;
+ default:
+ LOGE("Unknown PCM format %i. Forcing default", format);
+ break;
}
- return NO_ERROR;
+ return NO_ERROR;
}
uint32_t ALSAStreamOps::sampleRate() const
@@ -344,7 +383,7 @@ uint32_t ALSAStreamOps::sampleRate() const
return NO_INIT;
return snd_pcm_hw_params_get_rate(mHardwareParams, &rate, 0) < 0
- ? 0 : static_cast<uint32_t>(rate);
+ ? 0 : static_cast<uint32_t>(rate);
}
status_t ALSAStreamOps::sampleRate(uint32_t rate)
@@ -365,7 +404,7 @@ status_t ALSAStreamOps::sampleRate(uint32_t rate)
if (err < 0) {
LOGE("Unable to set %s sample rate to %u: %s",
- stream, rate, snd_strerror(err));
+ stream, rate, snd_strerror(err));
return BAD_VALUE;
}
if (requestedRate != rate) {
@@ -373,8 +412,9 @@ status_t ALSAStreamOps::sampleRate(uint32_t rate)
// This may cause resampling problems; i.e. PCM playback will be too
// slow or fast.
LOGW("Requested rate (%u HZ) does not match actual rate (%u HZ)",
- rate, requestedRate);
- } else {
+ rate, requestedRate);
+ }
+ else {
LOGD("Set %s sample rate to %u HZ", stream, requestedRate);
}
return NO_ERROR;
@@ -385,19 +425,20 @@ status_t ALSAStreamOps::sampleRate(uint32_t rate)
//
size_t ALSAStreamOps::bufferSize() const
{
- snd_pcm_uframes_t periodSize;
int err;
if (!mHandle)
return -1;
- err = snd_pcm_hw_params_get_period_size(mHardwareParams,
- &periodSize,
- 0);
+ snd_pcm_uframes_t bufferSize = 0;
+ snd_pcm_uframes_t periodSize = 0;
+
+ err = snd_pcm_get_params(mHandle, &bufferSize, &periodSize);
+
if (err < 0)
return -1;
- return static_cast<size_t>(snd_pcm_frames_to_bytes(mHandle, periodSize));
+ return static_cast<size_t>(snd_pcm_frames_to_bytes(mHandle, bufferSize));
}
int ALSAStreamOps::format() const
@@ -415,18 +456,17 @@ int ALSAStreamOps::format() const
pcmFormatBitWidth = snd_pcm_format_physical_width(ALSAFormat);
audioSystemFormat = AudioSystem::DEFAULT;
- switch(pcmFormatBitWidth)
- {
- case 8:
- audioSystemFormat = AudioSystem::PCM_8_BIT;
- break;
+ switch(pcmFormatBitWidth) {
+ case 8:
+ audioSystemFormat = AudioSystem::PCM_8_BIT;
+ break;
- case 16:
- audioSystemFormat = AudioSystem::PCM_16_BIT;
- break;
+ case 16:
+ audioSystemFormat = AudioSystem::PCM_16_BIT;
+ break;
- default:
- LOG_FATAL("Unknown AudioSystem bit width %i!", pcmFormatBitWidth);
+ default:
+ LOG_FATAL("Unknown AudioSystem bit width %i!", pcmFormatBitWidth);
}
return audioSystemFormat;
@@ -443,15 +483,14 @@ int ALSAStreamOps::channelCount() const
err = snd_pcm_hw_params_get_channels(mHardwareParams, &val);
if (err < 0) {
LOGE("Unable to get device channel count: %s",
- snd_strerror(err));
+ snd_strerror(err));
return -1;
}
return val;
}
-status_t ALSAStreamOps::channelCount(int channels)
-{
+status_t ALSAStreamOps::channelCount(int channels) {
int err;
if (!mHandle)
@@ -460,62 +499,50 @@ status_t ALSAStreamOps::channelCount(int channels)
err = snd_pcm_hw_params_set_channels(mHandle, mHardwareParams, channels);
if (err < 0) {
LOGE("Unable to set channel count to %i: %s",
- channels, snd_strerror(err));
+ channels, snd_strerror(err));
return BAD_VALUE;
}
LOGD("Using %i %s for %s.",
- channels, channels == 1 ? "channel" : "channels", streamName());
+ channels, channels == 1 ? "channel" : "channels", streamName());
return NO_ERROR;
}
-status_t ALSAStreamOps::open(int mode, int device)
+status_t ALSAStreamOps::open(int mode, uint32_t device)
{
const char *stream = streamName();
const char *devName = deviceName(mode, device);
int err;
- // The PCM stream is opened in blocking mode, per ALSA defaults. The
- // AudioFlinger seems to assume blocking mode too, so asynchronous mode
- // should not be used.
- if ((err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0)) < 0) {
+ for(;;) {
+ // The PCM stream is opened in blocking mode, per ALSA defaults. The
+ // AudioFlinger seems to assume blocking mode too, so asynchronous mode
+ // should not be used.
+ err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
+ if (err == 0) break;
- // Try without the mode.
- devName = deviceName(AudioSystem::MODE_INVALID, device);
+ // See if there is a less specific name we can try.
+ // Note: We are changing the contents of a const char * here.
+ char *tail = strrchr(devName, '_');
+ if (! tail) break;
+ *tail = 0;
+ }
+ if (err < 0) {
+ // None of the Android defined audio devices exist. Open a generic one.
+ devName = "hw:00,0";
err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
if (err < 0) {
-
- // Try without mode or device.
- devName = deviceName(AudioSystem::MODE_INVALID, -1);
-
- err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
- if (err < 0) {
-
- err = snd_pcm_open(&mHandle, "hw:00,0", mDefaults->direction, 0);
-
- if (err < 0) {
- LOGE("Unable to open fallback %s device: %s",
- stream, snd_strerror(err));
-
- // Last resort is the NULL device (i.e. the bit bucket).
- err = snd_pcm_null_open(&mHandle, _nullALSADeviceName,
- mDefaults->direction, 0);
- if (err < 0) {
- LOG_FATAL("Unable to open NULL ALSA device: %s",
- snd_strerror(err));
- }
- LOGD("Opened NULL %s device.", streamName());
- return err;
- }
- }
+ // Last resort is the NULL device (i.e. the bit bucket).
+ devName = _nullALSADeviceName;
+ err = snd_pcm_open(&mHandle, devName, mDefaults->direction, 0);
}
}
- mMode = mode;
- mDevice = device;
+ mMode = mode;
+ mDevice = device;
LOGI("Initialized ALSA %s device %s", stream, devName);
return err;
@@ -523,13 +550,13 @@ status_t ALSAStreamOps::open(int mode, int device)
void ALSAStreamOps::close()
{
- snd_pcm_t *handle = mHandle;
+ snd_pcm_t *handle = mHandle;
mHandle = NULL;
if (handle) {
snd_pcm_close(handle);
- mMode = -1;
- mDevice = -1;
+ mMode = -1;
+ mDevice = 0;
}
}
@@ -558,18 +585,19 @@ status_t ALSAStreamOps::setSoftwareParams()
// For playback, configure ALSA to start the transfer when the
// buffer is almost full.
startThreshold = (bufferSize / periodSize) * periodSize;
- } else {
+ }
+ else {
// For recording, configure ALSA to start the transfer on the
// first frame.
startThreshold = 1;
}
err = snd_pcm_sw_params_set_start_threshold(mHandle,
- mSoftwareParams,
- startThreshold);
+ mSoftwareParams,
+ startThreshold);
if (err < 0) {
LOGE("Unable to set start threshold to %lu frames: %s",
- startThreshold, snd_strerror(err));
+ startThreshold, snd_strerror(err));
return NO_INIT;
}
@@ -579,7 +607,7 @@ status_t ALSAStreamOps::setSoftwareParams()
bufferSize);
if (err < 0) {
LOGE("Unable to set stop threshold to %lu frames: %s",
- bufferSize, snd_strerror(err));
+ bufferSize, snd_strerror(err));
return NO_INIT;
}
@@ -590,7 +618,7 @@ status_t ALSAStreamOps::setSoftwareParams()
periodSize);
if (err < 0) {
LOGE("Unable to configure available minimum to %lu: %s",
- periodSize, snd_strerror(err));
+ periodSize, snd_strerror(err));
return NO_INIT;
}
@@ -598,7 +626,7 @@ status_t ALSAStreamOps::setSoftwareParams()
err = snd_pcm_sw_params(mHandle, mSoftwareParams);
if (err < 0) {
LOGE("Unable to configure software parameters: %s",
- snd_strerror(err));
+ snd_strerror(err));
return NO_INIT;
}
@@ -624,7 +652,7 @@ status_t ALSAStreamOps::setPCMFormat(snd_pcm_format_t format)
err = snd_pcm_hw_params_set_format(mHandle, mHardwareParams, format);
if (err < 0) {
LOGE("Unable to configure PCM format %s (%s): %s",
- formatName, formatDesc, snd_strerror(err));
+ formatName, formatDesc, snd_strerror(err));
return NO_INIT;
}
@@ -641,8 +669,8 @@ status_t ALSAStreamOps::setHardwareResample(bool resample)
static_cast<int>(resample));
if (err < 0) {
LOGE("Unable to %s hardware resampling: %s",
- resample ? "enable" : "disable",
- snd_strerror(err));
+ resample ? "enable" : "disable",
+ snd_strerror(err));
return NO_INIT;
}
return NO_ERROR;
@@ -676,7 +704,7 @@ status_t ALSAStreamOps::setDevice(int mode, uint32_t device)
const char *stream = streamName();
status_t status = open (mode, device);
- int err;
+ int err;
if (status != NO_ERROR)
return status;
@@ -687,17 +715,17 @@ status_t ALSAStreamOps::setDevice(int mode, uint32_t device)
return NO_INIT;
}
+ status = setPCMFormat(mDefaults->format);
+
// Set the interleaved read and write format.
err = snd_pcm_hw_params_set_access(mHandle, mHardwareParams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
LOGE("Unable to configure PCM read/write format: %s",
- snd_strerror(err));
+ snd_strerror(err));
return NO_INIT;
}
- status = setPCMFormat(mDefaults->format);
-
//
// Some devices do not have the default two channels. Force an error to
// prevent AudioMixer from crashing and taking the whole system down.
@@ -719,33 +747,71 @@ status_t ALSAStreamOps::setDevice(int mode, uint32_t device)
if (status != NO_ERROR)
return status;
- unsigned int bufferTime;
- unsigned int periodTime;
+ snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;
+ unsigned int latency = mDefaults->latency;
- // Set the buffer time.
- bufferTime = mDefaults->bufferTime;
- err = snd_pcm_hw_params_set_buffer_time_near(mHandle,
- mHardwareParams,
- &bufferTime,
- 0);
+ // Make sure we have at least the size we originally wanted
+ err = snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, bufferSize);
if (err < 0) {
- LOGE("Unable to set buffer time to %u usec: %s",
- bufferTime, snd_strerror(err));
+ LOGE("Unable to set buffer size to %d: %s",
+ (int)bufferSize, snd_strerror(err));
return NO_INIT;
}
- // Set the period time (i.e. the number of frames)
- periodTime = mDefaults->periodTime;
- err = snd_pcm_hw_params_set_period_time_near(mHandle,
- mHardwareParams,
- &periodTime,
- 0);
+ // Setup buffers for latency
+ err = snd_pcm_hw_params_set_buffer_time_near (mHandle, mHardwareParams,
+ &latency, NULL);
if (err < 0) {
- LOGE("Unable to set period time to %u usec: %s",
- periodTime, snd_strerror(err));
- return NO_INIT;
+ /* That didn't work, set the period instead */
+ unsigned int periodTime = latency / 4;
+ err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,
+ &periodTime, NULL);
+ if (err < 0) {
+ LOGE("Unable to set the period time for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
+ snd_pcm_uframes_t periodSize;
+ err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);
+ if (err < 0) {
+ LOGE("Unable to get the period size for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
+ bufferSize = periodSize * 4;
+ if (bufferSize < mDefaults->bufferSize)
+ bufferSize = mDefaults->bufferSize;
+ err = snd_pcm_hw_params_set_buffer_size_near (mHandle, mHardwareParams, &bufferSize);
+ if (err < 0) {
+ LOGE("Unable to set the buffer size for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
+ } else {
+ // OK, we got buffer time near what we expect. See what that did for bufferSize.
+ err = snd_pcm_hw_params_get_buffer_size (mHardwareParams, &bufferSize);
+ if (err < 0) {
+ LOGE("Unable to get the buffer size for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
+ // Does set_buffer_time_near change the passed value? It should.
+ err = snd_pcm_hw_params_get_buffer_time (mHardwareParams, &latency, NULL);
+ if (err < 0) {
+ LOGE("Unable to get the buffer time for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
+ unsigned int periodTime = latency / 4;
+ err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,
+ &periodTime, NULL);
+ if (err < 0) {
+ LOGE("Unable to set the period time for latency: %s", snd_strerror(err));
+ return NO_INIT;
+ }
}
+ LOGD("Buffer size: %d", (int)bufferSize);
+ LOGD("Latency: %d", (int)latency);
+
+ mDefaults->bufferSize = bufferSize;
+ mDefaults->latency = latency;
+
// Commit the hardware parameters back to the device.
err = snd_pcm_hw_params(mHandle, mHardwareParams);
if (err < 0) {
@@ -761,49 +827,44 @@ status_t ALSAStreamOps::setDevice(int mode, uint32_t device)
// ----------------------------------------------------------------------------
AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent) :
- mParent(parent),
- mPowerLock(false)
+ mParent(parent),
+ mPowerLock(false)
{
- static StreamDefaults _defaults =
- {
- deviceName : "AndroidPlayback",
+ static StreamDefaults _defaults = {
+ devicePrefix : "AndroidPlayback",
direction : SND_PCM_STREAM_PLAYBACK,
- format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
+ format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
channels : 2,
sampleRate : 44100,
- bufferTime : 500000, // Ring buffer length in usec, 1/2 second
- periodTime : 100000, // Period time in usec
- };
+ latency : 250000, // Desired Delay in usec
+ bufferSize : 16384, // Desired Number of samples
+ };
setStreamDefaults(&_defaults);
}
AudioStreamOutALSA::~AudioStreamOutALSA()
{
- standby();
- mParent->mOutput = NULL;
+ standby();
+ mParent->mOutput = NULL;
}
int AudioStreamOutALSA::channelCount() const
{
- int c;
-
- c = ALSAStreamOps::channelCount();
+ int c = ALSAStreamOps::channelCount();
// AudioMixer will seg fault if it doesn't have two channels.
LOGW_IF(c != 2,
- "AudioMixer expects two channels, but only %i found!", c);
+ "AudioMixer expects two channels, but only %i found!", c);
return c;
}
status_t AudioStreamOutALSA::setVolume(float volume)
{
- if (! mParent->mMixer || mDevice < 0)
- return NO_INIT;
-
- ALSAMixer::mixer_types mixer_type = static_cast<ALSAMixer::mixer_types>(mDevice);
+ if (! mParent->mMixer || ! mDevice)
+ return NO_INIT;
- return mParent->mMixer->setVolume (mixer_type, volume);
+ return mParent->mMixer->setVolume (mDevice, volume);
}
ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
@@ -814,7 +875,7 @@ ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
AutoMutex lock(mLock);
if (isStandby())
- return 0;
+ return 0;
if (!mPowerLock) {
acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioLock");
@@ -841,47 +902,43 @@ status_t AudioStreamOutALSA::dump(int fd, const Vector<String16>& args)
status_t AudioStreamOutALSA::setDevice(int mode, uint32_t newDevice)
{
- uint32_t dev;
-
- //
- // Output to only one device. The new device is the first selected bit
- // in newDevice (per IAudioFlinger::ROUTE_*).
- //
- // It's possible to not output to any device (i.e. newDevice is 0).
- //
- dev = newDevice ? (ffs(static_cast<int>(newDevice)) - 1) : -1;
-
AutoMutex lock(mLock);
- return ALSAStreamOps::setDevice(mode, dev);
+ return ALSAStreamOps::setDevice(mode, newDevice);
}
-const char *AudioStreamOutALSA::deviceName(int mode, int device)
+const char *AudioStreamOutALSA::deviceName(int mode, uint32_t device)
{
- static char devString[PROPERTY_VALUE_MAX];
- int hasDevExt = 0;
-
- strcpy (devString, mDefaults->deviceName);
+ static char devString[ALSA_NAME_MAX];
+ int dev;
+ int hasDevExt = 0;
+
+ strcpy (devString, mDefaults->devicePrefix);
+
+ for (dev=0; device; dev++)
+ if (device & (1 << dev)) {
+ /* Don't go past the end of our list */
+ if (dev >= deviceSuffixLen)
+ break;
+ ALSA_STRCAT (devString, deviceSuffix[dev]);
+ device &= ~(1 << dev);
+ hasDevExt = 1;
+ }
- if (device >= 0 && device < deviceSuffixLen) {
- strcat (devString, deviceSuffix[device]);
- hasDevExt = 1;
- }
+ if (hasDevExt)
+ switch (mode) {
+ case AudioSystem::MODE_NORMAL:
+ ALSA_STRCAT (devString, "_normal");
+ break;
+ case AudioSystem::MODE_RINGTONE:
+ ALSA_STRCAT (devString, "_ringtone");
+ break;
+ case AudioSystem::MODE_IN_CALL:
+ ALSA_STRCAT (devString, "_incall");
+ break;
+ };
- if (hasDevExt)
- switch (mode) {
- case AudioSystem::MODE_NORMAL:
- strcat (devString, "_normal");
- break;
- case AudioSystem::MODE_RINGTONE:
- strcat (devString, "_ringtone");
- break;
- case AudioSystem::MODE_IN_CALL:
- strcat (devString, "_incall");
- break;
- };
-
- return devString;
+ return devString;
}
status_t AudioStreamOutALSA::standby()
@@ -904,36 +961,43 @@ bool AudioStreamOutALSA::isStandby()
return (!mHandle);
}
+#define USEC_TO_MSEC(x) ((x + 999) / 1000)
+
+uint32_t AudioStreamOutALSA::latency() const
+{
+ // Android wants latency in milliseconds.
+ return USEC_TO_MSEC (mDefaults->latency);
+}
+
// ----------------------------------------------------------------------------
AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent) :
- mParent(parent)
+ mParent(parent)
{
- static StreamDefaults _defaults =
- {
- deviceName : "AndroidRecord",
+ static StreamDefaults _defaults = {
+ devicePrefix : "AndroidRecord",
direction : SND_PCM_STREAM_CAPTURE,
- format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
+ format : SND_PCM_FORMAT_S16_LE, // AudioSystem::PCM_16_BIT
channels : 1,
sampleRate : AudioRecord::DEFAULT_SAMPLE_RATE,
- bufferTime : 500000, // Ring buffer length in usec, 1/2 second
- periodTime : 100000, // Period time in usec
- };
+ latency : 250000, // Desired Delay in usec
+ bufferSize : 16384, // Desired Number of samples
+ };
setStreamDefaults(&_defaults);
}
AudioStreamInALSA::~AudioStreamInALSA()
{
- mParent->mInput = NULL;
+ mParent->mInput = NULL;
}
status_t AudioStreamInALSA::setGain(float gain)
{
- if (mParent->mMixer)
- return mParent->mMixer->setMasterGain (gain);
- else
- return NO_INIT;
+ if (mParent->mMixer)
+ return mParent->mMixer->setMasterGain (gain);
+ else
+ return NO_INIT;
}
ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
@@ -962,40 +1026,53 @@ status_t AudioStreamInALSA::setDevice(int mode, uint32_t newDevice)
{
AutoMutex lock(mLock);
- // The AudioHardwareALSA API does not allow one to set the input routing.
- // Only one input device (the microphone) is currently supported.
- //
- return ALSAStreamOps::setDevice(mode, AudioRecord::MIC_INPUT);
+ return ALSAStreamOps::setDevice(mode, newDevice);
}
-const char *AudioStreamInALSA::deviceName(int mode, int device)
+const char *AudioStreamInALSA::deviceName(int mode, uint32_t device)
{
- static char devString[PROPERTY_VALUE_MAX];
+ static char devString[ALSA_NAME_MAX];
+
+ strcpy (devString, mDefaults->devicePrefix);
- strcpy (devString, mDefaults->deviceName);
+ // The AudioHardwareALSA API does not allow one to set the input routing.
+ // Only one input device (the microphone) is currently supported.
+ //
strcat (devString, "_Microphone");
return devString;
}
+status_t AudioStreamInALSA::standby()
+{
+ AutoMutex lock(mLock);
+
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
-struct ALSAMixer::mixer_info_t {
- mixer_info_t() :
- elem(0), min(0), max(100), mute(false)
- {
- }
- snd_mixer_elem_t *elem;
- long min;
- long max;
- long volume;
- bool mute;
- char name[PROPERTY_VALUE_MAX];
+struct mixer_info_t
+{
+ mixer_info_t() :
+ elem(0),
+ min(SND_MIXER_VOL_RANGE_MIN),
+ max(SND_MIXER_VOL_RANGE_MAX),
+ mute(false)
+ {
+ }
+
+ snd_mixer_elem_t *elem;
+ long min;
+ long max;
+ long volume;
+ bool mute;
+ char name[ALSA_NAME_MAX];
};
static int initMixer (snd_mixer_t **mixer, const char *name)
{
- int err;
+ int err;
if ((err = snd_mixer_open(mixer, 0)) < 0) {
LOGE("Unable to open mixer: %s", snd_strerror(err));
@@ -1004,159 +1081,168 @@ static int initMixer (snd_mixer_t **mixer, const char *name)
if ((err = snd_mixer_attach(*mixer, name)) < 0) {
LOGE("Unable to attach mixer to device %s: %s",
- name, snd_strerror(err));
+ name, snd_strerror(err));
- if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) {
- LOGE("Unable to attach mixer to device default: %s",
- snd_strerror(err));
+ if ((err = snd_mixer_attach(*mixer, "hw:00")) < 0) {
+ LOGE("Unable to attach mixer to device default: %s",
+ snd_strerror(err));
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
- }
+ snd_mixer_close (*mixer);
+ *mixer = NULL;
+ return err;
+ }
}
if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) {
LOGE("Unable to register mixer elements: %s", snd_strerror(err));
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
+ snd_mixer_close (*mixer);
+ *mixer = NULL;
+ return err;
}
// Get the mixer controls from the kernel
if ((err = snd_mixer_load(*mixer)) < 0) {
LOGE("Unable to load mixer elements: %s", snd_strerror(err));
- snd_mixer_close (*mixer);
- *mixer = NULL;
- return err;
+ snd_mixer_close (*mixer);
+ *mixer = NULL;
+ return err;
}
- return 0;
+ return 0;
}
typedef int (*hasVolume_t)(snd_mixer_elem_t*);
-static hasVolume_t hasVolume[] =
-{
- snd_mixer_selem_has_playback_volume,
- snd_mixer_selem_has_capture_volume
+static const hasVolume_t hasVolume[] = {
+ snd_mixer_selem_has_playback_volume,
+ snd_mixer_selem_has_capture_volume
};
typedef int (*getVolumeRange_t)(snd_mixer_elem_t*, long int*, long int*);
-static getVolumeRange_t getVolumeRange[] =
-{
- snd_mixer_selem_get_playback_volume_range,
- snd_mixer_selem_get_capture_volume_range
+static const getVolumeRange_t getVolumeRange[] = {
+ snd_mixer_selem_get_playback_volume_range,
+ snd_mixer_selem_get_capture_volume_range
};
typedef int (*setVolume_t)(snd_mixer_elem_t*, long int);
-static setVolume_t setVol[] =
-{
- snd_mixer_selem_set_playback_volume_all,
- snd_mixer_selem_set_capture_volume_all
+static const setVolume_t setVol[] = {
+ snd_mixer_selem_set_playback_volume_all,
+ snd_mixer_selem_set_capture_volume_all
};
ALSAMixer::ALSAMixer()
{
int err;
- initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidPlayback");
- initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidRecord");
+ initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidPlayback");
+ initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidRecord");
snd_mixer_selem_id_t *sid;
snd_mixer_selem_id_alloca(&sid);
- for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
+ for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
- mMaster[i] = new mixer_info_t;
+ mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;
- property_get (mixerMasterProp[i].propName,
- mMaster[i]->name,
- mixerMasterProp[i].propDefault);
+ property_get (mixerMasterProp[i].propName,
+ info->name,
+ mixerMasterProp[i].propDefault);
- for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
- elem;
- elem = snd_mixer_elem_next(elem)) {
+ for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
+ elem;
+ elem = snd_mixer_elem_next(elem)) {
- if (!snd_mixer_selem_is_active(elem))
- continue;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
- snd_mixer_selem_get_id(elem, sid);
+ snd_mixer_selem_get_id(elem, sid);
- // Find PCM playback volume control element.
- const char *elementName = snd_mixer_selem_id_get_name(sid);
+ // Find PCM playback volume control element.
+ const char *elementName = snd_mixer_selem_id_get_name(sid);
- if (mMaster[i]->elem == NULL &&
- strcmp(elementName, mMaster[i]->name) == 0 &&
- hasVolume[i] (elem)) {
+ if (hasVolume[i] (elem))
+ LOGD ("Mixer: element name: '%s'", elementName);
- mMaster[i]->elem = elem;
- getVolumeRange[i] (elem, &mMaster[i]->min, &mMaster[i]->max);
- mMaster[i]->volume = mMaster[i]->max;
- setVol[i] (elem, mMaster[i]->volume);
- if (i == SND_PCM_STREAM_PLAYBACK &&
- snd_mixer_selem_has_playback_switch (elem))
- snd_mixer_selem_set_playback_switch_all (elem, 1);
- break;
- }
+ if (info->elem == NULL &&
+ strcmp(elementName, info->name) == 0 &&
+ hasVolume[i] (elem)) {
+
+ info->elem = elem;
+ getVolumeRange[i] (elem, &info->min, &info->max);
+ info->volume = info->max;
+ setVol[i] (elem, info->volume);
+ if (i == SND_PCM_STREAM_PLAYBACK &&
+ snd_mixer_selem_has_playback_switch (elem))
+ snd_mixer_selem_set_playback_switch_all (elem, 1);
+ break;
+ }
}
- for (int j = 0; j <= MIXER_LAST; j++) {
+ LOGD ("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");
+
+ for (int j = 0; mixerProp[j][i].routes; j++) {
- mInfo[i][j] = new mixer_info_t;
+ mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;
- property_get (mixerProp[i][j].propName,
- mInfo[i][j]->name,
- mixerProp[i][j].propDefault);
+ property_get (mixerProp[j][i].propName,
+ info->name,
+ mixerProp[j][i].propDefault);
- for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
- elem;
- elem = snd_mixer_elem_next(elem)) {
+ for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
+ elem;
+ elem = snd_mixer_elem_next(elem)) {
- if (!snd_mixer_selem_is_active(elem))
- continue;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
- snd_mixer_selem_get_id(elem, sid);
+ snd_mixer_selem_get_id(elem, sid);
- // Find PCM playback volume control element.
- const char *elementName = snd_mixer_selem_id_get_name(sid);
+ // Find PCM playback volume control element.
+ const char *elementName = snd_mixer_selem_id_get_name(sid);
- if (mInfo[i][j]->elem == NULL &&
- strcmp(elementName, mInfo[i][j]->name) == 0 &&
- hasVolume[i] (elem)) {
+ if (info->elem == NULL &&
+ strcmp(elementName, info->name) == 0 &&
+ hasVolume[i] (elem)) {
- mInfo[i][j]->elem = elem;
- getVolumeRange[i] (elem, &mInfo[i][j]->min, &mInfo[i][j]->max);
- mInfo[i][j]->volume = mInfo[i][j]->max;
- setVol[i] (elem, mInfo[i][j]->volume);
- if (i == SND_PCM_STREAM_PLAYBACK &&
- snd_mixer_selem_has_playback_switch (elem))
- snd_mixer_selem_set_playback_switch_all (elem, 1);
- break;
- }
- }
- }
- }
- LOGD("mixer initialized.");
+ info->elem = elem;
+ getVolumeRange[i] (elem, &info->min, &info->max);
+ info->volume = info->max;
+ setVol[i] (elem, info->volume);
+ if (i == SND_PCM_STREAM_PLAYBACK &&
+ snd_mixer_selem_has_playback_switch (elem))
+ snd_mixer_selem_set_playback_switch_all (elem, 1);
+ break;
+ }
+ }
+ LOGD ("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
+ }
+ }
+ LOGD("mixer initialized.");
}
ALSAMixer::~ALSAMixer()
{
- for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
- if (mMixer[i]) snd_mixer_close (mMixer[i]);
- if (mMaster[i]) delete mMaster[i];
- for (int j = 0; j <= MIXER_LAST; j++) {
- if (mInfo[i][j]) delete mInfo[i][j];
- }
- }
+ for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {
+ if (mMixer[i]) snd_mixer_close (mMixer[i]);
+ if (mixerMasterProp[i].mInfo) {
+ delete mixerMasterProp[i].mInfo;
+ mixerMasterProp[i].mInfo = NULL;
+ }
+ for (int j = 0; mixerProp[j][i].routes; j++) {
+ if (mixerProp[j][i].mInfo) {
+ delete mixerProp[j][i].mInfo;
+ mixerProp[j][i].mInfo = NULL;
+ }
+ }
+ }
LOGD("mixer destroyed.");
}
status_t ALSAMixer::setMasterVolume(float volume)
{
- mixer_info_t *info = mMaster[SND_PCM_STREAM_PLAYBACK];
+ mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
if (!info || !info->elem) return INVALID_OPERATION;
long minVol = info->min;
@@ -1175,7 +1261,7 @@ status_t ALSAMixer::setMasterVolume(float volume)
status_t ALSAMixer::setMasterGain(float gain)
{
- mixer_info_t *info = mMaster[SND_PCM_STREAM_CAPTURE];
+ mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_CAPTURE].mInfo;
if (!info || !info->elem) return INVALID_OPERATION;
long minVol = info->min;
@@ -1192,108 +1278,134 @@ status_t ALSAMixer::setMasterGain(float gain)
return NO_ERROR;
}
-status_t ALSAMixer::setVolume(mixer_types mixer, float volume)
+status_t ALSAMixer::setVolume(uint32_t device, float volume)
{
- mixer_info_t *info = mInfo[mixer][SND_PCM_STREAM_PLAYBACK];
- if (!info || !info->elem) return INVALID_OPERATION;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
- long minVol = info->min;
- long maxVol = info->max;
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
- // Make sure volume is between bounds.
- long vol = minVol + volume * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
+ long minVol = info->min;
+ long maxVol = info->max;
- info->volume = vol;
- snd_mixer_selem_set_playback_volume_all (info->elem, vol);
+ // Make sure volume is between bounds.
+ long vol = minVol + volume * (maxVol - minVol);
+ if (vol > maxVol) vol = maxVol;
+ if (vol < minVol) vol = minVol;
+
+ info->volume = vol;
+ snd_mixer_selem_set_playback_volume_all (info->elem, vol);
+ }
return NO_ERROR;
}
-status_t ALSAMixer::setGain(mixer_types mixer, float gain)
+status_t ALSAMixer::setGain(uint32_t device, float gain)
{
- mixer_info_t *info = mInfo[mixer][SND_PCM_STREAM_CAPTURE];
- if (!info || !info->elem) return INVALID_OPERATION;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
- long minVol = info->min;
- long maxVol = info->max;
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
- // Make sure volume is between bounds.
- long vol = minVol + gain * (maxVol - minVol);
- if (vol > maxVol) vol = maxVol;
- if (vol < minVol) vol = minVol;
+ long minVol = info->min;
+ long maxVol = info->max;
- info->volume = vol;
- snd_mixer_selem_set_capture_volume_all (info->elem, vol);
+ // Make sure volume is between bounds.
+ long vol = minVol + gain * (maxVol - minVol);
+ if (vol > maxVol) vol = maxVol;
+ if (vol < minVol) vol = minVol;
+
+ info->volume = vol;
+ snd_mixer_selem_set_capture_volume_all (info->elem, vol);
+ }
return NO_ERROR;
}
-status_t ALSAMixer::setCaptureMuteState(mixer_types mixer, bool state)
+status_t ALSAMixer::setCaptureMuteState(uint32_t device, bool state)
{
- mixer_info_t *info = mInfo[mixer][SND_PCM_STREAM_CAPTURE];
- if (!info || !info->elem) return INVALID_OPERATION;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
- if (info->mute == state) return NO_ERROR;
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
- if (snd_mixer_selem_has_capture_switch (info->elem)) {
+ if (snd_mixer_selem_has_capture_switch (info->elem)) {
- int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state));
- if (err < 0) {
- LOGE("Unable to %s capture mixer switch %s",
- state ? "enable" : "disable", info->name);
- return INVALID_OPERATION;
- }
- }
+ int err = snd_mixer_selem_set_capture_switch_all (info->elem, static_cast<int>(!state));
+ if (err < 0) {
+ LOGE("Unable to %s capture mixer switch %s",
+ state ? "enable" : "disable", info->name);
+ return INVALID_OPERATION;
+ }
+ }
+
+ info->mute = state;
+ }
- info->mute = state;
return NO_ERROR;
}
-status_t ALSAMixer::getCaptureMuteState(mixer_types mixer, bool *state)
+status_t ALSAMixer::getCaptureMuteState(uint32_t device, bool *state)
{
- mixer_info_t *info = mInfo[mixer][SND_PCM_STREAM_CAPTURE];
- if (!info || !info->elem) return INVALID_OPERATION;
-
if (! state) return BAD_VALUE;
- *state = info->mute;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_CAPTURE].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_CAPTURE].routes & device) {
- return NO_ERROR;
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_CAPTURE].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
+
+ *state = info->mute;
+ return NO_ERROR;
+ }
+
+ return BAD_VALUE;
}
-status_t ALSAMixer::setPlaybackMuteState(mixer_types mixer, bool state)
+status_t ALSAMixer::setPlaybackMuteState(uint32_t device, bool state)
{
- mixer_info_t *info = mInfo[mixer][SND_PCM_STREAM_PLAYBACK];
- if (!info || !info->elem) return INVALID_OPERATION;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
- if (snd_mixer_selem_has_playback_switch (info->elem)) {
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
- int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state));
- if (err < 0) {
- LOGE("Unable to %s playback mixer switch %s",
- state ? "enable" : "disable", info->name);
- return INVALID_OPERATION;
- }
- }
+ if (snd_mixer_selem_has_playback_switch (info->elem)) {
+
+ int err = snd_mixer_selem_set_playback_switch_all (info->elem, static_cast<int>(!state));
+ if (err < 0) {
+ LOGE("Unable to %s playback mixer switch %s",
+ state ? "enable" : "disable", info->name);
+ return INVALID_OPERATION;
+ }
+ }
+
+ info->mute = state;
+ }
- info->mute = state;
return NO_ERROR;
}
-status_t ALSAMixer::getPlaybackMuteState(mixer_types mixer, bool *state)
+status_t ALSAMixer::getPlaybackMuteState(uint32_t device, bool *state)
{
- mixer_info_t *info = mInfo[SND_PCM_STREAM_PLAYBACK][mixer];
- if (!info || !info->elem) return INVALID_OPERATION;
-
if (! state) return BAD_VALUE;
- *state = info->mute;
+ for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes; j++)
+ if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].routes & device) {
- return NO_ERROR;
+ mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
+ if (!info || !info->elem) return INVALID_OPERATION;
+
+ *state = info->mute;
+ return NO_ERROR;
+ }
+
+ return BAD_VALUE;
}
// ----------------------------------------------------------------------------
-}; // namespace android
+}; // namespace android
diff --git a/AudioHardwareALSA.h b/AudioHardwareALSA.h
index 12d875c..b2b0975 100644
--- a/AudioHardwareALSA.h
+++ b/AudioHardwareALSA.h
@@ -1,19 +1,19 @@
/* AudioHardwareALSA.h
-**
-** Copyright 2008, Wind River Systems
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ **
+ ** Copyright 2008, Wind River Systems
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
#ifndef ANDROID_AUDIO_HARDWARE_ALSA_H
#define ANDROID_AUDIO_HARDWARE_ALSA_H
@@ -22,245 +22,257 @@
#include <sys/types.h>
#include <alsa/asoundlib.h>
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioHardwareBase.h>
-namespace android {
-
-class AudioHardwareALSA;
-
-// ----------------------------------------------------------------------------
-
-class ALSAMixer
+namespace android
{
-public:
- //
- // Keep this in sync with AudioSystem::audio_routes
- //
- enum mixer_types {
- MIXER_EARPIECE = 0,
- MIXER_SPEAKER = 1,
- MIXER_BLUETOOTH = 2,
- MIXER_HEADSET = 3,
- MIXER_LAST = MIXER_HEADSET
- };
-
- ALSAMixer();
- virtual ~ALSAMixer();
- bool isValid() { return !!mMixer[SND_PCM_STREAM_PLAYBACK]; }
- status_t setMasterVolume(float volume);
- status_t setMasterGain(float gain);
+ class AudioHardwareALSA;
- status_t setVolume(mixer_types mixer, float volume);
- status_t setGain(mixer_types mixer, float gain);
+ // ----------------------------------------------------------------------------
- status_t setCaptureMuteState(mixer_types mixer, bool state);
- status_t getCaptureMuteState(mixer_types mixer, bool *state);
- status_t setPlaybackMuteState(mixer_types mixer, bool state);
- status_t getPlaybackMuteState(mixer_types mixer, bool *state);
-
-private:
- snd_mixer_t *mMixer[SND_PCM_STREAM_LAST+1];
-
- struct mixer_info_t;
- mixer_info_t *mMaster[SND_PCM_STREAM_LAST+1];
- mixer_info_t *mInfo[SND_PCM_STREAM_LAST+1][MIXER_LAST+1];
-};
-
-class ALSAStreamOps
-{
-public:
- struct StreamDefaults
+ class ALSAMixer
{
- const char * deviceName;
- snd_pcm_stream_t direction; // playback or capture
- snd_pcm_format_t format;
- int channels;
- uint32_t sampleRate;
- unsigned int bufferTime; // Ring buffer length in usec
- unsigned int periodTime; // Period time in usec
- };
-
- ALSAStreamOps();
- virtual ~ALSAStreamOps();
-
- status_t set(int format,
- int channels,
- uint32_t rate);
- virtual uint32_t sampleRate() const;
- status_t sampleRate(uint32_t rate);
- virtual size_t bufferSize() const;
- virtual int format() const;
- virtual int channelCount() const;
- status_t channelCount(int channels);
- const char *streamName();
- virtual status_t setDevice(int mode, uint32_t device);
-
- virtual const char *deviceName(int mode, int device) = 0;
-
-protected:
- friend class AudioStreamOutALSA;
- friend class AudioStreamInALSA;
-
- status_t open(int mode, int device);
- void close();
- status_t setSoftwareParams();
- status_t setPCMFormat(snd_pcm_format_t format);
- status_t setHardwareResample(bool resample);
-
- void setStreamDefaults(StreamDefaults *dev)
- {
- mDefaults = dev;
- }
-
- Mutex mLock;
+ public:
+ ALSAMixer();
+ virtual ~ALSAMixer();
-private:
- snd_pcm_t *mHandle;
- snd_pcm_hw_params_t *mHardwareParams;
- snd_pcm_sw_params_t *mSoftwareParams;
- int mMode;
- int mDevice;
+ bool isValid() { return !!mMixer[SND_PCM_STREAM_PLAYBACK]; }
+ status_t setMasterVolume(float volume);
+ status_t setMasterGain(float gain);
- StreamDefaults *mDefaults;
-};
+ status_t setVolume(uint32_t device, float volume);
+ status_t setGain(uint32_t device, float gain);
-// ----------------------------------------------------------------------------
-
-class AudioStreamOutALSA : public AudioStreamOut, public ALSAStreamOps
-{
-public:
- AudioStreamOutALSA(AudioHardwareALSA *parent);
- virtual ~AudioStreamOutALSA();
-
- status_t set(int format = 0,
- int channelCount = 0,
- uint32_t sampleRate = 0)
- {
- return ALSAStreamOps::set(format, channelCount, sampleRate);
- }
+ status_t setCaptureMuteState(uint32_t device, bool state);
+ status_t getCaptureMuteState(uint32_t device, bool *state);
+ status_t setPlaybackMuteState(uint32_t device, bool state);
+ status_t getPlaybackMuteState(uint32_t device, bool *state);
- virtual uint32_t sampleRate() const
- {
- return ALSAStreamOps::sampleRate();
- }
+ private:
+ snd_mixer_t *mMixer[SND_PCM_STREAM_LAST+1];
+ };
- virtual size_t bufferSize() const
+ class ALSAStreamOps
{
- return ALSAStreamOps::bufferSize();
- }
+ public:
+ struct StreamDefaults
+ {
+ const char * devicePrefix;
+ snd_pcm_stream_t direction; // playback or capture
+ snd_pcm_format_t format;
+ int channels;
+ uint32_t sampleRate;
+ unsigned int latency; // Delay in usec
+ unsigned int bufferSize; // Size of sample buffer
+ };
+
+ ALSAStreamOps();
+ virtual ~ALSAStreamOps();
+
+ status_t set(int format,
+ int channels,
+ uint32_t rate);
+ virtual uint32_t sampleRate() const;
+ status_t sampleRate(uint32_t rate);
+ virtual size_t bufferSize() const;
+ virtual int format() const;
+ virtual int channelCount() const;
+ status_t channelCount(int channels);
+ const char *streamName();
+ virtual status_t setDevice(int mode, uint32_t device);
+
+ virtual const char *deviceName(int mode, uint32_t device) = 0;
+
+ protected:
+ friend class AudioStreamOutALSA;
+ friend class AudioStreamInALSA;
+
+ status_t open(int mode, uint32_t device);
+ void close();
+ status_t setSoftwareParams();
+ status_t setPCMFormat(snd_pcm_format_t format);
+ status_t setHardwareResample(bool resample);
+
+ void setStreamDefaults(StreamDefaults *dev) {
+ mDefaults = dev;
+ }
+
+ Mutex mLock;
+
+ private:
+ snd_pcm_t *mHandle;
+ snd_pcm_hw_params_t *mHardwareParams;
+ snd_pcm_sw_params_t *mSoftwareParams;
+ int mMode;
+ uint32_t mDevice;
+
+ StreamDefaults *mDefaults;
+ };
- virtual int channelCount() const;
+ // ----------------------------------------------------------------------------
- virtual int format() const
+ class AudioStreamOutALSA : public AudioStreamOut, public ALSAStreamOps
{
- return ALSAStreamOps::format();
- }
+ public:
+ AudioStreamOutALSA(AudioHardwareALSA *parent);
+ virtual ~AudioStreamOutALSA();
- virtual ssize_t write(const void *buffer, size_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
- virtual status_t setDevice(int mode, uint32_t newDevice);
+ status_t set(int format = 0,
+ int channelCount = 0,
+ uint32_t sampleRate = 0) {
+ return ALSAStreamOps::set(format, channelCount, sampleRate);
+ }
- status_t setVolume(float volume);
+ virtual uint32_t sampleRate() const
+ {
+ return ALSAStreamOps::sampleRate();
+ }
- virtual const char *deviceName(int mode, int device);
+ virtual size_t bufferSize() const
+ {
+ return ALSAStreamOps::bufferSize();
+ }
- status_t standby();
- bool isStandby();
+ virtual int channelCount() const;
-private:
- AudioHardwareALSA *mParent;
- bool mPowerLock;
-};
+ virtual int format() const
+ {
+ return ALSAStreamOps::format();
+ }
+ virtual uint32_t latency() const;
-class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps
-{
-public:
- AudioStreamInALSA(AudioHardwareALSA *parent);
- virtual ~AudioStreamInALSA();
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setDevice(int mode, uint32_t newDevice);
- status_t set(int format = 0,
- int channelCount = 0,
- uint32_t sampleRate = 0)
- {
- return ALSAStreamOps::set(format, channelCount, sampleRate);
- }
+ status_t setVolume(float volume);
- virtual uint32_t sampleRate()
- {
- return ALSAStreamOps::sampleRate();
- }
+ virtual const char *deviceName(int mode, uint32_t device);
- virtual size_t bufferSize() const
- {
- return ALSAStreamOps::bufferSize();
- }
+ status_t standby();
+ bool isStandby();
- virtual int channelCount() const
- {
- return ALSAStreamOps::channelCount();
- }
+ private:
+ AudioHardwareALSA *mParent;
+ bool mPowerLock;
+ };
- virtual int format() const
+ class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps
{
- return ALSAStreamOps::format();
- }
+ public:
+ AudioStreamInALSA(AudioHardwareALSA *parent);
+ virtual ~AudioStreamInALSA();
- virtual ssize_t read(void* buffer, ssize_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
- virtual status_t setDevice(int mode, uint32_t newDevice);
+ status_t set(int format = 0,
+ int channelCount = 0,
+ uint32_t sampleRate = 0) {
+ return ALSAStreamOps::set(format, channelCount, sampleRate);
+ }
- virtual status_t setGain(float gain);
+ virtual uint32_t sampleRate() {
+ return ALSAStreamOps::sampleRate();
+ }
- virtual const char *deviceName(int mode, int device);
+ virtual size_t bufferSize() const
+ {
+ return ALSAStreamOps::bufferSize();
+ }
-private:
- AudioHardwareALSA *mParent;
-};
+ virtual int channelCount() const
+ {
+ return ALSAStreamOps::channelCount();
+ }
+ virtual int format() const
+ {
+ return ALSAStreamOps::format();
+ }
-class AudioHardwareALSA : public AudioHardwareInterface
-{
-public:
- AudioHardwareALSA();
- virtual ~AudioHardwareALSA();
-
- virtual status_t initCheck();
- virtual status_t standby();
- virtual status_t setVoiceVolume(float volume);
- virtual status_t setMasterVolume(float volume);
-
- virtual AudioStreamOut *openOutputStream(int format = 0,
- int channelCount = 0,
- uint32_t sampleRate = 0);
-
- virtual AudioStreamIn *openInputStream (int format = 0,
- int channelCount = 0,
- uint32_t sampleRate = 0);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setDevice(int mode, uint32_t newDevice);
- // Microphone mute
- virtual status_t setMicMute(bool state);
- virtual status_t getMicMute(bool *state);
+ virtual status_t setGain(float gain);
-protected:
- // audio routing
- virtual status_t doRouting();
- virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual const char *deviceName(int mode, uint32_t device);
- friend class AudioStreamOutALSA;
- friend class AudioStreamInALSA;
+ virtual status_t standby();
- ALSAMixer *mMixer;
- AudioStreamOutALSA *mOutput;
- AudioStreamInALSA *mInput;
-
-private:
- Mutex mLock;
-};
+ private:
+ AudioHardwareALSA *mParent;
+ };
-// ----------------------------------------------------------------------------
+ class AudioHardwareALSA : public AudioHardwareBase
+ {
+ public:
+ AudioHardwareALSA();
+ virtual ~AudioHardwareALSA();
+
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ * return status based on values defined in include/utils/Errors.h
+ */
+ virtual status_t initCheck();
+
+ /**
+ * put the audio hardware into standby mode to conserve power. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby();
+
+ /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+ virtual status_t setVoiceVolume(float volume);
+
+ /**
+ * set the audio volume for all audio activities other than voice call.
+ * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+ * the software mixer will emulate this capability.
+ */
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ /** This method creates and opens the audio hardware output stream */
+ virtual AudioStreamOut* openOutputStream(
+ int format=0,
+ int channelCount=0,
+ uint32_t sampleRate=0,
+ status_t *status=0);
+
+ /** This method creates and opens the audio hardware input stream */
+ virtual AudioStreamIn* openInputStream(
+ int format,
+ int channelCount,
+ uint32_t sampleRate,
+ status_t *status);
+
+ protected:
+ /**
+ * doRouting actually initiates the routing. A call to setRouting
+ * or setMode may result in a routing change. The generic logic calls
+ * doRouting when required. If the device has any special requirements these
+ * methods can be overriden.
+ */
+ virtual status_t doRouting();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ friend class AudioStreamOutALSA;
+ friend class AudioStreamInALSA;
+
+ ALSAMixer *mMixer;
+ AudioStreamOutALSA *mOutput;
+ AudioStreamInALSA *mInput;
+
+ private:
+ Mutex mLock;
+ };
-}; // namespace android
+ // ----------------------------------------------------------------------------
-#endif // ANDROID_AUDIO_HARDWARE_ALSA_H
+}; // namespace android
+#endif // ANDROID_AUDIO_HARDWARE_ALSA_H
diff --git a/AudioHardwareInterface.cpp b/AudioHardwareInterface.cpp
deleted file mode 100644
index 68fa70e..0000000
--- a/AudioHardwareInterface.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-** Copyright 2008 Wind River Systems
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <cutils/properties.h>
-#include <string.h>
-#include <unistd.h>
-
-#define LOG_TAG "AudioHardwareInterface"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include "AudioHardwareStub.h"
-#include "AudioHardwareALSA.h"
-
-// #define DUMP_FLINGER_OUT // if defined allows recording samples in a file
-#ifdef DUMP_FLINGER_OUT
-#include "AudioDumpInterface.h"
-#endif
-
-
-// change to 1 to log routing calls
-#define LOG_ROUTING_CALLS 0
-
-namespace android {
-
-#if LOG_ROUTING_CALLS
-static const char* routingModeStrings[] =
-{
- "OUT OF RANGE",
- "INVALID",
- "CURRENT",
- "NORMAL",
- "RINGTONE",
- "IN_CALL"
-};
-
-static const char* routeStrings[] =
-{
- "EARPIECE ",
- "SPEAKER ",
- "BLUETOOTH ",
- "HEADSET "
-};
-static const char* routeNone = "NONE";
-
-static const char* displayMode(int mode)
-{
- if ((mode < -2) || (mode > 2))
- return routingModeStrings[0];
- return routingModeStrings[mode+3];
-}
-
-static const char* displayRoutes(uint32_t routes)
-{
- static char routeStr[80];
- if (routes == 0)
- return routeNone;
- routeStr[0] = 0;
- int bitMask = 1;
- for (int i = 0; i < 4; ++i, bitMask <<= 1) {
- if (routes & bitMask) {
- strcat(routeStr, routeStrings[i]);
- }
- }
- routeStr[strlen(routeStr)-1] = 0;
- return routeStr;
-}
-#endif
-
-// ----------------------------------------------------------------------------
-
-AudioHardwareInterface* AudioHardwareInterface::create()
-{
- /*
- * FIXME: This code needs to instantiate the correct audio device
- * interface. For now - we use compile-time switches.
- */
- AudioHardwareInterface* hw = 0;
- char value[PROPERTY_VALUE_MAX];
-
- hw = new AudioHardwareALSA();
-
- if (hw->initCheck() != NO_ERROR) {
- LOGW("Using stubbed audio hardware. No sound will be produced.");
- delete hw;
- hw = new AudioHardwareStub();
- }
-
-#ifdef DUMP_FLINGER_OUT
- // This code adds a record of buffers in a file to write calls made by AudioFlinger.
- // It replaces the current AudioHardwareInterface object by an intermediate one which
- // will record buffers in a file (after sending them to hardware) for testing purpose.
- // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement
- // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded
- // in the file.
-
- // read dump mode
- property_get("audioflinger.dump", value, "0");
- switch(value[0]) {
- case '1':
- LOGV("Dump mode");
- hw = new AudioDumpInterface(hw); // replace interface
- return hw;
- break;
- case '0':
- default:
- LOGV("No Dump mode");
- return hw;
- break;
- }
-#endif
- return hw;
-}
-
-AudioStreamOut::~AudioStreamOut()
-{
-}
-
-AudioStreamIn::~AudioStreamIn() {}
-
-AudioHardwareInterface::AudioHardwareInterface()
-{
- // force a routing update on initialization
- memset(&mRoutes, 0, sizeof(mRoutes));
- mMode = 0;
-}
-
-// generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
-{
-#if LOG_ROUTING_CALLS
- LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
-#endif
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- uint32_t old = mRoutes[mode];
- mRoutes[mode] = routes;
- if ((mode != mMode) || (old == routes))
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- const char* oldRouteStr = strdup(displayRoutes(old));
- LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
- displayMode(mode), oldRouteStr, displayRoutes(routes));
- delete oldRouteStr;
-#endif
- return doRouting();
-}
-
-status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
-{
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- *routes = mRoutes[mode];
-#if LOG_ROUTING_CALLS
- LOGD("getRouting: mode=%s, routes=[%s]",
- displayMode(mode), displayRoutes(*routes));
-#endif
- return NO_ERROR;
-}
-
-status_t AudioHardwareInterface::setMode(int mode)
-{
-#if LOG_ROUTING_CALLS
- LOGD("setMode(%s)", displayMode(mode));
-#endif
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- if (mMode == mode)
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
- displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
-#endif
- mMode = mode;
- return doRouting();
-}
-
-status_t AudioHardwareInterface::getMode(int* mode)
-{
- // Implement: set audio routing
- *mode = mMode;
- return NO_ERROR;
-}
-
-status_t AudioHardwareInterface::setParameter(const char* key, const char* value)
-{
- // default implementation is to ignore
- return NO_ERROR;
-}
-
-status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
- result.append(buffer);
- snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
- result.append(buffer);
- for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
- snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
- result.append(buffer);
- }
- ::write(fd, result.string(), result.size());
- dump(fd, args); // Dump the state of the concrete child.
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/AudioHardwareStub.cpp b/AudioHardwareStub.cpp
deleted file mode 100644
index 0046db8..0000000
--- a/AudioHardwareStub.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <utils/String8.h>
-
-#include "AudioHardwareStub.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
-{
-}
-
-AudioHardwareStub::~AudioHardwareStub()
-{
-}
-
-status_t AudioHardwareStub::initCheck()
-{
- return NO_ERROR;
-}
-
-status_t AudioHardwareStub::standby()
-{
- return NO_ERROR;
-}
-
-AudioStreamOut* AudioHardwareStub::openOutputStream(
- int format, int channelCount, uint32_t sampleRate)
-{
- AudioStreamOutStub* out = new AudioStreamOutStub();
- if (out->set(format, channelCount, sampleRate) == NO_ERROR)
- return out;
- delete out;
- return 0;
-}
-
-AudioStreamIn* AudioHardwareStub::openInputStream(
- int format, int channelCount, uint32_t sampleRate)
-{
- AudioStreamInStub* in = new AudioStreamInStub();
- if (in->set(format, channelCount, sampleRate) == NO_ERROR)
- return in;
- delete in;
- return 0;
-}
-
-status_t AudioHardwareStub::setVoiceVolume(float volume)
-{
- return NO_ERROR;
-}
-
-status_t AudioHardwareStub::setMasterVolume(float volume)
-{
- return NO_ERROR;
-}
-
-status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.append("AudioHardwareStub::dumpInternals\n");
- snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
- result.append(buffer);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
-{
- dumpInternals(fd, args);
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
-{
- // fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
-
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
-}
-
-ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
-{
- // fake timing for audio output
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
- return bytes;
-}
-
-status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
- snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
- snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
- snprintf(buffer, SIZE, "\tformat: %d\n", format());
- result.append(buffer);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
-{
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
-}
-
-ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
-{
- // fake timing for audio input
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
- memset(buffer, 0, bytes);
- return bytes;
-}
-
-status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
- result.append(buffer);
- snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
- result.append(buffer);
- snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
- result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
- result.append(buffer);
- snprintf(buffer, SIZE, "\tformat: %d\n", format());
- result.append(buffer);
- ::write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/AudioHardwareStub.h b/AudioHardwareStub.h
deleted file mode 100644
index 1a61552..0000000
--- a/AudioHardwareStub.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* //device/servers/AudioFlinger/AudioHardwareStub.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_AUDIO_HARDWARE_STUB_H
-#define ANDROID_AUDIO_HARDWARE_STUB_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <hardware/AudioHardwareInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class AudioStreamOutStub : public AudioStreamOut {
-public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
- virtual uint32_t sampleRate() const { return 44100; }
- virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
- virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual status_t setVolume(float volume) { return NO_ERROR; }
- virtual ssize_t write(const void* buffer, size_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
-};
-
-class AudioStreamInStub : public AudioStreamIn {
-public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
- virtual uint32_t sampleRate() const { return 8000; }
- virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
- virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual status_t setGain(float gain) { return NO_ERROR; }
- virtual ssize_t read(void* buffer, ssize_t bytes);
- virtual status_t dump(int fd, const Vector<String16>& args);
-};
-
-class AudioHardwareStub : public AudioHardwareInterface
-{
-public:
- AudioHardwareStub();
- virtual ~AudioHardwareStub();
- virtual status_t initCheck();
- virtual status_t standby();
- virtual status_t setVoiceVolume(float volume);
- virtual status_t setMasterVolume(float volume);
-
- // mic mute
- virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
- virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
-
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
- // create I/O streams
- virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0);
-
- virtual AudioStreamIn* openInputStream(
- int format,
- int channelCount,
- uint32_t sampleRate);
-
-protected:
- virtual status_t doRouting() { return NO_ERROR; }
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- bool mMicMute;
-private:
- status_t dumpInternals(int fd, const Vector<String16>& args);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_AUDIO_HARDWARE_STUB_H