diff options
Diffstat (limited to 'libs/audioflinger/AudioFlinger.cpp')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 2471 |
1 files changed, 0 insertions, 2471 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp deleted file mode 100644 index 557d93b..0000000 --- a/libs/audioflinger/AudioFlinger.cpp +++ /dev/null @@ -1,2471 +0,0 @@ -/* //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 <utils/IServiceManager.h> -#include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/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 <hardware_legacy/AudioHardwareInterface.h> - -#include "AudioMixer.h" -#include "AudioFlinger.h" - -#ifdef WITH_A2DP -#include "A2dpAudioInterface.h" -#endif - -// ---------------------------------------------------------------------------- -// the sim build doesn't have gettid - -#ifndef HAVE_GETTID -# define gettid getpid -#endif - -// ---------------------------------------------------------------------------- - -namespace android { - -//static const nsecs_t kStandbyTimeInNsecs = seconds(3); -static const unsigned long kBufferRecoveryInUsecs = 2000; -static const unsigned long kMaxBufferRecoveryInUsecs = 20000; -static const float MAX_GAIN = 4096.0f; - -// retry counts for buffer fill timeout -// 50 * ~20msecs = 1 second -static const int8_t kMaxTrackRetries = 50; -static const int8_t kMaxTrackStartupRetries = 50; - -static const int kStartSleepTime = 30000; -static const int kStopSleepTime = 30000; - -// Maximum number of pending buffers allocated by OutputTrack::write() -static const uint8_t kMaxOutputTrackBuffers = 5; - - -#define AUDIOFLINGER_SECURITY_ENABLED 1 - -// ---------------------------------------------------------------------------- - -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 - if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO"))) - LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest"); - 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 - if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"))) - LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest"); - return true; -#endif -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::AudioFlinger() - : BnAudioFlinger(), - mAudioHardware(0), mA2dpAudioInterface(0), - mA2dpEnabled(false), mA2dpEnabledReq(false), - mForcedSpeakerCount(0), mForcedRoute(0), mRouteRestoreTime(0), mMusicMuteSaved(false) -{ - 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 - mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; - status_t status; - AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); - mHardwareStatus = AUDIO_HW_IDLE; - if (hwOutput) { - mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE); - } else { - LOGE("Failed to initialize hardware output stream, status: %d", status); - } - -#ifdef WITH_A2DP - // Create A2DP interface - mA2dpAudioInterface = new A2dpAudioInterface(); - AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); - if (a2dpOutput) { - mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP); - if (hwOutput) { - uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate(); - MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread, - hwOutput->sampleRate(), - AudioSystem::PCM_16_BIT, - hwOutput->channelCount(), - frameCount); - mHardwareMixerThread->setOuputTrack(a2dpOutTrack); - } - } else { - LOGE("Failed to initialize A2DP output stream, status: %d", status); - } -#endif - - // FIXME - this should come from settings - setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); - setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL); - setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL); - setMode(AudioSystem::MODE_NORMAL); - - setMasterVolume(1.0f); - setMasterMute(false); - - // Start record thread - mAudioRecordThread = new AudioRecordThread(mAudioHardware); - if (mAudioRecordThread != 0) { - mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); - } - } else { - LOGE("Couldn't even initialize the stubbed audio hardware!"); - } - - char value[PROPERTY_VALUE_MAX]; - property_get("ro.audio.silent", value, "0"); - if (atoi(value)) { - LOGD("Silence is golden"); - setMasterMute(true); - } -} - -AudioFlinger::~AudioFlinger() -{ - if (mAudioRecordThread != 0) { - mAudioRecordThread->exit(); - mAudioRecordThread.clear(); - } - mHardwareMixerThread.clear(); - delete mAudioHardware; - // deleting mA2dpAudioInterface also deletes mA2dpOutput; -#ifdef WITH_A2DP - mA2dpMixerThread.clear(); - delete mA2dpAudioInterface; -#endif -} - - -#ifdef WITH_A2DP -void AudioFlinger::setA2dpEnabled(bool enable) -{ - LOGV_IF(enable, "set output to A2DP\n"); - LOGV_IF(!enable, "set output to hardware audio\n"); - - mA2dpEnabledReq = enable; - mA2dpMixerThread->wakeUp(); -} -#endif // WITH_A2DP - -bool AudioFlinger::streamForcedToSpeaker(int streamType) -{ - // NOTE that streams listed here must not be routed to A2DP by default: - // AudioSystem::routedToA2dpOutput(streamType) == false - return (streamType == AudioSystem::RING || - streamType == AudioSystem::ALARM || - streamType == AudioSystem::NOTIFICATION); -} - -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; - - snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus); - 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; -} - -status_t AudioFlinger::dump(int fd, const Vector<String16>& args) -{ - if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - dumpPermissionDenial(fd, args); - } else { - AutoMutex lock(&mLock); - - dumpClients(fd, args); - dumpInternals(fd, args); - mHardwareMixerThread->dump(fd, args); -#ifdef WITH_A2DP - mA2dpMixerThread->dump(fd, args); -#endif - - // dump record client - if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args); - - if (mAudioHardware) { - mAudioHardware->dumpState(fd, args); - } - } - 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, - status_t *status) -{ - sp<MixerThread::Track> track; - sp<TrackHandle> trackHandle; - sp<Client> client; - wp<Client> wclient; - status_t lStatus; - - if (streamType >= AudioSystem::NUM_STREAM_TYPES) { - LOGE("invalid stream type"); - lStatus = BAD_VALUE; - goto Exit; - } - - { - Mutex::Autolock _l(mLock); - - wclient = mClients.valueFor(pid); - - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } -#ifdef WITH_A2DP - if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) { - track = mA2dpMixerThread->createTrack(client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer, &lStatus); - } else -#endif - { - track = mHardwareMixerThread->createTrack(client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer, &lStatus); - } - if (track != NULL) { - trackHandle = new TrackHandle(track); - lStatus = NO_ERROR; - } - } - -Exit: - if(status) { - *status = lStatus; - } - return trackHandle; -} - -uint32_t AudioFlinger::sampleRate(int output) const -{ -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->sampleRate(); - } -#endif - return mHardwareMixerThread->sampleRate(); -} - -int AudioFlinger::channelCount(int output) const -{ -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->channelCount(); - } -#endif - return mHardwareMixerThread->channelCount(); -} - -int AudioFlinger::format(int output) const -{ -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->format(); - } -#endif - return mHardwareMixerThread->format(); -} - -size_t AudioFlinger::frameCount(int output) const -{ -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->frameCount(); - } -#endif - return mHardwareMixerThread->frameCount(); -} - -uint32_t AudioFlinger::latency(int output) const -{ -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->latency(); - } -#endif - return mHardwareMixerThread->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; - mHardwareMixerThread->setMasterVolume(value); -#ifdef WITH_A2DP - mA2dpMixerThread->setMasterVolume(value); -#endif - - return NO_ERROR; -} - -status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask) -{ - status_t err = NO_ERROR; - - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) { - LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask); - return BAD_VALUE; - } - -#ifdef WITH_A2DP - LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid()); - if (mode == AudioSystem::MODE_NORMAL && - (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) { - AutoMutex lock(&mLock); - - bool enableA2dp = false; - if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) { - enableA2dp = true; - } - setA2dpEnabled(enableA2dp); - LOGV("setOutput done\n"); - } -#endif - - // do nothing if only A2DP routing is affected - mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP; - if (mask) { - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_GET_ROUTING; - uint32_t r; - err = mAudioHardware->getRouting(mode, &r); - if (err == NO_ERROR) { - r = (r & ~mask) | (routes & mask); - if (mode == AudioSystem::MODE_NORMAL || - (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) { - mSavedRoute = r; - r |= mForcedRoute; - LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute); - } - mHardwareStatus = AUDIO_HW_SET_ROUTING; - err = mAudioHardware->setRouting(mode, r); - } - mHardwareStatus = AUDIO_HW_IDLE; - } - return err; -} - -uint32_t AudioFlinger::getRouting(int mode) const -{ - uint32_t routes = 0; - if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) { - if (mode == AudioSystem::MODE_NORMAL || - (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) { - routes = mSavedRoute; - } else { - mHardwareStatus = AUDIO_HW_GET_ROUTING; - mAudioHardware->getRouting(mode, &routes); - mHardwareStatus = AUDIO_HW_IDLE; - } - } else { - LOGW("Illegal value: getRouting(%d)", mode); - } - return routes; -} - -status_t AudioFlinger::setMode(int mode) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) { - LOGW("Illegal value: setMode(%d)", mode); - return BAD_VALUE; - } - - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MODE; - status_t ret = mAudioHardware->setMode(mode); - mHardwareStatus = AUDIO_HW_IDLE; - return ret; -} - -int AudioFlinger::getMode() const -{ - int mode = AudioSystem::MODE_INVALID; - mHardwareStatus = AUDIO_HW_SET_MODE; - mAudioHardware->getMode(&mode); - mHardwareStatus = AUDIO_HW_IDLE; - return mode; -} - -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 -{ - bool state = AudioSystem::MODE_INVALID; - mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; - mAudioHardware->getMicMute(&state); - mHardwareStatus = AUDIO_HW_IDLE; - return state; -} - -status_t AudioFlinger::setMasterMute(bool muted) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - mHardwareMixerThread->setMasterMute(muted); -#ifdef WITH_A2DP - mA2dpMixerThread->setMasterMute(muted); -#endif - return NO_ERROR; -} - -float AudioFlinger::masterVolume() const -{ - return mHardwareMixerThread->masterVolume(); -} - -bool AudioFlinger::masterMute() const -{ - return mHardwareMixerThread->masterMute(); -} - -status_t AudioFlinger::setStreamVolume(int stream, float value) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - - mHardwareMixerThread->setStreamVolume(stream, value); -#ifdef WITH_A2DP - mA2dpMixerThread->setStreamVolume(stream, value); -#endif - - status_t ret = NO_ERROR; - if (stream == AudioSystem::VOICE_CALL || - stream == AudioSystem::BLUETOOTH_SCO) { - - if (stream == AudioSystem::VOICE_CALL) { - value = (float)AudioSystem::logToLinear(value)/100.0f; - } else { // (type == AudioSystem::BLUETOOTH_SCO) - value = 1.0f; - } - - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_VOICE_VOLUME; - ret = mAudioHardware->setVoiceVolume(value); - mHardwareStatus = AUDIO_HW_IDLE; - } - - return ret; -} - -status_t AudioFlinger::setStreamMute(int stream, bool muted) -{ - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - -#ifdef WITH_A2DP - mA2dpMixerThread->setStreamMute(stream, muted); -#endif - if (stream == AudioSystem::MUSIC) - { - AutoMutex lock(&mHardwareLock); - if (mForcedRoute != 0) - mMusicMuteSaved = muted; - else - mHardwareMixerThread->setStreamMute(stream, muted); - } else { - mHardwareMixerThread->setStreamMute(stream, muted); - } - - - - return NO_ERROR; -} - -float AudioFlinger::streamVolume(int stream) const -{ - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return 0.0f; - } - return mHardwareMixerThread->streamVolume(stream); -} - -bool AudioFlinger::streamMute(int stream) const -{ - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { - return true; - } - - if (stream == AudioSystem::MUSIC && mForcedRoute != 0) - { - return mMusicMuteSaved; - } - return mHardwareMixerThread->streamMute(stream); -} - -bool AudioFlinger::isMusicActive() const -{ - #ifdef WITH_A2DP - if (isA2dpEnabled()) { - return mA2dpMixerThread->isMusicActive(); - } - #endif - return mHardwareMixerThread->isMusicActive(); -} - -status_t AudioFlinger::setParameter(const char* key, const char* value) -{ - status_t result, result2; - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_PARAMETER; - - LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid()); - result = mAudioHardware->setParameter(key, value); - if (mA2dpAudioInterface) { - result2 = mA2dpAudioInterface->setParameter(key, value); - if (result2) - result = result2; - } - mHardwareStatus = AUDIO_HW_IDLE; - return result; -} - -size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) -{ - return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); -} - -void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) -{ - - LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mLock); - - sp<IBinder> binder = client->asBinder(); - if (mNotificationClients.indexOf(binder) < 0) { - LOGV("Adding notification client %p", binder.get()); - binder->linkToDeath(this); - mNotificationClients.add(binder); - client->a2dpEnabledChanged(isA2dpEnabled()); - } -} - -void AudioFlinger::binderDied(const wp<IBinder>& who) { - - LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mLock); - - IBinder *binder = who.unsafe_get(); - - if (binder != NULL) { - int index = mNotificationClients.indexOf(binder); - if (index >= 0) { - LOGV("Removing notification client %p", binder); - mNotificationClients.removeAt(index); - } - } -} - -void AudioFlinger::handleOutputSwitch() -{ - if (mA2dpEnabled != mA2dpEnabledReq) - { - Mutex::Autolock _l(mLock); - - if (mA2dpEnabled != mA2dpEnabledReq) - { - mA2dpEnabled = mA2dpEnabledReq; - SortedVector < sp<MixerThread::Track> > tracks; - SortedVector < wp<MixerThread::Track> > activeTracks; - - // We hold mA2dpMixerThread mLock already - Mutex::Autolock _l(mHardwareMixerThread->mLock); - - // Transfer tracks playing on MUSIC stream from one mixer to the other - if (mA2dpEnabled) { - mHardwareMixerThread->getTracks(tracks, activeTracks); - mA2dpMixerThread->putTracks(tracks, activeTracks); - } else { - mA2dpMixerThread->getTracks(tracks, activeTracks); - mHardwareMixerThread->putTracks(tracks, activeTracks); - } - - // Notify AudioSystem of the A2DP activation/deactivation - size_t size = mNotificationClients.size(); - for (size_t i = 0; i < size; i++) { - sp<IBinder> binder = mNotificationClients.itemAt(i).promote(); - if (binder != NULL) { - LOGV("Notifying output change to client %p", binder.get()); - sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); - client->a2dpEnabledChanged(mA2dpEnabled); - } - } - - mHardwareMixerThread->wakeUp(); - } - } -} - -void AudioFlinger::removeClient(pid_t pid) -{ - LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mLock); - mClients.removeItem(pid); -} - -void AudioFlinger::wakeUp() -{ - mHardwareMixerThread->wakeUp(); -#ifdef WITH_A2DP - mA2dpMixerThread->wakeUp(); -#endif // WITH_A2DP -} - -bool AudioFlinger::isA2dpEnabled() const -{ - return mA2dpEnabledReq; -} - -void AudioFlinger::handleForcedSpeakerRoute(int command) -{ - switch(command) { - case ACTIVE_TRACK_ADDED: - { - AutoMutex lock(mHardwareLock); - if (mForcedSpeakerCount++ == 0) { - mRouteRestoreTime = 0; - mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC); - if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { - LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER); - mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(0); - usleep(mHardwareMixerThread->latency()*1000); - mHardwareStatus = AUDIO_HW_SET_ROUTING; - mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER); - mHardwareStatus = AUDIO_HW_IDLE; - // delay track start so that audio hardware has time to siwtch routes - usleep(kStartSleepTime); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume()); - mHardwareStatus = AUDIO_HW_IDLE; - } - mForcedRoute = AudioSystem::ROUTE_SPEAKER; - } - LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount); - } - break; - case ACTIVE_TRACK_REMOVED: - { - AutoMutex lock(mHardwareLock); - if (mForcedSpeakerCount > 0){ - if (--mForcedSpeakerCount == 0) { - mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000); - } - LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount); - } else { - LOGE("mForcedSpeakerCount is already zero"); - } - } - break; - case CHECK_ROUTE_RESTORE_TIME: - case FORCE_ROUTE_RESTORE: - if (mRouteRestoreTime) { - AutoMutex lock(mHardwareLock); - if (mRouteRestoreTime && - (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) { - mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved); - mForcedRoute = 0; - if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { - mHardwareStatus = AUDIO_HW_SET_ROUTING; - mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute); - mHardwareStatus = AUDIO_HW_IDLE; - LOGV("Route forced to Speaker OFF %08x", mSavedRoute); - } - mRouteRestoreTime = 0; - } - } - break; - } -} - - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType) - : Thread(false), - mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), - mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0), - mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false), - mInWrite(false) -{ - mSampleRate = output->sampleRate(); - mChannelCount = output->channelCount(); - - // FIXME - Current mixer implementation only supports stereo output - if (mChannelCount == 1) { - LOGE("Invalid audio hardware channel count"); - } - - mFormat = output->format(); - mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t); - mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate()); - - // FIXME - Current mixer implementation only supports stereo output: Always - // Allocate a stereo buffer even if HW output is mono. - mMixBuffer = new int16_t[mFrameCount * 2]; - memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); -} - -AudioFlinger::MixerThread::~MixerThread() -{ - delete [] mMixBuffer; - delete mAudioMixer; -} - -status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args) -{ - dumpInternals(fd, args); - dumpTracks(fd, args); - return NO_ERROR; -} - -status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType); - result.append(buffer); - result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n"); - for (size_t i = 0; i < mTracks.size(); ++i) { - wp<Track> wTrack = mTracks[i]; - if (wTrack != 0) { - sp<Track> track = wTrack.promote(); - if (track != 0) { - track->dump(buffer, SIZE); - result.append(buffer); - } - } - } - - snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType); - result.append(buffer); - result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n"); - for (size_t i = 0; i < mActiveTracks.size(); ++i) { - wp<Track> wTrack = mTracks[i]; - if (wTrack != 0) { - sp<Track> track = wTrack.promote(); - if (track != 0) { - track->dump(buffer, SIZE); - result.append(buffer); - } - } - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType); - result.append(buffer); - snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames()); - result.append(buffer); - snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); - result.append(buffer); - snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites); - result.append(buffer); - snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites); - result.append(buffer); - snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite); - result.append(buffer); - snprintf(buffer, SIZE, "standby: %d\n", mStandby); - result.append(buffer); - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -// Thread virtuals -bool AudioFlinger::MixerThread::threadLoop() -{ - unsigned long sleepTime = kBufferRecoveryInUsecs; - int16_t* curBuf = mMixBuffer; - Vector< sp<Track> > tracksToRemove; - size_t enabledTracks = 0; - nsecs_t standbyTime = systemTime(); - size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t); - nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2; - -#ifdef WITH_A2DP - bool outputTrackActive = false; -#endif - - do { - enabledTracks = 0; - { // scope for the mLock - - Mutex::Autolock _l(mLock); - -#ifdef WITH_A2DP - if (mOutputType == AudioSystem::AUDIO_OUTPUT_A2DP) { - mAudioFlinger->handleOutputSwitch(); - } - if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) { - if (outputTrackActive) { - mOutputTrack->stop(); - outputTrackActive = false; - } - } -#endif - - const SortedVector< wp<Track> >& activeTracks = mActiveTracks; - - // put audio hardware into standby after short delay - if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) { - // wait until we have something to do... - LOGV("Audio hardware entering standby, output %d\n", mOutputType); -// mAudioFlinger->mHardwareStatus = AUDIO_HW_STANDBY; - if (!mStandby) { - mOutput->standby(); - mStandby = true; - } - -#ifdef WITH_A2DP - if (outputTrackActive) { - mOutputTrack->stop(); - outputTrackActive = false; - } -#endif - if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { - mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE); - } -// mHardwareStatus = AUDIO_HW_IDLE; - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - mWaitWorkCV.wait(mLock); - LOGV("Audio hardware exiting standby, output %d\n", mOutputType); - standbyTime = systemTime() + kStandbyTimeInNsecs; - continue; - } - - // Forced route to speaker is handled by hardware mixer thread - if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { - mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME); - } - - // find out which tracks need to be processed - size_t count = activeTracks.size(); - for (size_t i=0 ; i<count ; i++) { - sp<Track> t = activeTracks[i].promote(); - if (t == 0) continue; - - Track* const track = t.get(); - audio_track_cblk_t* cblk = track->cblk(); - - // The first time a track is added we wait - // for all its buffers to be filled before processing it - mAudioMixer->setActiveTrack(track->name()); - if (cblk->framesReady() && (track->isReady() || track->isStopped()) && - !track->isPaused()) - { - //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); - - // compute volume for this track - int16_t left, right; - if (track->isMuted() || mMasterMute || track->isPausing()) { - left = right = 0; - if (track->isPausing()) { - LOGV("paused(%d)", track->name()); - track->setPaused(); - } - } else { - float typeVolume = mStreamTypes[track->type()].volume; - float v = mMasterVolume * typeVolume; - float v_clamped = v * cblk->volume[0]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - left = int16_t(v_clamped); - v_clamped = v * cblk->volume[1]; - if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; - right = int16_t(v_clamped); - } - - // XXX: these things DON'T need to be done each time - mAudioMixer->setBufferProvider(track); - mAudioMixer->enable(AudioMixer::MIXING); - - int param; - if ( track->mFillingUpStatus == Track::FS_FILLED) { - // no ramp for the first volume setting - track->mFillingUpStatus = Track::FS_ACTIVE; - if (track->mState == TrackBase::RESUMING) { - track->mState = TrackBase::ACTIVE; - param = AudioMixer::RAMP_VOLUME; - } else { - param = AudioMixer::VOLUME; - } - } else { - param = AudioMixer::RAMP_VOLUME; - } - mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); - mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::FORMAT, track->format()); - mAudioMixer->setParameter( - AudioMixer::TRACK, - AudioMixer::CHANNEL_COUNT, track->channelCount()); - mAudioMixer->setParameter( - AudioMixer::RESAMPLE, - AudioMixer::SAMPLE_RATE, - int(cblk->sampleRate)); - - // reset retry count - track->mRetryCount = kMaxTrackRetries; - enabledTracks++; - } else { - //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server); - if (track->isStopped()) { - track->reset(); - } - if (track->isTerminated() || track->isStopped() || track->isPaused()) { - // We have consumed all the buffers of this track. - // Remove it from the list of active tracks. - LOGV("remove(%d) from active list", track->name()); - tracksToRemove.add(track); - } else { - // No buffers for this track. Give it a few chances to - // fill a buffer, then remove it from active list. - if (--(track->mRetryCount) <= 0) { - LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name()); - tracksToRemove.add(track); - } - } - // LOGV("disable(%d)", track->name()); - mAudioMixer->disable(AudioMixer::MIXING); - } - } - - // remove all the tracks that need to be... - count = tracksToRemove.size(); - if (UNLIKELY(count)) { - for (size_t i=0 ; i<count ; i++) { - const sp<Track>& track = tracksToRemove[i]; - removeActiveTrack(track); - if (track->isTerminated()) { - mTracks.remove(track); - deleteTrackName(track->mName); - } - } - } - } - - if (LIKELY(enabledTracks)) { - // mix buffers... - mAudioMixer->process(curBuf); - -#ifdef WITH_A2DP - if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) { - if (!outputTrackActive) { - LOGV("starting output track in mixer for output %d", mOutputType); - mOutputTrack->start(); - outputTrackActive = true; - } - mOutputTrack->write(curBuf, mFrameCount); - } -#endif - - // output audio to hardware - mLastWriteTime = systemTime(); - mInWrite = true; - mOutput->write(curBuf, mixBufferSize); - mNumWrites++; - mInWrite = false; - mStandby = false; - nsecs_t temp = systemTime(); - standbyTime = temp + kStandbyTimeInNsecs; - nsecs_t delta = temp - mLastWriteTime; - if (delta > maxPeriod) { - LOGW("write blocked for %llu msecs", ns2ms(delta)); - mNumDelayedWrites++; - } - sleepTime = kBufferRecoveryInUsecs; - } else { -#ifdef WITH_A2DP - if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) { - if (outputTrackActive) { - mOutputTrack->write(curBuf, 0); - if (mOutputTrack->bufferQueueEmpty()) { - mOutputTrack->stop(); - outputTrackActive = false; - } else { - standbyTime = systemTime() + kStandbyTimeInNsecs; - } - } - } -#endif - // There was nothing to mix this round, which means all - // active tracks were late. Sleep a little bit to give - // them another chance. If we're too late, the audio - // hardware will zero-fill for us. - //LOGV("no buffers - usleep(%lu)", sleepTime); - usleep(sleepTime); - if (sleepTime < kMaxBufferRecoveryInUsecs) { - sleepTime += kBufferRecoveryInUsecs; - } - } - - // finally let go of all our tracks, without the lock held - // since we can't guarantee the destructors won't acquire that - // same lock. - tracksToRemove.clear(); - } while (true); - - return false; -} - -status_t AudioFlinger::MixerThread::readyToRun() -{ - if (mSampleRate == 0) { - LOGE("No working audio driver found."); - return NO_INIT; - } - LOGI("AudioFlinger's thread ready to run for output %d", mOutputType); - return NO_ERROR; -} - -void AudioFlinger::MixerThread::onFirstRef() -{ - const size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType); - - run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); -} - - -sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack( - const sp<AudioFlinger::Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer, - status_t *status) -{ - sp<Track> track; - status_t lStatus; - - // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) { - LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); - lStatus = BAD_VALUE; - goto Exit; - } - - { - Mutex::Autolock _l(mLock); - - if (mSampleRate == 0) { - LOGE("Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; - } - - track = new Track(this, client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer); - if (track->getCblk() == NULL) { - track.clear(); - lStatus = NO_MEMORY; - goto Exit; - } - mTracks.add(track); - lStatus = NO_ERROR; - } - -Exit: - if(status) { - *status = lStatus; - } - return track; -} - -void AudioFlinger::MixerThread::getTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks) -{ - size_t size = mTracks.size(); - LOGV ("MixerThread::getTracks() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size()); - for (size_t i = 0; i < size; i++) { - sp<Track> t = mTracks[i]; - if (AudioSystem::routedToA2dpOutput(t->mStreamType)) { - tracks.add(t); - int j = mActiveTracks.indexOf(t); - if (j >= 0) { - t = mActiveTracks[j].promote(); - if (t != NULL) { - activeTracks.add(t); - } - } - } - } - - size = activeTracks.size(); - for (size_t i = 0; i < size; i++) { - removeActiveTrack(activeTracks[i]); - } - - size = tracks.size(); - for (size_t i = 0; i < size; i++) { - sp<Track> t = tracks[i]; - mTracks.remove(t); - deleteTrackName(t->name()); - } -} - -void AudioFlinger::MixerThread::putTracks( - SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks) -{ - - LOGV ("MixerThread::putTracks() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size()); - - size_t size = tracks.size(); - for (size_t i = 0; i < size ; i++) { - sp<Track> t = tracks[i]; - int name = getTrackName(); - - if (name < 0) return; - - t->mName = name; - t->mMixerThread = this; - mTracks.add(t); - - int j = activeTracks.indexOf(t); - if (j >= 0) { - addActiveTrack(t); - } - } -} - -uint32_t AudioFlinger::MixerThread::sampleRate() const -{ - return mSampleRate; -} - -int AudioFlinger::MixerThread::channelCount() const -{ - return mChannelCount; -} - -int AudioFlinger::MixerThread::format() const -{ - return mFormat; -} - -size_t AudioFlinger::MixerThread::frameCount() const -{ - return mFrameCount; -} - -uint32_t AudioFlinger::MixerThread::latency() const -{ - if (mOutput) { - return mOutput->latency(); - } - else { - return 0; - } -} - -status_t AudioFlinger::MixerThread::setMasterVolume(float value) -{ - mMasterVolume = value; - return NO_ERROR; -} - -status_t AudioFlinger::MixerThread::setMasterMute(bool muted) -{ - mMasterMute = muted; - return NO_ERROR; -} - -float AudioFlinger::MixerThread::masterVolume() const -{ - return mMasterVolume; -} - -bool AudioFlinger::MixerThread::masterMute() const -{ - return mMasterMute; -} - -status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value) -{ - mStreamTypes[stream].volume = value; - return NO_ERROR; -} - -status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted) -{ - mStreamTypes[stream].mute = muted; - return NO_ERROR; -} - -float AudioFlinger::MixerThread::streamVolume(int stream) const -{ - return mStreamTypes[stream].volume; -} - -bool AudioFlinger::MixerThread::streamMute(int stream) const -{ - return mStreamTypes[stream].mute; -} - -bool AudioFlinger::MixerThread::isMusicActive() const -{ - size_t count = mActiveTracks.size(); - for (size_t i = 0 ; i < count ; ++i) { - sp<Track> t = mActiveTracks[i].promote(); - if (t == 0) continue; - Track* const track = t.get(); - if (t->mStreamType == AudioSystem::MUSIC) - return true; - } - return false; -} - -status_t AudioFlinger::MixerThread::addTrack(const sp<Track>& track) -{ - status_t status = ALREADY_EXISTS; - Mutex::Autolock _l(mLock); - - // here the track could be either new, or restarted - // in both cases "unstop" the track - if (track->isPaused()) { - track->mState = TrackBase::RESUMING; - LOGV("PAUSED => RESUMING (%d)", track->name()); - } else { - track->mState = TrackBase::ACTIVE; - LOGV("? => ACTIVE (%d)", track->name()); - } - // set retry count for buffer fill - track->mRetryCount = kMaxTrackStartupRetries; - if (mActiveTracks.indexOf(track) < 0) { - // the track is newly added, make sure it fills up all its - // buffers before playing. This is to ensure the client will - // effectively get the latency it requested. - track->mFillingUpStatus = Track::FS_FILLING; - track->mResetDone = false; - addActiveTrack(track); - status = NO_ERROR; - } - - LOGV("mWaitWorkCV.broadcast"); - mWaitWorkCV.broadcast(); - - return status; -} - -void AudioFlinger::MixerThread::removeTrack(wp<Track> track, int name) -{ - Mutex::Autolock _l(mLock); - sp<Track> t = track.promote(); - if (t!=NULL && (t->mState <= TrackBase::STOPPED)) { - remove_track_l(track, name); - } -} - -void AudioFlinger::MixerThread::remove_track_l(wp<Track> track, int name) -{ - sp<Track> t = track.promote(); - if (t!=NULL) { - t->reset(); - } - deleteTrackName(name); - removeActiveTrack(track); - mWaitWorkCV.broadcast(); -} - -void AudioFlinger::MixerThread::destroyTrack(const sp<Track>& track) -{ - // NOTE: We're acquiring a strong reference on the track before - // acquiring the lock, this is to make sure removing it from - // mTracks won't cause the destructor to be called while the lock is - // held (note that technically, 'track' could be a reference to an item - // in mTracks, which is why we need to do this). - sp<Track> keep(track); - Mutex::Autolock _l(mLock); - track->mState = TrackBase::TERMINATED; - if (mActiveTracks.indexOf(track) < 0) { - LOGV("remove track (%d) and delete from mixer", track->name()); - mTracks.remove(track); - deleteTrackName(keep->name()); - } -} - - -void AudioFlinger::MixerThread::addActiveTrack(const wp<Track>& t) -{ - mActiveTracks.add(t); - - // Force routing to speaker for certain stream types - // The forced routing to speaker is managed by hardware mixer - if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { - sp<Track> track = t.promote(); - if (track == NULL) return; - - if (streamForcedToSpeaker(track->type())) { - mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED); - } - } -} - -void AudioFlinger::MixerThread::removeActiveTrack(const wp<Track>& t) -{ - mActiveTracks.remove(t); - - // Force routing to speaker for certain stream types - // The forced routing to speaker is managed by hardware mixer - if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { - sp<Track> track = t.promote(); - if (track == NULL) return; - - if (streamForcedToSpeaker(track->type())) { - mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED); - } - } -} - -int AudioFlinger::MixerThread::getTrackName() -{ - return mAudioMixer->getTrackName(); -} - -void AudioFlinger::MixerThread::deleteTrackName(int name) -{ - mAudioMixer->deleteTrackName(name); -} - -size_t AudioFlinger::MixerThread::getOutputFrameCount() -{ - return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::TrackBase::TrackBase( - const sp<MixerThread>& mixerThread, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer) - : RefBase(), - mMixerThread(mixerThread), - mClient(client), - mStreamType(streamType), - mFrameCount(0), - mState(IDLE), - mClientTid(-1), - mFormat(format), - mFlags(flags & ~SYSTEM_FLAGS_MASK) -{ - mName = mixerThread->getTrackName(); - LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - if (mName < 0) { - LOGE("no more track names availlable"); - return; - } - - LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); - - // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); - size_t size = sizeof(audio_track_cblk_t); - size_t bufferSize = frameCount*channelCount*sizeof(int16_t); - if (sharedBuffer == 0) { - size += bufferSize; - } - - if (client != NULL) { - mCblkMemory = client->heap()->allocate(size); - if (mCblkMemory != 0) { - mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); - if (mCblk) { // construct the shared structure in-place. - new(mCblk) audio_track_cblk_t(); - // clear all buffers - mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channels = channelCount; - if (sharedBuffer == 0) { - mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); - memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flowControlFlag = 1; - } else { - mBuffer = sharedBuffer->pointer(); - } - mBufferEnd = (uint8_t *)mBuffer + bufferSize; - } - } else { - LOGE("not enough memory for AudioTrack size=%u", size); - client->heap()->dump("AudioTrack"); - return; - } - } else { - mCblk = (audio_track_cblk_t *)(new uint8_t[size]); - if (mCblk) { // construct the shared structure in-place. - new(mCblk) audio_track_cblk_t(); - // clear all buffers - mCblk->frameCount = frameCount; - mCblk->sampleRate = sampleRate; - mCblk->channels = channelCount; - mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); - memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flowControlFlag = 1; - mBufferEnd = (uint8_t *)mBuffer + bufferSize; - } - } -} - -AudioFlinger::MixerThread::TrackBase::~TrackBase() -{ - if (mCblk) { - mCblk->~audio_track_cblk_t(); // destroy our shared-structure. - } - mCblkMemory.clear(); // and free the shared memory - mClient.clear(); -} - -void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) -{ - buffer->raw = 0; - mFrameCount = buffer->frameCount; - step(); - buffer->frameCount = 0; -} - -bool AudioFlinger::MixerThread::TrackBase::step() { - bool result; - audio_track_cblk_t* cblk = this->cblk(); - - result = cblk->stepServer(mFrameCount); - if (!result) { - LOGV("stepServer failed acquiring cblk mutex"); - mFlags |= STEPSERVER_FAILED; - } - return result; -} - -void AudioFlinger::MixerThread::TrackBase::reset() { - audio_track_cblk_t* cblk = this->cblk(); - - cblk->user = 0; - cblk->server = 0; - cblk->userBase = 0; - cblk->serverBase = 0; - mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK); - LOGV("TrackBase::reset"); -} - -sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const -{ - return mCblkMemory; -} - -int AudioFlinger::MixerThread::TrackBase::sampleRate() const { - return mCblk->sampleRate; -} - -int AudioFlinger::MixerThread::TrackBase::channelCount() const { - return mCblk->channels; -} - -void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { - audio_track_cblk_t* cblk = this->cblk(); - int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels; - int16_t *bufferEnd = bufferStart + frames * cblk->channels; - - // Check validity of returned pointer in case the track control block would have been corrupted. - if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) { - LOGW("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ - server %d, serverBase %d, user %d, userBase %d", - bufferStart, bufferEnd, mBuffer, mBufferEnd, - cblk->server, cblk->serverBase, cblk->user, cblk->userBase); - return 0; - } - - return bufferStart; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::Track::Track( - const sp<MixerThread>& mixerThread, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - const sp<IMemory>& sharedBuffer) - : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer) -{ - mVolume[0] = 1.0f; - mVolume[1] = 1.0f; - mMute = false; - mSharedBuffer = sharedBuffer; -} - -AudioFlinger::MixerThread::Track::~Track() -{ - wp<Track> weak(this); // never create a strong ref from the dtor - mState = TERMINATED; - mMixerThread->removeTrack(weak, mName); -} - -void AudioFlinger::MixerThread::Track::destroy() -{ - mMixerThread->destroyTrack(this); -} - -void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size) -{ - snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n", - mName - AudioMixer::TRACK0, - (mClient == NULL) ? getpid() : mClient->pid(), - mStreamType, - mFormat, - mCblk->channels, - mFrameCount, - mState, - mMute, - mFillingUpStatus, - mCblk->sampleRate, - mCblk->volume[0], - mCblk->volume[1], - mCblk->server, - mCblk->user); -} - -status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) -{ - audio_track_cblk_t* cblk = this->cblk(); - uint32_t framesReady; - uint32_t framesReq = buffer->frameCount; - - // Check if last stepServer failed, try to step now - if (mFlags & TrackBase::STEPSERVER_FAILED) { - if (!step()) goto getNextBuffer_exit; - LOGV("stepServer recovered"); - mFlags &= ~TrackBase::STEPSERVER_FAILED; - } - - framesReady = cblk->framesReady(); - - if (LIKELY(framesReady)) { - uint32_t s = cblk->server; - uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; - - bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd; - if (framesReq > framesReady) { - framesReq = framesReady; - } - if (s + framesReq > bufferEnd) { - framesReq = bufferEnd - s; - } - - buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == 0) goto getNextBuffer_exit; - - buffer->frameCount = framesReq; - return NO_ERROR; - } - -getNextBuffer_exit: - buffer->raw = 0; - buffer->frameCount = 0; - return NOT_ENOUGH_DATA; -} - -bool AudioFlinger::MixerThread::Track::isReady() const { - if (mFillingUpStatus != FS_FILLING) return true; - - if (mCblk->framesReady() >= mCblk->frameCount || - mCblk->forceReady) { - mFillingUpStatus = FS_FILLED; - mCblk->forceReady = 0; - LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType); - return true; - } - return false; -} - -status_t AudioFlinger::MixerThread::Track::start() -{ - LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); - mMixerThread->addTrack(this); - return NO_ERROR; -} - -void AudioFlinger::MixerThread::Track::stop() -{ - LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); - Mutex::Autolock _l(mMixerThread->mLock); - if (mState > STOPPED) { - mState = STOPPED; - // If the track is not active (PAUSED and buffers full), flush buffers - if (mMixerThread->mActiveTracks.indexOf(this) < 0) { - reset(); - } - LOGV("(> STOPPED) => STOPPED (%d)", mName); - } -} - -void AudioFlinger::MixerThread::Track::pause() -{ - LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); - Mutex::Autolock _l(mMixerThread->mLock); - if (mState == ACTIVE || mState == RESUMING) { - mState = PAUSING; - LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName); - } -} - -void AudioFlinger::MixerThread::Track::flush() -{ - LOGV("flush(%d)", mName); - Mutex::Autolock _l(mMixerThread->mLock); - if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { - return; - } - // No point remaining in PAUSED state after a flush => go to - // STOPPED state - mState = STOPPED; - - // NOTE: reset() will reset cblk->user and cblk->server with - // the risk that at the same time, the AudioMixer is trying to read - // data. In this case, getNextBuffer() would return a NULL pointer - // as audio buffer => the AudioMixer code MUST always test that pointer - // returned by getNextBuffer() is not NULL! - reset(); -} - -void AudioFlinger::MixerThread::Track::reset() -{ - // Do not reset twice to avoid discarding data written just after a flush and before - // the audioflinger thread detects the track is stopped. - if (!mResetDone) { - TrackBase::reset(); - // Force underrun condition to avoid false underrun callback until first data is - // written to buffer - mCblk->flowControlFlag = 1; - mCblk->forceReady = 0; - mFillingUpStatus = FS_FILLING; - mResetDone = true; - } -} - -void AudioFlinger::MixerThread::Track::mute(bool muted) -{ - mMute = muted; -} - -void AudioFlinger::MixerThread::Track::setVolume(float left, float right) -{ - mVolume[0] = left; - mVolume[1] = right; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::RecordTrack::RecordTrack( - const sp<MixerThread>& mixerThread, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags) - : TrackBase(mixerThread, client, streamType, sampleRate, format, - channelCount, frameCount, flags, 0), - mOverflow(false) -{ -} - -AudioFlinger::MixerThread::RecordTrack::~RecordTrack() -{ - mMixerThread->deleteTrackName(mName); -} - -status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) -{ - audio_track_cblk_t* cblk = this->cblk(); - uint32_t framesAvail; - uint32_t framesReq = buffer->frameCount; - - // Check if last stepServer failed, try to step now - if (mFlags & TrackBase::STEPSERVER_FAILED) { - if (!step()) goto getNextBuffer_exit; - LOGV("stepServer recovered"); - mFlags &= ~TrackBase::STEPSERVER_FAILED; - } - - framesAvail = cblk->framesAvailable_l(); - - if (LIKELY(framesAvail)) { - uint32_t s = cblk->server; - uint32_t bufferEnd = cblk->serverBase + cblk->frameCount; - - if (framesReq > framesAvail) { - framesReq = framesAvail; - } - if (s + framesReq > bufferEnd) { - framesReq = bufferEnd - s; - } - - buffer->raw = getBuffer(s, framesReq); - if (buffer->raw == 0) goto getNextBuffer_exit; - - buffer->frameCount = framesReq; - return NO_ERROR; - } - -getNextBuffer_exit: - buffer->raw = 0; - buffer->frameCount = 0; - return NOT_ENOUGH_DATA; -} - -status_t AudioFlinger::MixerThread::RecordTrack::start() -{ - return mMixerThread->mAudioFlinger->startRecord(this); -} - -void AudioFlinger::MixerThread::RecordTrack::stop() -{ - mMixerThread->mAudioFlinger->stopRecord(this); - TrackBase::reset(); - // Force overerrun condition to avoid false overrun callback until first data is - // read from buffer - mCblk->flowControlFlag = 1; -} - - -// ---------------------------------------------------------------------------- - -AudioFlinger::MixerThread::OutputTrack::OutputTrack( - const sp<MixerThread>& mixerThread, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount) - : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL), - mOutputMixerThread(mixerThread) -{ - - mCblk->out = 1; - mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); - mCblk->volume[0] = mCblk->volume[1] = 0x1000; - mOutBuffer.frameCount = 0; - mCblk->bufferTimeoutMs = 10; - - LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", - mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd); - -} - -AudioFlinger::MixerThread::OutputTrack::~OutputTrack() -{ - stop(); -} - -status_t AudioFlinger::MixerThread::OutputTrack::start() -{ - status_t status = Track::start(); - - mRetryCount = 127; - return status; -} - -void AudioFlinger::MixerThread::OutputTrack::stop() -{ - Track::stop(); - clearBufferQueue(); - mOutBuffer.frameCount = 0; -} - -void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames) -{ - Buffer *pInBuffer; - Buffer inBuffer; - uint32_t channels = mCblk->channels; - - inBuffer.frameCount = frames; - inBuffer.i16 = data; - - if (mCblk->user == 0) { - if (mOutputMixerThread->isMusicActive()) { - mCblk->forceReady = 1; - LOGV("OutputTrack::start() force ready"); - } else if (mCblk->frameCount > frames){ - if (mBufferQueue.size() < kMaxOutputTrackBuffers) { - uint32_t startFrames = (mCblk->frameCount - frames); - LOGV("OutputTrack::start() write %d frames", startFrames); - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[startFrames * channels]; - pInBuffer->frameCount = startFrames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else { - LOGW ("OutputTrack::write() no more buffers"); - } - } - } - - while (1) { - // First write pending buffers, then new data - if (mBufferQueue.size()) { - pInBuffer = mBufferQueue.itemAt(0); - } else { - pInBuffer = &inBuffer; - } - - if (pInBuffer->frameCount == 0) { - break; - } - - if (mOutBuffer.frameCount == 0) { - mOutBuffer.frameCount = pInBuffer->frameCount; - if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) { - break; - } - } - - uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; - memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t)); - mCblk->stepUser(outFrames); - pInBuffer->frameCount -= outFrames; - pInBuffer->i16 += outFrames * channels; - mOutBuffer.frameCount -= outFrames; - mOutBuffer.i16 += outFrames * channels; - - if (pInBuffer->frameCount == 0) { - if (mBufferQueue.size()) { - mBufferQueue.removeAt(0); - delete [] pInBuffer->mBuffer; - delete pInBuffer; - } else { - break; - } - } - } - - // If we could not write all frames, allocate a buffer and queue it for next time. - if (inBuffer.frameCount) { - if (mBufferQueue.size() < kMaxOutputTrackBuffers) { - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels]; - pInBuffer->frameCount = inBuffer.frameCount; - pInBuffer->i16 = pInBuffer->mBuffer; - memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } else { - LOGW("OutputTrack::write() no more buffers"); - } - } - - // Calling write() with a 0 length buffer, means that no more data will be written: - // If no more buffers are pending, fill output track buffer to make sure it is started - // by output mixer. - if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) { - frames = mCblk->frameCount - mCblk->user; - pInBuffer = new Buffer; - pInBuffer->mBuffer = new int16_t[frames * channels]; - pInBuffer->frameCount = frames; - pInBuffer->i16 = pInBuffer->mBuffer; - memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t)); - mBufferQueue.add(pInBuffer); - } - -} - -status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer) -{ - int active; - int timeout = 0; - status_t result; - audio_track_cblk_t* cblk = mCblk; - uint32_t framesReq = buffer->frameCount; - - LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server); - buffer->frameCount = 0; - - uint32_t framesAvail = cblk->framesAvailable(); - - if (framesAvail == 0) { - return AudioTrack::NO_MORE_BUFFERS; - } - - if (framesReq > framesAvail) { - framesReq = framesAvail; - } - - uint32_t u = cblk->user; - uint32_t bufferEnd = cblk->userBase + cblk->frameCount; - - if (u + framesReq > bufferEnd) { - framesReq = bufferEnd - u; - } - - buffer->frameCount = framesReq; - buffer->raw = (void *)cblk->buffer(u); - return NO_ERROR; -} - - -void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue() -{ - size_t size = mBufferQueue.size(); - Buffer *pBuffer; - - for (size_t i = 0; i < size; i++) { - pBuffer = mBufferQueue.itemAt(i); - delete [] pBuffer->mBuffer; - delete pBuffer; - } - mBufferQueue.clear(); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) - : RefBase(), - mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), - mPid(pid) -{ - // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer -} - -AudioFlinger::Client::~Client() -{ - mAudioFlinger->removeClient(mPid); -} - -const sp<MemoryDealer>& AudioFlinger::Client::heap() const -{ - return mMemoryDealer; -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track) - : BnAudioTrack(), - mTrack(track) -{ -} - -AudioFlinger::TrackHandle::~TrackHandle() { - // just stop the track on deletion, associated resources - // will be freed from the main thread once all pending buffers have - // been played. Unless it's not in the active track list, in which - // case we free everything now... - mTrack->destroy(); -} - -status_t AudioFlinger::TrackHandle::start() { - return mTrack->start(); -} - -void AudioFlinger::TrackHandle::stop() { - mTrack->stop(); -} - -void AudioFlinger::TrackHandle::flush() { - mTrack->flush(); -} - -void AudioFlinger::TrackHandle::mute(bool e) { - mTrack->mute(e); -} - -void AudioFlinger::TrackHandle::pause() { - mTrack->pause(); -} - -void AudioFlinger::TrackHandle::setVolume(float left, float right) { - mTrack->setVolume(left, right); -} - -sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { - return mTrack->getCblk(); -} - -status_t AudioFlinger::TrackHandle::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioTrack::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- - -sp<IAudioRecord> AudioFlinger::openRecord( - pid_t pid, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - status_t *status) -{ - sp<AudioRecordThread> thread; - sp<MixerThread::RecordTrack> recordTrack; - sp<RecordHandle> recordHandle; - sp<Client> client; - wp<Client> wclient; - AudioStreamIn* input = 0; - int inFrameCount; - size_t inputBufferSize; - status_t lStatus; - - // check calling permissions - if (!recordingAllowed()) { - lStatus = PERMISSION_DENIED; - goto Exit; - } - - if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) { - LOGE("invalid stream type"); - lStatus = BAD_VALUE; - goto Exit; - } - - if (sampleRate > MAX_SAMPLE_RATE) { - LOGE("Sample rate out of range"); - lStatus = BAD_VALUE; - goto Exit; - } - - if (mAudioRecordThread == 0) { - LOGE("Audio record thread not started"); - lStatus = NO_INIT; - goto Exit; - } - - - // Check that audio input stream accepts requested audio parameters - inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); - if (inputBufferSize == 0) { - lStatus = BAD_VALUE; - LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount); - goto Exit; - } - - // add client to list - { - Mutex::Autolock _l(mLock); - wclient = mClients.valueFor(pid); - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } - } - - // frameCount must be a multiple of input buffer size - inFrameCount = inputBufferSize/channelCount/sizeof(short); - frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; - - // create new record track and pass to record thread - recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate, - format, channelCount, frameCount, flags); - if (recordTrack->getCblk() == NULL) { - recordTrack.clear(); - lStatus = NO_MEMORY; - goto Exit; - } - - // return to handle to client - recordHandle = new RecordHandle(recordTrack); - lStatus = NO_ERROR; - -Exit: - if (status) { - *status = lStatus; - } - return recordHandle; -} - -status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) { - if (mAudioRecordThread != 0) { - return mAudioRecordThread->start(recordTrack); - } - return NO_INIT; -} - -void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) { - if (mAudioRecordThread != 0) { - mAudioRecordThread->stop(recordTrack); - } -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack) - : BnAudioRecord(), - mRecordTrack(recordTrack) -{ -} - -AudioFlinger::RecordHandle::~RecordHandle() { - stop(); -} - -status_t AudioFlinger::RecordHandle::start() { - LOGV("RecordHandle::start()"); - return mRecordTrack->start(); -} - -void AudioFlinger::RecordHandle::stop() { - LOGV("RecordHandle::stop()"); - mRecordTrack->stop(); -} - -sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { - return mRecordTrack->getCblk(); -} - -status_t AudioFlinger::RecordHandle::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioRecord::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- - -AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) : - mAudioHardware(audioHardware), - mActive(false) -{ -} - -AudioFlinger::AudioRecordThread::~AudioRecordThread() -{ -} - -bool AudioFlinger::AudioRecordThread::threadLoop() -{ - LOGV("AudioRecordThread: start record loop"); - AudioBufferProvider::Buffer buffer; - int inBufferSize = 0; - int inFrameCount = 0; - AudioStreamIn* input = 0; - - mActive = 0; - - // start recording - while (!exitPending()) { - if (!mActive) { - mLock.lock(); - if (!mActive && !exitPending()) { - LOGV("AudioRecordThread: loop stopping"); - if (input) { - delete input; - input = 0; - } - mRecordTrack.clear(); - mStopped.signal(); - - mWaitWorkCV.wait(mLock); - - LOGV("AudioRecordThread: loop starting"); - if (mRecordTrack != 0) { - input = mAudioHardware->openInputStream(mRecordTrack->format(), - mRecordTrack->channelCount(), - mRecordTrack->sampleRate(), - &mStartStatus, - (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16)); - if (input != 0) { - inBufferSize = input->bufferSize(); - inFrameCount = inBufferSize/input->frameSize(); - } - } else { - mStartStatus = NO_INIT; - } - if (mStartStatus !=NO_ERROR) { - LOGW("record start failed, status %d", mStartStatus); - mActive = false; - mRecordTrack.clear(); - } - mWaitWorkCV.signal(); - } - mLock.unlock(); - } else if (mRecordTrack != 0) { - - buffer.frameCount = inFrameCount; - if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) { - LOGV("AudioRecordThread read: %d frames", buffer.frameCount); - ssize_t bytesRead = input->read(buffer.raw, inBufferSize); - if (bytesRead < 0) { - LOGE("Error reading audio input"); - sleep(1); - } - mRecordTrack->releaseBuffer(&buffer); - mRecordTrack->overflow(); - } - - // client isn't retrieving buffers fast enough - else { - if (!mRecordTrack->setOverflow()) - LOGW("AudioRecordThread: buffer overflow"); - // Release the processor for a while before asking for a new buffer. - // This will give the application more chance to read from the buffer and - // clear the overflow. - usleep(5000); - } - } - } - - - if (input) { - delete input; - } - mRecordTrack.clear(); - - return false; -} - -status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack) -{ - LOGV("AudioRecordThread::start"); - AutoMutex lock(&mLock); - mActive = true; - // If starting the active track, just reset mActive in case a stop - // was pending and exit - if (recordTrack == mRecordTrack.get()) return NO_ERROR; - - if (mRecordTrack != 0) return -EBUSY; - - mRecordTrack = recordTrack; - - // signal thread to start - LOGV("Signal record thread"); - mWaitWorkCV.signal(); - mWaitWorkCV.wait(mLock); - LOGV("Record started, status %d", mStartStatus); - return mStartStatus; -} - -void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) { - LOGV("AudioRecordThread::stop"); - AutoMutex lock(&mLock); - if (mActive && (recordTrack == mRecordTrack.get())) { - mActive = false; - mStopped.wait(mLock); - } -} - -void AudioFlinger::AudioRecordThread::exit() -{ - LOGV("AudioRecordThread::exit"); - { - AutoMutex lock(&mLock); - requestExit(); - mWaitWorkCV.signal(); - } - requestExitAndWait(); -} - -status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - pid_t pid = 0; - - if (mRecordTrack != 0 && mRecordTrack->mClient != 0) { - snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid()); - result.append(buffer); - } else { - result.append("No record client\n"); - } - write(fd, result.string(), result.size()); - return NO_ERROR; -} - -status_t AudioFlinger::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - return BnAudioFlinger::onTransact(code, data, reply, flags); -} - -// ---------------------------------------------------------------------------- -void AudioFlinger::instantiate() { - defaultServiceManager()->addService( - String16("media.audio_flinger"), new AudioFlinger()); -} - -}; // namespace android |