diff options
Diffstat (limited to 'libs/audioflinger/AudioFlinger.cpp')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 2109 |
1 files changed, 1478 insertions, 631 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 918b01fea918..3c81a47812d0 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -47,6 +47,15 @@ #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); @@ -59,6 +68,16 @@ static const float MAX_GAIN = 4096.0f; static const int8_t kMaxTrackRetries = 50; static const int8_t kMaxTrackStartupRetries = 50; +static const int kStartSleepTime = 30000; +static const int kStopSleepTime = 30000; + +static const int kDumpLockRetries = 50; +static const int kDumpLockSleep = 20000; + +// Maximum number of pending buffers allocated by OutputTrack::write() +static const uint8_t kMaxOutputTrackBuffers = 5; + + #define AUDIOFLINGER_SECURITY_ENABLED 1 // ---------------------------------------------------------------------------- @@ -98,13 +117,10 @@ static bool settingsAllowed() { // ---------------------------------------------------------------------------- AudioFlinger::AudioFlinger() - : BnAudioFlinger(), Thread(false), - mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0), - mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0), - mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0), - mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0), - mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false), - mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false) + : BnAudioFlinger(), + mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false), + mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0), + mRouteRestoreTime(0), mMusicMuteSaved(false) { mHardwareStatus = AUDIO_HW_IDLE; mAudioHardware = AudioHardwareInterface::create(); @@ -113,57 +129,51 @@ AudioFlinger::AudioFlinger() // open 16-bit output stream for s/w mixer mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; status_t status; - mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); + AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); mHardwareStatus = AUDIO_HW_IDLE; - if (mHardwareOutput) { - mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate()); - mRequestedOutput = mHardwareOutput; - doSetOutput(mHardwareOutput); - - // FIXME - this should come from settings - setMasterVolume(1.0f); - 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); - mMasterMute = false; + if (hwOutput) { + mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE); } else { - LOGE("Failed to initialize output stream, status: %d", status); + LOGE("Failed to initialize hardware output stream, status: %d", status); } #ifdef WITH_A2DP // Create A2DP interface mA2dpAudioInterface = new A2dpAudioInterface(); - mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status); - mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate()); - - // create a buffer big enough for both hardware and A2DP audio output. - size_t hwFrameCount = getOutputFrameCount(mHardwareOutput); - size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput); - size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount); -#else - size_t frameCount = getOutputFrameCount(mHardwareOutput); + 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 - Current mixer implementation only supports stereo output: Always - // Allocate a stereo buffer even if HW output is mono. - mMixBuffer = new int16_t[frameCount * 2]; - memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t)); - + + // 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); + mAudioRecordThread = new AudioRecordThread(mAudioHardware, this); 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"); - mMasterMute = true; - } } AudioFlinger::~AudioFlinger() @@ -172,59 +182,72 @@ AudioFlinger::~AudioFlinger() mAudioRecordThread->exit(); mAudioRecordThread.clear(); } + mHardwareMixerThread.clear(); delete mAudioHardware; // deleting mA2dpAudioInterface also deletes mA2dpOutput; +#ifdef WITH_A2DP + mA2dpMixerThread.clear(); delete mA2dpAudioInterface; - delete [] mMixBuffer; - delete mHardwareAudioMixer; - delete mA2dpAudioMixer; -} - -void AudioFlinger::setOutput(AudioStreamOut* output) -{ - mRequestedOutput = output; +#endif } -void AudioFlinger::doSetOutput(AudioStreamOut* output) + +#ifdef WITH_A2DP +// setA2dpEnabled_l() must be called with AudioFlinger::mLock held +void AudioFlinger::setA2dpEnabled_l(bool enable) { - mSampleRate = output->sampleRate(); - mChannelCount = output->channelCount(); + SortedVector < sp<MixerThread::Track> > tracks; + SortedVector < wp<MixerThread::Track> > activeTracks; + + LOGV_IF(enable, "set output to A2DP\n"); + LOGV_IF(!enable, "set output to hardware audio\n"); - // FIXME - Current mixer implementation only supports stereo output - if (mChannelCount == 1) { - LOGE("Invalid audio hardware channel count"); + // Transfer tracks playing on MUSIC stream from one mixer to the other + if (enable) { + mHardwareMixerThread->getTracks_l(tracks, activeTracks); + mA2dpMixerThread->putTracks_l(tracks, activeTracks); + } else { + mA2dpMixerThread->getTracks_l(tracks, activeTracks); + mHardwareMixerThread->putTracks_l(tracks, activeTracks); } - mFormat = output->format(); - mFrameCount = getOutputFrameCount(output); - mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer); - mOutput = output; + mA2dpEnabled = enable; + mNotifyA2dpChange = true; + mWaitWorkCV.broadcast(); } -size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) +// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held +void AudioFlinger::checkA2dpEnabledChange_l() { - return output->bufferSize() / output->channelCount() / sizeof(int16_t); + if (mNotifyA2dpChange) { + // 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); + } + } + mNotifyA2dpChange = false; + } } +#endif // WITH_A2DP -#ifdef WITH_A2DP -bool AudioFlinger::streamDisablesA2dp(int streamType) +bool AudioFlinger::streamForcedToSpeaker(int streamType) { - return (streamType == AudioTrack::SYSTEM || - streamType == AudioTrack::RING || - streamType == AudioTrack::ALARM || - streamType == AudioTrack::NOTIFICATION); + // 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); } -void AudioFlinger::setA2dpEnabled(bool enable) +bool AudioFlinger::streamDisablesA2dp(int streamType) { - if (enable) { - LOGD("set output to A2DP\n"); - setOutput(mA2dpOutput); - } else { - LOGD("set output to hardware audio\n"); - setOutput(mHardwareOutput); - } + return (streamType == AudioSystem::VOICE_CALL || + streamType == AudioSystem::BLUETOOTH_SCO); } -#endif // WITH_A2DP status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) { @@ -247,13 +270,672 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) return NO_ERROR; } -status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args) + +status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + int hardwareStatus = mHardwareStatus; + + if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) { + hardwareStatus = AUDIO_HW_STANDBY; + } + 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; +} + +status_t AudioFlinger::dump(int fd, const Vector<String16>& args) +{ + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + dumpPermissionDenial(fd, args); + } else { + bool locked = false; + for (int i = 0; i < kDumpLockRetries; ++i) { + if (mLock.tryLock() == NO_ERROR) { + locked = true; + break; + } + usleep(kDumpLockSleep); + } + + 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); + } + 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, + 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_l(client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer, &lStatus); + } else +#endif + { + track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer, &lStatus); + } + } + if (lStatus == NO_ERROR) { + trackHandle = new TrackHandle(track); + } else { + track.clear(); + } + +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; + } + if (mA2dpDisableCount > 0) { + mA2dpSuppressed = enableA2dp; + } else { + setA2dpEnabled_l(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; + } + + status_t ret = NO_ERROR; + + if (stream == AudioSystem::VOICE_CALL || + stream == AudioSystem::BLUETOOTH_SCO) { + float hwValue = value; + if (stream == AudioSystem::VOICE_CALL) { + hwValue = (float)AudioSystem::logToLinear(value)/100.0f; + // FIXME: This is a temporary fix to re-base the internally + // generated in-call audio so that it is never muted, which is + // already the case for the hardware routed in-call audio. + // When audio stream handling is reworked, this should be + // addressed more cleanly. Fixes #1324; see discussion at + // http://review.source.android.com/8224 + value = value * 0.99 + 0.01; + } else { // (type == AudioSystem::BLUETOOTH_SCO) + hwValue = 1.0f; + } + + AutoMutex lock(mHardwareLock); + mHardwareStatus = AUDIO_SET_VOICE_VOLUME; + ret = mAudioHardware->setVoiceVolume(hwValue); + mHardwareStatus = AUDIO_HW_IDLE; + + } + + mHardwareMixerThread->setStreamVolume(stream, value); +#ifdef WITH_A2DP + mA2dpMixerThread->setStreamVolume(stream, value); +#endif + + 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; + } + float value = mHardwareMixerThread->streamVolume(stream); + + if (stream == AudioSystem::VOICE_CALL) { + // FIXME: Re-base internally generated in-call audio, + // reverse of above in setStreamVolume. + value = (value - 0.01) / 0.99; + } + + return value; +} + +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::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); +} + +bool AudioFlinger::isA2dpEnabled() const +{ + return mA2dpEnabled; +} + +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; + } +} + +#ifdef WITH_A2DP +// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held +void AudioFlinger::handleStreamDisablesA2dp_l(int command) +{ + switch(command) { + case ACTIVE_TRACK_ADDED: + { + if (mA2dpDisableCount++ == 0) { + if (mA2dpEnabled) { + setA2dpEnabled_l(false); + mA2dpSuppressed = true; + } + } + LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount); + } + break; + case ACTIVE_TRACK_REMOVED: + { + if (mA2dpDisableCount > 0) { + if (--mA2dpDisableCount == 0) { + if (mA2dpSuppressed) { + setA2dpEnabled_l(true); + mA2dpSuppressed = false; + } + } + LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); + } else { + LOGE("mA2dpDisableCount is already zero"); + } + } + break; + } +} +#endif + +// ---------------------------------------------------------------------------- + +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; - result.append("Tracks:\n"); + 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]; @@ -266,7 +948,8 @@ status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args) } } - result.append("Active Tracks:\n"); + 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]; @@ -282,13 +965,15 @@ status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args) return NO_ERROR; } -status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) +status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; char buffer[SIZE]; String8 result; - snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames()); + 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); @@ -300,85 +985,86 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) result.append(buffer); snprintf(buffer, SIZE, "standby: %d\n", mStandby); result.append(buffer); - 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); - dumpTracks(fd, args); - dumpInternals(fd, args); - if (mAudioHardware) { - mAudioHardware->dumpState(fd, args); - } - } - return NO_ERROR; -} - // Thread virtuals -bool AudioFlinger::threadLoop() +bool AudioFlinger::MixerThread::threadLoop() { unsigned long sleepTime = kBufferRecoveryInUsecs; int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; size_t enabledTracks = 0; - nsecs_t standbyTime = systemTime(); + 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 + { // scope for the AudioFlinger::mLock - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mAudioFlinger->mLock); + +#ifdef WITH_A2DP + if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) { + if (outputTrackActive) { + mAudioFlinger->mLock.unlock(); + mOutputTrack->stop(); + mAudioFlinger->mLock.lock(); + outputTrackActive = false; + } + } + mAudioFlinger->checkA2dpEnabledChange_l(); +#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\n"); - mHardwareStatus = AUDIO_HW_STANDBY; + LOGV("Audio hardware entering standby, output %d\n", mOutputType); if (!mStandby) { mOutput->standby(); mStandby = true; } - mHardwareStatus = AUDIO_HW_IDLE; + +#ifdef WITH_A2DP + if (outputTrackActive) { + mAudioFlinger->mLock.unlock(); + mOutputTrack->stop(); + mAudioFlinger->mLock.lock(); + outputTrackActive = false; + } +#endif + if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { + mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE); + } // we're about to wait, flush the binder command buffer IPCThreadState::self()->flushCommands(); - mWaitWorkCV.wait(mLock); - LOGV("Audio hardware exiting standby\n"); + mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock); + LOGV("Audio hardware exiting standby, output %d\n", mOutputType); + + if (mMasterMute == false) { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.audio.silent", value, "0"); + if (atoi(value)) { + LOGD("Silence is golden"); + setMasterMute(true); + } + } + standbyTime = systemTime() + kStandbyTimeInNsecs; continue; } - // check for change in output - if (mRequestedOutput != mOutput) { - - // put current output into standby mode - if (mOutput) mOutput->standby(); - - // change output - doSetOutput(mRequestedOutput); + // 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 @@ -396,7 +1082,7 @@ bool AudioFlinger::threadLoop() if (cblk->framesReady() && (track->isReady() || track->isStopped()) && !track->isPaused()) { - //LOGD("u=%08x, s=%08x [OK]", u, s); + //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server); // compute volume for this track int16_t left, right; @@ -451,7 +1137,7 @@ bool AudioFlinger::threadLoop() track->mRetryCount = kMaxTrackRetries; enabledTracks++; } else { - //LOGD("u=%08x, s=%08x [NOT READY]", u, s); + //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server); if (track->isStopped()) { track->reset(); } @@ -478,22 +1164,33 @@ bool AudioFlinger::threadLoop() if (UNLIKELY(count)) { for (size_t i=0 ; i<count ; i++) { const sp<Track>& track = tracksToRemove[i]; - removeActiveTrack(track); + removeActiveTrack_l(track); if (track->isTerminated()) { mTracks.remove(track); - mAudioMixer->deleteTrackName(track->mName); + deleteTrackName_l(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; - size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t); mOutput->write(curBuf, mixBufferSize); mNumWrites++; mInWrite = false; @@ -501,18 +1198,30 @@ bool AudioFlinger::threadLoop() nsecs_t temp = systemTime(); standbyTime = temp + kStandbyTimeInNsecs; nsecs_t delta = temp - mLastWriteTime; - nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2; if (delta > maxPeriod) { LOGW("write blocked for %llu msecs", ns2ms(delta)); mNumDelayedWrites++; } sleepTime = kBufferRecoveryInUsecs; - } else { + } 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); + //LOGV("no buffers - usleep(%lu)", sleepTime); usleep(sleepTime); if (sleepTime < kMaxBufferRecoveryInUsecs) { sleepTime += kBufferRecoveryInUsecs; @@ -528,106 +1237,151 @@ bool AudioFlinger::threadLoop() return false; } -status_t AudioFlinger::readyToRun() +status_t AudioFlinger::MixerThread::readyToRun() { if (mSampleRate == 0) { LOGE("No working audio driver found."); return NO_INIT; } - LOGI("AudioFlinger's main thread ready to run."); + LOGI("AudioFlinger's thread ready to run for output %d", mOutputType); return NO_ERROR; } -void AudioFlinger::onFirstRef() +void AudioFlinger::MixerThread::onFirstRef() { - run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO); + const size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType); + + run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); } -// IAudioFlinger interface -sp<IAudioTrack> AudioFlinger::createTrack( - pid_t pid, +// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held +sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l( + const sp<AudioFlinger::Client>& client, int streamType, uint32_t sampleRate, int format, int channelCount, int frameCount, - uint32_t flags, const sp<IMemory>& sharedBuffer, status_t *status) { sp<Track> track; - sp<TrackHandle> trackHandle; - sp<Client> client; - wp<Client> wclient; status_t lStatus; - - if (streamType >= AudioTrack::NUM_STREAM_TYPES) { - LOGE("invalid stream type"); + + // 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; } - // 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", sampleRate); - lStatus = BAD_VALUE; + + if (mSampleRate == 0) { + LOGE("Audio driver not initialized."); + lStatus = NO_INIT; goto Exit; } - { - Mutex::Autolock _l(mLock); + track = new Track(this, client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer); + if (track->getCblk() == NULL) { + lStatus = NO_MEMORY; + goto Exit; + } + mTracks.add(track); + lStatus = NO_ERROR; - if (mSampleRate == 0) { - LOGE("Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; +Exit: + if(status) { + *status = lStatus; + } + return track; +} + +// getTracks_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::getTracks_l( + SortedVector < sp<Track> >& tracks, + SortedVector < wp<Track> >& activeTracks) +{ + size_t size = mTracks.size(); + LOGV ("MixerThread::getTracks_l() 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); + } + } } + } - wclient = mClients.valueFor(pid); + size = activeTracks.size(); + for (size_t i = 0; i < size; i++) { + removeActiveTrack_l(activeTracks[i]); + } + + size = tracks.size(); + for (size_t i = 0; i < size; i++) { + sp<Track> t = tracks[i]; + mTracks.remove(t); + deleteTrackName_l(t->name()); + } +} - if (wclient != NULL) { - client = wclient.promote(); - } else { - client = new Client(this, pid); - mClients.add(pid, client); - } +// putTracks_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::putTracks_l( + SortedVector < sp<Track> >& tracks, + SortedVector < wp<Track> >& activeTracks) +{ - track = new Track(this, client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer); - mTracks.add(track); - trackHandle = new TrackHandle(track); + LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size()); - lStatus = NO_ERROR; - } + size_t size = tracks.size(); + for (size_t i = 0; i < size ; i++) { + sp<Track> t = tracks[i]; + int name = getTrackName_l(); -Exit: - if(status) { - *status = lStatus; + if (name < 0) return; + + t->mName = name; + t->mMixerThread = this; + mTracks.add(t); + + int j = activeTracks.indexOf(t); + if (j >= 0) { + addActiveTrack_l(t); + } } - return trackHandle; } -uint32_t AudioFlinger::sampleRate() const +uint32_t AudioFlinger::MixerThread::sampleRate() const { return mSampleRate; } -int AudioFlinger::channelCount() const +int AudioFlinger::MixerThread::channelCount() const { return mChannelCount; } -int AudioFlinger::format() const +int AudioFlinger::MixerThread::format() const { return mFormat; } -size_t AudioFlinger::frameCount() const +size_t AudioFlinger::MixerThread::frameCount() const { return mFrameCount; } -uint32_t AudioFlinger::latency() const +uint32_t AudioFlinger::MixerThread::latency() const { if (mOutput) { return mOutput->latency(); @@ -637,260 +1391,67 @@ uint32_t AudioFlinger::latency() const } } -status_t AudioFlinger::setMasterVolume(float value) +status_t AudioFlinger::MixerThread::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) { - mMasterVolume = 1.0f; - } - else { - mMasterVolume = value; - } - mHardwareStatus = AUDIO_HW_IDLE; + mMasterVolume = value; 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\n", mode, routes, mask); - if (mode == AudioSystem::MODE_NORMAL && - (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) { - AutoMutex lock(&mLock); - - bool enableA2dp = false; - if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) { - if (mA2dpDisableCount > 0) - mA2dpSuppressed = true; - else - enableA2dp = true; - } - setA2dpEnabled(enableA2dp); - LOGD("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); - 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)) { - 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 +status_t AudioFlinger::MixerThread::setMasterMute(bool muted) { - 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; - } - mMasterMute = muted; return NO_ERROR; } -float AudioFlinger::masterVolume() const +float AudioFlinger::MixerThread::masterVolume() const { return mMasterVolume; } -bool AudioFlinger::masterMute() const +bool AudioFlinger::MixerThread::masterMute() const { return mMasterMute; } -status_t AudioFlinger::setStreamVolume(int stream, float value) +status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value) { - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { - return BAD_VALUE; - } - - status_t ret = NO_ERROR; - if (stream == AudioTrack::VOICE_CALL) { - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_VOICE_VOLUME; - ret = mAudioHardware->setVoiceVolume(value); - mHardwareStatus = AUDIO_HW_IDLE; - // FIXME: This is a temporary fix to re-base the internally - // generated in-call audio so that it is never muted, which is - // already the case for the hardware routed in-call audio. - // When audio stream handling is reworked, this should be - // addressed more cleanly. Fixes #1324; see discussion at - // http://review.source.android.com/8224 - mStreamTypes[stream].volume = value * (1.0 - 1.0 / 6.0) + (1.0 / 6.0); - } else { - mStreamTypes[stream].volume = value; - } - return ret; + mStreamTypes[stream].volume = value; + return NO_ERROR; } -status_t AudioFlinger::setStreamMute(int stream, bool muted) +status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted) { - // check calling permissions - if (!settingsAllowed()) { - return PERMISSION_DENIED; - } - - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { - return BAD_VALUE; - } mStreamTypes[stream].mute = muted; return NO_ERROR; } -float AudioFlinger::streamVolume(int stream) const +float AudioFlinger::MixerThread::streamVolume(int stream) const { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { - return 0.0f; - } - if (stream == AudioTrack::VOICE_CALL) { - // FIXME: Re-base internally generated in-call audio, - // reverse of above in setStreamVolume. - return (mStreamTypes[stream].volume - (1.0 / 6.0)) / (1.0 - 1.0 / 6.0); - } return mStreamTypes[stream].volume; } -bool AudioFlinger::streamMute(int stream) const +bool AudioFlinger::MixerThread::streamMute(int stream) const { - if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { - return true; - } return mStreamTypes[stream].mute; } -bool AudioFlinger::isMusicActive() const +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 == AudioTrack::MUSIC) + if (t->mStreamType == AudioSystem::MUSIC) return true; } return false; } -status_t AudioFlinger::setParameter(const char* key, const char* value) -{ - status_t result, result2; - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_SET_PARAMETER; - result = mAudioHardware->setParameter(key, value); - if (mA2dpAudioInterface) { - result2 = mA2dpAudioInterface->setParameter(key, value); - if (result2) - result = result2; - } - mHardwareStatus = AUDIO_HW_IDLE; - return result; -} - -void AudioFlinger::removeClient(pid_t pid) -{ - Mutex::Autolock _l(mLock); - mClients.removeItem(pid); -} - -status_t AudioFlinger::addTrack(const sp<Track>& track) +// addTrack_l() must be called with AudioFlinger::mLock held +status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track) { - Mutex::Autolock _l(mLock); + status_t status = ALREADY_EXISTS; // here the track could be either new, or restarted // in both cases "unstop" the track @@ -903,139 +1464,135 @@ status_t AudioFlinger::addTrack(const sp<Track>& track) } // set retry count for buffer fill track->mRetryCount = kMaxTrackStartupRetries; - LOGV("mWaitWorkCV.broadcast"); - mWaitWorkCV.broadcast(); - 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); - return NO_ERROR; + addActiveTrack_l(track); + status = NO_ERROR; } - return ALREADY_EXISTS; -} + + LOGV("mWaitWorkCV.broadcast"); + mAudioFlinger->mWaitWorkCV.broadcast(); -void AudioFlinger::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); - } + return status; } -void AudioFlinger::remove_track_l(wp<Track> track, int name) +// removeTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name) { sp<Track> t = track.promote(); - if (t!=NULL) { + if (t!=NULL && (t->mState <= TrackBase::STOPPED)) { t->reset(); + deleteTrackName_l(name); + removeActiveTrack_l(track); + mAudioFlinger->mWaitWorkCV.broadcast(); } - audioMixer()->deleteTrackName(name); - removeActiveTrack(track); - mWaitWorkCV.broadcast(); } -void AudioFlinger::destroyTrack(const sp<Track>& track) +// destroyTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::destroyTrack_l(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); - audioMixer()->deleteTrackName(keep->name()); + deleteTrackName_l(track->name()); } } -void AudioFlinger::addActiveTrack(const wp<Track>& t) +// addActiveTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::addActiveTrack_l(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); + } #ifdef WITH_A2DP - // disable A2DP for certain stream types - sp<Track> track = t.promote(); - if (streamDisablesA2dp(track->type())) { - if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) { - setA2dpEnabled(false); - mA2dpSuppressed = true; - LOGD("mA2dpSuppressed = true\n"); + // AudioFlinger::mLock must be locked before calling + // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). + if (streamDisablesA2dp(track->type())) { + mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED); } - LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount); - } #endif + } } -void AudioFlinger::removeActiveTrack(const wp<Track>& t) +// removeActiveTrack_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::removeActiveTrack_l(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); + } #ifdef WITH_A2DP - // disable A2DP for certain stream types - sp<Track> track = t.promote(); - if (streamDisablesA2dp(track->type())) { - if (mA2dpDisableCount > 0) { - mA2dpDisableCount--; - if (mA2dpDisableCount == 0 && mA2dpSuppressed) { - setA2dpEnabled(true); - mA2dpSuppressed = false; - } - LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount); - } else - LOGE("mA2dpDisableCount is already zero"); - } + // AudioFlinger::mLock must be locked before calling + // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). + if (streamDisablesA2dp(track->type())) { + mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED); + } #endif + } } -// ---------------------------------------------------------------------------- - -AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) - : RefBase(), - mAudioFlinger(audioFlinger), - mMemoryDealer(new MemoryDealer(1024*1024)), - mPid(pid) +// getTrackName_l() must be called with AudioFlinger::mLock held +int AudioFlinger::MixerThread::getTrackName_l() { - // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer + return mAudioMixer->getTrackName(); } -AudioFlinger::Client::~Client() +// deleteTrackName_l() must be called with AudioFlinger::mLock held +void AudioFlinger::MixerThread::deleteTrackName_l(int name) { - mAudioFlinger->removeClient(mPid); + mAudioMixer->deleteTrackName(name); } -const sp<MemoryDealer>& AudioFlinger::Client::heap() const +size_t AudioFlinger::MixerThread::getOutputFrameCount() { - return mMemoryDealer; + return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t); } // ---------------------------------------------------------------------------- -AudioFlinger::TrackBase::TrackBase( - const sp<AudioFlinger>& audioFlinger, +// TrackBase constructor must be called with AudioFlinger::mLock held +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(), - mAudioFlinger(audioFlinger), + mMixerThread(mixerThread), mClient(client), mStreamType(streamType), mFrameCount(0), mState(IDLE), mClientTid(-1), mFormat(format), - mFlags(0) + mFlags(flags & ~SYSTEM_FLAGS_MASK) { - mName = audioFlinger->audioMixer()->getTrackName(); + mName = mixerThread->getTrackName_l(); + LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); if (mName < 0) { LOGE("no more track names availlable"); return; @@ -1043,7 +1600,6 @@ AudioFlinger::TrackBase::TrackBase( 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); @@ -1051,41 +1607,60 @@ AudioFlinger::TrackBase::TrackBase( size += bufferSize; } - 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(); + 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; } - mBufferEnd = (uint8_t *)mBuffer + bufferSize; + } else { + LOGE("not enough memory for AudioTrack size=%u", size); + client->heap()->dump("AudioTrack"); + return; } - } 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::TrackBase::~TrackBase() +AudioFlinger::MixerThread::TrackBase::~TrackBase() { - mCblk->~audio_track_cblk_t(); // destroy our shared-structure. + if (mCblk) { + mCblk->~audio_track_cblk_t(); // destroy our shared-structure. + } mCblkMemory.clear(); // and free the shared memory mClient.clear(); } -void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) +void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) { buffer->raw = 0; mFrameCount = buffer->frameCount; @@ -1093,7 +1668,7 @@ void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) buffer->frameCount = 0; } -bool AudioFlinger::TrackBase::step() { +bool AudioFlinger::MixerThread::TrackBase::step() { bool result; audio_track_cblk_t* cblk = this->cblk(); @@ -1105,31 +1680,31 @@ bool AudioFlinger::TrackBase::step() { return result; } -void AudioFlinger::TrackBase::reset() { +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 = 0; + mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK); LOGV("TrackBase::reset"); } -sp<IMemory> AudioFlinger::TrackBase::getCblk() const +sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const { return mCblkMemory; } -int AudioFlinger::TrackBase::sampleRate() const { +int AudioFlinger::MixerThread::TrackBase::sampleRate() const { return mCblk->sampleRate; } -int AudioFlinger::TrackBase::channelCount() const { +int AudioFlinger::MixerThread::TrackBase::channelCount() const { return mCblk->channels; } -void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { +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; @@ -1148,8 +1723,9 @@ void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const // ---------------------------------------------------------------------------- -AudioFlinger::Track::Track( - const sp<AudioFlinger>& audioFlinger, +// Track constructor must be called with AudioFlinger::mLock held +AudioFlinger::MixerThread::Track::Track( + const sp<MixerThread>& mixerThread, const sp<Client>& client, int streamType, uint32_t sampleRate, @@ -1157,7 +1733,7 @@ AudioFlinger::Track::Track( int channelCount, int frameCount, const sp<IMemory>& sharedBuffer) - : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer) + : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer) { mVolume[0] = 1.0f; mVolume[1] = 1.0f; @@ -1165,23 +1741,36 @@ AudioFlinger::Track::Track( mSharedBuffer = sharedBuffer; } -AudioFlinger::Track::~Track() +AudioFlinger::MixerThread::Track::~Track() { wp<Track> weak(this); // never create a strong ref from the dtor + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); mState = TERMINATED; - mAudioFlinger->removeTrack(weak, mName); + mMixerThread->removeTrack_l(weak, mName); } -void AudioFlinger::Track::destroy() +void AudioFlinger::MixerThread::Track::destroy() { - mAudioFlinger->destroyTrack(this); + // NOTE: destroyTrack_l() can remove a strong reference to this Track + // by removing it from mTracks vector, so there is a risk that this Tracks's + // desctructor is called. As the destructor needs to lock AudioFlinger::mLock, + // we must acquire a strong reference on this Track before locking AudioFlinger::mLock + // here so that the destructor is called only when exiting this function. + // On the other hand, as long as Track::destroy() is only called by + // TrackHandle destructor, the TrackHandle still holds a strong ref on + // this Track with its member mTrack. + sp<Track> keep(this); + { // scope for AudioFlinger::mLock + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); + mMixerThread->destroyTrack_l(this); + } } -void AudioFlinger::Track::dump(char* buffer, size_t size) +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->pid(), + (mClient == NULL) ? getpid() : mClient->pid(), mStreamType, mFormat, mCblk->channels, @@ -1196,7 +1785,7 @@ void AudioFlinger::Track::dump(char* buffer, size_t size) mCblk->user); } -status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) { audio_track_cblk_t* cblk = this->cblk(); uint32_t framesReady; @@ -1236,53 +1825,55 @@ getNextBuffer_exit: return NOT_ENOUGH_DATA; } -bool AudioFlinger::Track::isReady() const { +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::Track::start() +status_t AudioFlinger::MixerThread::Track::start() { - LOGV("start(%d)", mName); - mAudioFlinger->addTrack(this); + LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); + mMixerThread->addTrack_l(this); return NO_ERROR; } -void AudioFlinger::Track::stop() +void AudioFlinger::MixerThread::Track::stop() { - LOGV("stop(%d)", mName); - Mutex::Autolock _l(mAudioFlinger->mLock); + LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType); + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); if (mState > STOPPED) { mState = STOPPED; // If the track is not active (PAUSED and buffers full), flush buffers - if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) { + if (mMixerThread->mActiveTracks.indexOf(this) < 0) { reset(); } LOGV("(> STOPPED) => STOPPED (%d)", mName); } } -void AudioFlinger::Track::pause() +void AudioFlinger::MixerThread::Track::pause() { - LOGV("pause(%d)", mName); - Mutex::Autolock _l(mAudioFlinger->mLock); + LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); if (mState == ACTIVE || mState == RESUMING) { mState = PAUSING; LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName); } } -void AudioFlinger::Track::flush() +void AudioFlinger::MixerThread::Track::flush() { LOGV("flush(%d)", mName); - Mutex::Autolock _l(mAudioFlinger->mLock); + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { return; } @@ -1298,7 +1889,7 @@ void AudioFlinger::Track::flush() reset(); } -void AudioFlinger::Track::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. @@ -1313,12 +1904,12 @@ void AudioFlinger::Track::reset() } } -void AudioFlinger::Track::mute(bool muted) +void AudioFlinger::MixerThread::Track::mute(bool muted) { mMute = muted; } -void AudioFlinger::Track::setVolume(float left, float right) +void AudioFlinger::MixerThread::Track::setVolume(float left, float right) { mVolume[0] = left; mVolume[1] = right; @@ -1326,7 +1917,292 @@ void AudioFlinger::Track::setVolume(float left, float right) // ---------------------------------------------------------------------------- -AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track) +// RecordTrack constructor must be called with AudioFlinger::mLock held +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() +{ + Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); + mMixerThread->deleteTrackName_l(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) { @@ -1386,8 +2262,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( uint32_t flags, status_t *status) { - sp<AudioRecordThread> thread; - sp<RecordTrack> recordTrack; + sp<MixerThread::RecordTrack> recordTrack; sp<RecordHandle> recordHandle; sp<Client> client; wp<Client> wclient; @@ -1414,12 +2289,6 @@ sp<IAudioRecord> AudioFlinger::openRecord( goto Exit; } - if (mSampleRate == 0) { - LOGE("Audio driver not initialized"); - lStatus = NO_INIT; - goto Exit; - } - if (mAudioRecordThread == 0) { LOGE("Audio record thread not started"); lStatus = NO_INIT; @@ -1436,7 +2305,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( } // add client to list - { + { // scope for mLock Mutex::Autolock _l(mLock); wclient = mClients.valueFor(pid); if (wclient != NULL) { @@ -1445,15 +2314,20 @@ sp<IAudioRecord> AudioFlinger::openRecord( 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 RecordTrack(this, client, streamType, sampleRate, - format, channelCount, frameCount); + // frameCount must be a multiple of input buffer size + inFrameCount = inputBufferSize/channelCount/sizeof(short); + frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount; + + // create new record track. The record track uses one track in mHardwareMixerThread by convention. + 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); @@ -1466,97 +2340,22 @@ Exit: return recordHandle; } -status_t AudioFlinger::startRecord(RecordTrack* recordTrack) { +status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) { if (mAudioRecordThread != 0) { return mAudioRecordThread->start(recordTrack); } return NO_INIT; } -void AudioFlinger::stopRecord(RecordTrack* recordTrack) { +void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) { if (mAudioRecordThread != 0) { mAudioRecordThread->stop(recordTrack); } } - -// ---------------------------------------------------------------------------- - -AudioFlinger::RecordTrack::RecordTrack( - const sp<AudioFlinger>& audioFlinger, - const sp<Client>& client, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount) - : TrackBase(audioFlinger, client, streamType, sampleRate, format, - channelCount, frameCount, 0), - mOverflow(false) -{ -} - -AudioFlinger::RecordTrack::~RecordTrack() -{ - mAudioFlinger->audioMixer()->deleteTrackName(mName); -} - -status_t AudioFlinger::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::RecordTrack::start() -{ - return mAudioFlinger->startRecord(this); -} - -void AudioFlinger::RecordTrack::stop() -{ - mAudioFlinger->stopRecord(this); - TrackBase::reset(); - // Force overerrun condition to avoid false overrun callback until first data is - // read from buffer - mCblk->flowControlFlag = 1; -} - // ---------------------------------------------------------------------------- -AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack) +AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack) : BnAudioRecord(), mRecordTrack(recordTrack) { @@ -1588,8 +2387,10 @@ status_t AudioFlinger::RecordHandle::onTransact( // ---------------------------------------------------------------------------- -AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) : +AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware, + const sp<AudioFlinger>& audioFlinger) : mAudioHardware(audioHardware), + mAudioFlinger(audioFlinger), mActive(false) { } @@ -1619,15 +2420,17 @@ bool AudioFlinger::AudioRecordThread::threadLoop() 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); + mRecordTrack->channelCount(), + mRecordTrack->sampleRate(), + &mStartStatus, + (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16)); if (input != 0) { inBufferSize = input->bufferSize(); inFrameCount = inBufferSize/input->frameSize(); @@ -1643,12 +2446,14 @@ bool AudioFlinger::AudioRecordThread::threadLoop() mWaitWorkCV.signal(); } mLock.unlock(); - } else if (mRecordTrack != 0){ + } else if (mRecordTrack != 0) { buffer.frameCount = inFrameCount; - if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) { + if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR && + (int)buffer.frameCount == inFrameCount)) { LOGV("AudioRecordThread read: %d frames", buffer.frameCount); - if (input->read(buffer.raw, inBufferSize) < 0) { + ssize_t bytesRead = input->read(buffer.raw, inBufferSize); + if (bytesRead < 0) { LOGE("Error reading audio input"); sleep(1); } @@ -1677,7 +2482,7 @@ bool AudioFlinger::AudioRecordThread::threadLoop() return false; } -status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) +status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack) { LOGV("AudioRecordThread::start"); AutoMutex lock(&mLock); @@ -1690,6 +2495,19 @@ status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) mRecordTrack = recordTrack; +#ifdef WITH_A2DP + { // scope for lock2 + + // AudioFlinger::mLock must be locked before calling + // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). + AutoMutex lock2(&mAudioFlinger->mLock); + + // Currently there is no way to detect if we are recording over SCO, + // so we disable A2DP during any recording. + mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED); + } +#endif + // signal thread to start LOGV("Signal record thread"); mWaitWorkCV.signal(); @@ -1698,11 +2516,24 @@ status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack) return mStartStatus; } -void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) { +void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) { LOGV("AudioRecordThread::stop"); AutoMutex lock(&mLock); if (mActive && (recordTrack == mRecordTrack.get())) { +#ifdef WITH_A2DP + { // scope for lock2 + + // AudioFlinger::mLock must be locked before calling + // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l(). + AutoMutex lock2(&mAudioFlinger->mLock); + + // Currently there is no way to detect if we are recording over SCO, + // so we disable A2DP during any recording. + mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED); + } +#endif mActive = false; + mStopped.wait(mLock); } } @@ -1717,6 +2548,22 @@ void AudioFlinger::AudioRecordThread::exit() 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) |