From 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: auto import from //depot/cupcake/@135843 --- media/libmedia/AudioSystem.cpp | 383 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 media/libmedia/AudioSystem.cpp (limited to 'media/libmedia/AudioSystem.cpp') diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp new file mode 100644 index 0000000..63dfc3b --- /dev/null +++ b/media/libmedia/AudioSystem.cpp @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2006-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. + */ + +#define LOG_TAG "AudioSystem" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include + +namespace android { + +// client singleton for AudioFlinger binder interface +Mutex AudioSystem::gLock; +sp AudioSystem::gAudioFlinger; +sp AudioSystem::gAudioFlingerClient; +audio_error_callback AudioSystem::gAudioErrorCallback = NULL; +// Cached values +int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES]; +int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES]; +uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES]; +bool AudioSystem::gA2dpEnabled; +// Cached values for recording queries +uint32_t AudioSystem::gPrevInSamplingRate = 16000; +int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT; +int AudioSystem::gPrevInChannelCount = 1; +size_t AudioSystem::gInBuffSize = 0; + + +// establish binder interface to AudioFlinger service +const sp& AudioSystem::get_audio_flinger() +{ + Mutex::Autolock _l(gLock); + if (gAudioFlinger.get() == 0) { + sp sm = defaultServiceManager(); + sp binder; + do { + binder = sm->getService(String16("media.audio_flinger")); + if (binder != 0) + break; + LOGW("AudioFlinger not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + if (gAudioFlingerClient == NULL) { + gAudioFlingerClient = new AudioFlingerClient(); + } else { + if (gAudioErrorCallback) { + gAudioErrorCallback(NO_ERROR); + } + } + binder->linkToDeath(gAudioFlingerClient); + gAudioFlinger = interface_cast(binder); + gAudioFlinger->registerClient(gAudioFlingerClient); + // Cache frequently accessed parameters + for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) { + gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output); + gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output); + gOutLatency[output] = gAudioFlinger->latency(output); + } + gA2dpEnabled = gAudioFlinger->isA2dpEnabled(); + } + LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?"); + return gAudioFlinger; +} + +// routing helper functions +status_t AudioSystem::speakerphone(bool state) { + uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE; + return setRouting(MODE_IN_CALL, routes, ROUTE_ALL); +} + +status_t AudioSystem::isSpeakerphoneOn(bool* state) { + uint32_t routes = 0; + status_t s = getRouting(MODE_IN_CALL, &routes); + *state = !!(routes & ROUTE_SPEAKER); + return s; +} + +status_t AudioSystem::bluetoothSco(bool state) { + uint32_t mask = ROUTE_BLUETOOTH_SCO; + uint32_t routes = state ? mask : ROUTE_EARPIECE; + return setRouting(MODE_IN_CALL, routes, ROUTE_ALL); +} + +status_t AudioSystem::isBluetoothScoOn(bool* state) { + uint32_t routes = 0; + status_t s = getRouting(MODE_IN_CALL, &routes); + *state = !!(routes & ROUTE_BLUETOOTH_SCO); + return s; +} + +status_t AudioSystem::muteMicrophone(bool state) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setMicMute(state); +} + +status_t AudioSystem::isMicrophoneMuted(bool* state) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *state = af->getMicMute(); + return NO_ERROR; +} + +status_t AudioSystem::setMasterVolume(float value) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setMasterVolume(value); + return NO_ERROR; +} + +status_t AudioSystem::setMasterMute(bool mute) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setMasterMute(mute); + return NO_ERROR; +} + +status_t AudioSystem::getMasterVolume(float* volume) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *volume = af->masterVolume(); + return NO_ERROR; +} + +status_t AudioSystem::getMasterMute(bool* mute) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mute = af->masterMute(); + return NO_ERROR; +} + +status_t AudioSystem::setStreamVolume(int stream, float value) +{ + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setStreamVolume(stream, value); + return NO_ERROR; +} + +status_t AudioSystem::setStreamMute(int stream, bool mute) +{ + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setStreamMute(stream, mute); + return NO_ERROR; +} + +status_t AudioSystem::getStreamVolume(int stream, float* volume) +{ + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *volume = af->streamVolume(stream); + return NO_ERROR; +} + +status_t AudioSystem::getStreamMute(int stream, bool* mute) +{ + if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mute = af->streamMute(stream); + return NO_ERROR; +} + +status_t AudioSystem::setMode(int mode) +{ + if (mode >= NUM_MODES) return BAD_VALUE; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setMode(mode); +} + +status_t AudioSystem::getMode(int* mode) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mode = af->getMode(); + return NO_ERROR; +} + +status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setRouting(mode, routes, mask); +} + +status_t AudioSystem::getRouting(int mode, uint32_t* routes) +{ + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + uint32_t r = af->getRouting(mode); + *routes = r; + return NO_ERROR; +} + +status_t AudioSystem::isMusicActive(bool* state) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *state = af->isMusicActive(); + return NO_ERROR; +} + +// Temporary interface, do not use +// TODO: Replace with a more generic key:value get/set mechanism +status_t AudioSystem::setParameter(const char* key, const char* value) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setParameter(key, value); +} + +// convert volume steps to natural log scale + +// change this value to change volume scaling +static const float dBPerStep = 0.5f; +// shouldn't need to touch these +static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f; +static const float dBConvertInverse = 1.0f / dBConvert; + +float AudioSystem::linearToLog(int volume) +{ + // float v = volume ? exp(float(100 - volume) * dBConvert) : 0; + // LOGD("linearToLog(%d)=%f", volume, v); + // return v; + return volume ? exp(float(100 - volume) * dBConvert) : 0; +} + +int AudioSystem::logToLinear(float volume) +{ + // int v = volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; + // LOGD("logTolinear(%d)=%f", v, volume); + // return v; + return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; +} + +status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) +{ + int output = getOutput(streamType); + + if (gOutSamplingRate[output] == 0) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + // gOutSamplingRate is updated by get_audio_flinger() + } + LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]); + *samplingRate = gOutSamplingRate[output]; + + return NO_ERROR; +} + +status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) +{ + int output = getOutput(streamType); + + if (gOutFrameCount[output] == 0) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + // gOutFrameCount is updated by get_audio_flinger() + } + LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]); + + *frameCount = gOutFrameCount[output]; + return NO_ERROR; +} + +status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) +{ + int output = getOutput(streamType); + + if (gOutLatency[output] == 0) { + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + // gOutLatency is updated by get_audio_flinger() + } + LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]); + + *latency = gOutLatency[output]; + + return NO_ERROR; +} + +status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount, + size_t* buffSize) +{ + // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values + if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) + || (channelCount != gPrevInChannelCount)) { + // save the request params + gPrevInSamplingRate = sampleRate; + gPrevInFormat = format; + gPrevInChannelCount = channelCount; + + gInBuffSize = 0; + const sp& af = AudioSystem::get_audio_flinger(); + if (af == 0) { + return PERMISSION_DENIED; + } + gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount); + } + *buffSize = gInBuffSize; + + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +void AudioSystem::AudioFlingerClient::binderDied(const wp& who) { + Mutex::Autolock _l(AudioSystem::gLock); + AudioSystem::gAudioFlinger.clear(); + + for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) { + gOutFrameCount[output] = 0; + gOutSamplingRate[output] = 0; + gOutLatency[output] = 0; + } + AudioSystem::gInBuffSize = 0; + + if (gAudioErrorCallback) { + gAudioErrorCallback(DEAD_OBJECT); + } + LOGW("AudioFlinger server died!"); +} + +void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) { + gA2dpEnabled = enabled; + LOGV("AudioFlinger A2DP enabled status changed! %d", enabled); +} + +void AudioSystem::setErrorCallback(audio_error_callback cb) { + Mutex::Autolock _l(AudioSystem::gLock); + gAudioErrorCallback = cb; +} + +int AudioSystem::getOutput(int streamType) +{ + if (streamType == DEFAULT) { + streamType = MUSIC; + } + if (gA2dpEnabled && routedToA2dpOutput(streamType)) { + return AUDIO_OUTPUT_A2DP; + } else { + return AUDIO_OUTPUT_HARDWARE; + } +} + +bool AudioSystem::routedToA2dpOutput(int streamType) { + switch(streamType) { + case MUSIC: + case VOICE_CALL: + case BLUETOOTH_SCO: + case SYSTEM: + return true; + default: + return false; + } +} + + + +}; // namespace android + -- cgit v1.1