/* //device/include/server/AudioFlinger/AudioFlinger.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.*/ #define LOG_TAG "AudioFlinger"//#define LOG_NDEBUG 0 #include <math.h>#include <signal.h>#include <sys/time.h>#include <sys/resource.h> #include <binder/IServiceManager.h>#include <utils/Log.h>#include <binder/Parcel.h>#include <binder/IPCThreadState.h>#include <utils/String16.h>#include <utils/threads.h> #include <cutils/properties.h> #include <media/AudioTrack.h>#include <media/AudioRecord.h> #include <private/media/AudioTrackShared.h>#include <private/media/AudioEffectShared.h>#include <hardware_legacy/AudioHardwareInterface.h> #include "AudioMixer.h"#include "AudioFlinger.h" #ifdef WITH_A2DP#include "A2dpAudioInterface.h"#endif #ifdef LVMX#include "lifevibes.h"#endif #include <media/EffectsFactoryApi.h>#include <media/EffectVisualizerApi.h> // ----------------------------------------------------------------------------// the sim build doesn't have gettid #ifndef HAVE_GETTID# define gettid getpid#endif // ---------------------------------------------------------------------------- extern const char * const gEffectLibPath; namespace android { static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n";static const char* kHardwareLockedString = "Hardware lock is taken\n"; //static const nsecs_t kStandbyTimeInNsecs = seconds(3);static const float MAX_GAIN = 4096.0f;static const float MAX_GAIN_INT = 0x1000; // retry counts for buffer fill timeout// 50 * ~20msecs = 1 secondstatic const int8_t kMaxTrackRetries = 50;static const int8_t kMaxTrackStartupRetries = 50;// allow less retry attempts on direct output thread.// direct outputs can be a scarce resource in audio hardware and should// be released as quickly as possible.static const int8_t kMaxTrackRetriesDirect = 2; static const int kDumpLockRetries = 50;static const int kDumpLockSleep = 20000; static const nsecs_t kWarningThrottle = seconds(5); #define AUDIOFLINGER_SECURITY_ENABLED 0 // ---------------------------------------------------------------------------- static bool recordingAllowed() {#ifndef HAVE_ANDROID_OS return true;#endif#if AUDIOFLINGER_SECURITY_ENABLED if (getpid() == IPCThreadState::self()->getCallingPid()) return true; bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO")); if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO"); return ok;#else return true;#endif} static bool settingsAllowed() {#ifndef HAVE_ANDROID_OS return true;#endif#if AUDIOFLINGER_SECURITY_ENABLED if (getpid() == IPCThreadState::self()->getCallingPid()) return true; bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); return ok;#else return true;#endif} // ---------------------------------------------------------------------------- AudioFlinger::AudioFlinger() : BnAudioFlinger(), mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1){ mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface::create(); mHardwareStatus = AUDIO_HW_INIT; if (mAudioHardware->initCheck() == NO_ERROR) { // open 16-bit output stream for s/w mixer mMode = AudioSystem::MODE_NORMAL; setMode(mMode); setMasterVolume(1.0f); setMasterMute(false); } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); }#ifdef LVMX LifeVibes::init(); mLifeVibesClientPid = -1;#endif} AudioFlinger::~AudioFlinger(){ while (!mRecordThreads.isEmpty()) { // closeInput() will remove first entry from mRecordThreads closeInput(mRecordThreads.keyAt(0)); } while (!mPlaybackThreads.isEmpty()) { // closeOutput() will remove first entry from mPlaybackThreads closeOutput(mPlaybackThreads.keyAt(0)); } if (mAudioHardware) { delete mAudioHardware; }} status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args){ const size_t SIZE = 256; char buffer[SIZE]; String8 result; result.append("Clients:\n"); for (size_t i = 0; i < mClients.size(); ++i) { wp<Client> wClient = mClients.valueAt(i); if (wClient != 0) { sp<Client> client = wClient.promote(); if (client != 0) { snprintf(buffer, SIZE, " pid: %d\n", client->pid()); result.append(buffer); } } } write(fd, result.string(), result.size()); return NO_ERROR;} status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args){ const size_t SIZE = 256; char buffer[SIZE]; String8 result; int hardwareStatus = mHardwareStatus; snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus); result.append(buffer); write(fd, result.string(), result.size()); return NO_ERROR;} status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args){ const size_t SIZE = 256; char buffer[SIZE]; String8 result; snprintf(buffer, SIZE, "Permission Denial: " "can't dump AudioFlinger from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); result.append(buffer); write(fd, result.string(), result.size()); return NO_ERROR;} static bool tryLock(Mutex& mutex){ bool locked = false; for (int i = 0; i < kDumpLockRetries; ++i) { if (mutex.tryLock() == NO_ERROR) { locked = true; break; } usleep(kDumpLockSleep); } return locked;} status_t AudioFlinger::dump(int fd, const Vector<String16>& args){ if (checkCallingPermission(String16("android.permission.DUMP")) == false) { dumpPermissionDenial(fd, args); } else { // get state of hardware lock bool hardwareLocked = tryLock(mHardwareLock); if (!hardwareLocked) { String8 result(kHardwareLockedString); write(fd, result.string(), result.size()); } else { mHardwareLock.unlock(); } bool locked = tryLock(mLock); // failed to lock - AudioFlinger is probably deadlocked if (!locked) { String8 result(kDeadlockedString); write(fd, result.string(), result.size()); } dumpClients(fd, args); dumpInternals(fd, args); // dump playback threads for (size_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->dump(fd, args); } // dump record threads for (size_t i = 0; i < mRecordThreads.size(); i++) { mRecordThreads.valueAt(i)->dump(fd, args); } if (mAudioHardware) { mAudioHardware->dumpState(fd, args); } if (locked) mLock.unlock(); } return NO_ERROR;} // IAudioFlinger interface sp<IAudioTrack> AudioFlinger::createTrack( pid_t pid, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, int output, int *sessionId, status_t *status){ sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; wp<Client> wclient; status_t lStatus; int lSessionId; if (streamType >= AudioSystem::NUM_STREAM_TYPES) { LOGE("invalid stream type"); lStatus = BAD_VALUE; goto Exit; } { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); PlaybackThread *effectThread = NULL; if (thread == NULL) { LOGE("unknown output thread"); lStatus = BAD_VALUE; goto Exit; } wclient = mClients.valueFor(pid); if (wclient != NULL) { client = wclient.promote(); } else { client = new Client(this, pid); mClients.add(pid, client); } LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { // prevent same audio session on different output threads uint32_t sessions = t->hasAudioSession(*sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { lStatus = BAD_VALUE; goto Exit; } // check if an effect with same session ID is waiting for a track to be created if (sessions & PlaybackThread::EFFECT_SESSION) { effectThread = t.get(); } } } lSessionId = *sessionId; } else { // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } } LOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, lSessionId, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created if (lStatus == NO_ERROR && effectThread != NULL) { Mutex::Autolock _dl(thread->mLock); Mutex::Autolock _sl(effectThread->mLock); moveEffectChain_l(lSessionId, effectThread, thread, true); } } if (lStatus == NO_ERROR) { trackHandle = new TrackHandle(track); } else { // remove local strong reference to Client before deleting the Track so that the Client // destructor is called by the TrackBase destructor with mLock held client.clear(); track.clear(); } Exit: if(status) { *status = lStatus; } return trackHandle;} uint32_t AudioFlinger::sampleRate(int output) const{ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("sampleRate() unknown thread %d", output); return 0; } return thread->sampleRate();} int AudioFlinger::channelCount(int output) const{ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("channelCount() unknown thread %d", output); return 0; } return thread->channelCount();} int AudioFlinger::format(int output) const{ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("format() unknown thread %d", output); return 0; } return thread->format();} size_t AudioFlinger::frameCount(int output) const{ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("frameCount() unknown thread %d", output); return 0; } return thread->frameCount();} uint32_t AudioFlinger::latency(int output) const{ Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("latency() unknown thread %d", output); return 0; } return thread->latency();} status_t AudioFlinger::setMasterVolume(float value){ // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } // when hw supports master volume, don't scale in sw mixer AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; if (mAudioHardware->setMasterVolume(value) == NO_ERROR) { value = 1.0f; } mHardwareStatus = AUDIO_HW_IDLE; mMasterVolume = value; for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMasterVolume(value); return NO_ERROR;} status_t AudioFlinger::setMode(int mode){ status_t ret; // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { LOGW("Illegal value: setMode(%d)", mode); return BAD_VALUE; } { // scope for the lock AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MODE; ret = mAudioHardware->setMode(mode); mHardwareStatus = AUDIO_HW_IDLE; } if (NO_ERROR == ret) { Mutex::Autolock _l(mLock); mMode = mode; for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMode(mode);#ifdef LVMX LifeVibes::setMode(mode);#endif } return ret;} status_t AudioFlinger::setMicMute(bool state){ // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; status_t ret = mAudioHardware->setMicMute(state); mHardwareStatus = AUDIO_HW_IDLE; return ret;} bool AudioFlinger::getMicMute() constLines 1–500 of 6464. Load more
/* //device/include/server/AudioFlinger/AudioFlinger.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. */ #define LOG_TAG "AudioFlinger" //#define LOG_NDEBUG 0 #include <math.h> #include <signal.h> #include <sys/time.h> #include <sys/resource.h> #include <binder/IServiceManager.h> #include <utils/Log.h> #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/String16.h> #include <utils/threads.h> #include <cutils/properties.h> #include <media/AudioTrack.h> #include <media/AudioRecord.h> #include <private/media/AudioTrackShared.h> #include <private/media/AudioEffectShared.h> #include <hardware_legacy/AudioHardwareInterface.h> #include "AudioMixer.h" #include "AudioFlinger.h" #ifdef WITH_A2DP #include "A2dpAudioInterface.h" #endif #ifdef LVMX #include "lifevibes.h" #endif #include <media/EffectsFactoryApi.h> #include <media/EffectVisualizerApi.h> // ---------------------------------------------------------------------------- // the sim build doesn't have gettid #ifndef HAVE_GETTID # define gettid getpid #endif // ---------------------------------------------------------------------------- extern const char * const gEffectLibPath; namespace android { static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; static const char* kHardwareLockedString = "Hardware lock is taken\n"; //static const nsecs_t kStandbyTimeInNsecs = seconds(3); static const float MAX_GAIN = 4096.0f; static const float MAX_GAIN_INT = 0x1000; // retry counts for buffer fill timeout // 50 * ~20msecs = 1 second static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; // allow less retry attempts on direct output thread. // direct outputs can be a scarce resource in audio hardware and should // be released as quickly as possible. static const int8_t kMaxTrackRetriesDirect = 2; static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 20000; static const nsecs_t kWarningThrottle = seconds(5); #define AUDIOFLINGER_SECURITY_ENABLED 0 // ---------------------------------------------------------------------------- static bool recordingAllowed() { #ifndef HAVE_ANDROID_OS return true; #endif #if AUDIOFLINGER_SECURITY_ENABLED if (getpid() == IPCThreadState::self()->getCallingPid()) return true; bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO")); if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO"); return ok; #else return true; #endif } static bool settingsAllowed() { #ifndef HAVE_ANDROID_OS return true; #endif #if AUDIOFLINGER_SECURITY_ENABLED if (getpid() == IPCThreadState::self()->getCallingPid()) return true; bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")); if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); return ok; #else return true; #endif } // ---------------------------------------------------------------------------- AudioFlinger::AudioFlinger() : BnAudioFlinger(), mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1) { mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface::create(); mHardwareStatus = AUDIO_HW_INIT; if (mAudioHardware->initCheck() == NO_ERROR) { // open 16-bit output stream for s/w mixer mMode = AudioSystem::MODE_NORMAL; setMode(mMode); setMasterVolume(1.0f); setMasterMute(false); } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); } #ifdef LVMX LifeVibes::init(); mLifeVibesClientPid = -1; #endif } AudioFlinger::~AudioFlinger() { while (!mRecordThreads.isEmpty()) { // closeInput() will remove first entry from mRecordThreads closeInput(mRecordThreads.keyAt(0)); } while (!mPlaybackThreads.isEmpty()) { // closeOutput() will remove first entry from mPlaybackThreads closeOutput(mPlaybackThreads.keyAt(0)); } if (mAudioHardware) { delete mAudioHardware; } } status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; result.append("Clients:\n"); for (size_t i = 0; i < mClients.size(); ++i) { wp<Client> wClient = mClients.valueAt(i); if (wClient != 0) { sp<Client> client = wClient.promote(); if (client != 0) { snprintf(buffer, SIZE, " pid: %d\n", client->pid()); result.append(buffer); } } } write(fd, result.string(), result.size()); return NO_ERROR; } status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; int hardwareStatus = mHardwareStatus; snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus); result.append(buffer); write(fd, result.string(), result.size()); return NO_ERROR; } status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; snprintf(buffer, SIZE, "Permission Denial: " "can't dump AudioFlinger from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); result.append(buffer); write(fd, result.string(), result.size()); return NO_ERROR; } static bool tryLock(Mutex& mutex) { bool locked = false; for (int i = 0; i < kDumpLockRetries; ++i) { if (mutex.tryLock() == NO_ERROR) { locked = true; break; } usleep(kDumpLockSleep); } return locked; } status_t AudioFlinger::dump(int fd, const Vector<String16>& args) { if (checkCallingPermission(String16("android.permission.DUMP")) == false) { dumpPermissionDenial(fd, args); } else { // get state of hardware lock bool hardwareLocked = tryLock(mHardwareLock); if (!hardwareLocked) { String8 result(kHardwareLockedString); write(fd, result.string(), result.size()); } else { mHardwareLock.unlock(); } bool locked = tryLock(mLock); // failed to lock - AudioFlinger is probably deadlocked if (!locked) { String8 result(kDeadlockedString); write(fd, result.string(), result.size()); } dumpClients(fd, args); dumpInternals(fd, args); // dump playback threads for (size_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->dump(fd, args); } // dump record threads for (size_t i = 0; i < mRecordThreads.size(); i++) { mRecordThreads.valueAt(i)->dump(fd, args); } if (mAudioHardware) { mAudioHardware->dumpState(fd, args); } if (locked) mLock.unlock(); } return NO_ERROR; } // IAudioFlinger interface sp<IAudioTrack> AudioFlinger::createTrack( pid_t pid, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, int output, int *sessionId, status_t *status) { sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; wp<Client> wclient; status_t lStatus; int lSessionId; if (streamType >= AudioSystem::NUM_STREAM_TYPES) { LOGE("invalid stream type"); lStatus = BAD_VALUE; goto Exit; } { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); PlaybackThread *effectThread = NULL; if (thread == NULL) { LOGE("unknown output thread"); lStatus = BAD_VALUE; goto Exit; } wclient = mClients.valueFor(pid); if (wclient != NULL) { client = wclient.promote(); } else { client = new Client(this, pid); mClients.add(pid, client); } LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { sp<PlaybackThread> t = mPlaybackThreads.valueAt(i); if (mPlaybackThreads.keyAt(i) != output) { // prevent same audio session on different output threads uint32_t sessions = t->hasAudioSession(*sessionId); if (sessions & PlaybackThread::TRACK_SESSION) { lStatus = BAD_VALUE; goto Exit; } // check if an effect with same session ID is waiting for a track to be created if (sessions & PlaybackThread::EFFECT_SESSION) { effectThread = t.get(); } } } lSessionId = *sessionId; } else { // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } } LOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, lSessionId, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created if (lStatus == NO_ERROR && effectThread != NULL) { Mutex::Autolock _dl(thread->mLock); Mutex::Autolock _sl(effectThread->mLock); moveEffectChain_l(lSessionId, effectThread, thread, true); } } if (lStatus == NO_ERROR) { trackHandle = new TrackHandle(track); } else { // remove local strong reference to Client before deleting the Track so that the Client // destructor is called by the TrackBase destructor with mLock held client.clear(); track.clear(); } Exit: if(status) { *status = lStatus; } return trackHandle; } uint32_t AudioFlinger::sampleRate(int output) const { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("sampleRate() unknown thread %d", output); return 0; } return thread->sampleRate(); } int AudioFlinger::channelCount(int output) const { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("channelCount() unknown thread %d", output); return 0; } return thread->channelCount(); } int AudioFlinger::format(int output) const { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("format() unknown thread %d", output); return 0; } return thread->format(); } size_t AudioFlinger::frameCount(int output) const { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("frameCount() unknown thread %d", output); return 0; } return thread->frameCount(); } uint32_t AudioFlinger::latency(int output) const { Mutex::Autolock _l(mLock); PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { LOGW("latency() unknown thread %d", output); return 0; } return thread->latency(); } status_t AudioFlinger::setMasterVolume(float value) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } // when hw supports master volume, don't scale in sw mixer AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; if (mAudioHardware->setMasterVolume(value) == NO_ERROR) { value = 1.0f; } mHardwareStatus = AUDIO_HW_IDLE; mMasterVolume = value; for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMasterVolume(value); return NO_ERROR; } status_t AudioFlinger::setMode(int mode) { status_t ret; // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { LOGW("Illegal value: setMode(%d)", mode); return BAD_VALUE; } { // scope for the lock AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MODE; ret = mAudioHardware->setMode(mode); mHardwareStatus = AUDIO_HW_IDLE; } if (NO_ERROR == ret) { Mutex::Autolock _l(mLock); mMode = mode; for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMode(mode); #ifdef LVMX LifeVibes::setMode(mode); #endif } return ret; } status_t AudioFlinger::setMicMute(bool state) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; status_t ret = mAudioHardware->setMicMute(state); mHardwareStatus = AUDIO_HW_IDLE; return ret; } bool AudioFlinger::getMicMute() const