diff options
Diffstat (limited to 'libs/audioflinger/AudioFlinger.cpp')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 3233 |
1 files changed, 2102 insertions, 1131 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index f5bdeda..1336131 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -24,10 +24,10 @@ #include <sys/time.h> #include <sys/resource.h> -#include <utils/IServiceManager.h> +#include <binder/IServiceManager.h> #include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/IPCThreadState.h> +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> #include <utils/String16.h> #include <utils/threads.h> @@ -71,15 +71,9 @@ 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 @@ -121,131 +115,32 @@ static bool settingsAllowed() { AudioFlinger::AudioFlinger() : BnAudioFlinger(), - mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false), - mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0), - mRouteRestoreTime(0), mMusicMuteSaved(false) + mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(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, this); - if (mAudioRecordThread != 0) { - mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO); - } - } else { + } else { LOGE("Couldn't even initialize the stubbed audio hardware!"); } } 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 + mRecordThreads.clear(); + mPlaybackThreads.clear(); } -#ifdef WITH_A2DP -// setA2dpEnabled_l() must be called with AudioFlinger::mLock held -void AudioFlinger::setA2dpEnabled_l(bool enable) -{ - 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"); - - // 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); - } - mA2dpEnabled = enable; - mNotifyA2dpChange = true; - mWaitWorkCV.broadcast(); -} - -// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held -void AudioFlinger::checkA2dpEnabledChange_l() -{ - 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 - -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 || - streamType == AudioSystem::ENFORCED_AUDIBLE); -} status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args) { @@ -275,10 +170,7 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) 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()); @@ -336,13 +228,16 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) 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); + // dump playback threads + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + mPlaybackThreads[i]->dump(fd, args); + } + + // dump record threads + for (size_t i = 0; i < mRecordThreads.size(); i++) { + mRecordThreads[i]->dump(fd, args); + } if (mAudioHardware) { mAudioHardware->dumpState(fd, args); @@ -352,6 +247,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args) return NO_ERROR; } + // IAudioFlinger interface @@ -364,9 +260,10 @@ sp<IAudioTrack> AudioFlinger::createTrack( int frameCount, uint32_t flags, const sp<IMemory>& sharedBuffer, + void *output, status_t *status) { - sp<MixerThread::Track> track; + sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; wp<Client> wclient; @@ -380,6 +277,12 @@ sp<IAudioTrack> AudioFlinger::createTrack( { Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGE("unknown output thread"); + lStatus = BAD_VALUE; + goto Exit; + } wclient = mClients.valueFor(pid); @@ -389,16 +292,8 @@ sp<IAudioTrack> AudioFlinger::createTrack( 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); - } + track = thread->createTrack_l(client, streamType, sampleRate, format, + channelCount, frameCount, sharedBuffer, &lStatus); } if (lStatus == NO_ERROR) { trackHandle = new TrackHandle(track); @@ -413,54 +308,59 @@ Exit: return trackHandle; } -uint32_t AudioFlinger::sampleRate(int output) const +uint32_t AudioFlinger::sampleRate(void *output) const { -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->sampleRate(); - } -#endif - return mHardwareMixerThread->sampleRate(); + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGW("sampleRate() unknown thread %p", output); + return 0; + } + return thread->sampleRate(); } -int AudioFlinger::channelCount(int output) const +int AudioFlinger::channelCount(void *output) const { -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->channelCount(); - } -#endif - return mHardwareMixerThread->channelCount(); + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGW("channelCount() unknown thread %p", output); + return 0; + } + return thread->channelCount(); } -int AudioFlinger::format(int output) const +int AudioFlinger::format(void *output) const { -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->format(); - } -#endif - return mHardwareMixerThread->format(); + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGW("format() unknown thread %p", output); + return 0; + } + return thread->format(); } -size_t AudioFlinger::frameCount(int output) const +size_t AudioFlinger::frameCount(void *output) const { -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->frameCount(); - } -#endif - return mHardwareMixerThread->frameCount(); + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGW("frameCount() unknown thread %p", output); + return 0; + } + return thread->frameCount(); } -uint32_t AudioFlinger::latency(int output) const +uint32_t AudioFlinger::latency(void *output) const { -#ifdef WITH_A2DP - if (output == AudioSystem::AUDIO_OUTPUT_A2DP) { - return mA2dpMixerThread->latency(); - } -#endif - return mHardwareMixerThread->latency(); + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + LOGW("latency() unknown thread %p", output); + return 0; + } + return thread->latency(); } status_t AudioFlinger::setMasterVolume(float value) @@ -477,94 +377,12 @@ status_t AudioFlinger::setMasterVolume(float value) 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 - LOGV("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"); - } - // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when - // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only - // in this case to avoid doing it several times. - if (mode == AudioSystem::MODE_IN_CALL && - (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) { - AutoMutex lock(&mLock); - handleRouteDisablesA2dp_l(routes); - } -#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; -} + mMasterVolume = value; + for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + mPlaybackThreads[i]->setMasterVolume(value); -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; + return NO_ERROR; } status_t AudioFlinger::setMode(int mode) @@ -585,15 +403,6 @@ status_t AudioFlinger::setMode(int mode) 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 @@ -623,36 +432,46 @@ status_t AudioFlinger::setMasterMute(bool muted) if (!settingsAllowed()) { return PERMISSION_DENIED; } - mHardwareMixerThread->setMasterMute(muted); -#ifdef WITH_A2DP - mA2dpMixerThread->setMasterMute(muted); -#endif + + mMasterMute = muted; + for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + mPlaybackThreads[i]->setMasterMute(muted); + return NO_ERROR; } float AudioFlinger::masterVolume() const { - return mHardwareMixerThread->masterVolume(); + return mMasterVolume; } bool AudioFlinger::masterMute() const { - return mHardwareMixerThread->masterMute(); + return mMasterMute; } -status_t AudioFlinger::setStreamVolume(int stream, float value) +status_t AudioFlinger::setStreamVolume(int stream, float value, void *output) { // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; } - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || - uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) { + if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return BAD_VALUE; } + AutoMutex lock(mLock); + PlaybackThread *thread = NULL; + if (output) { + thread = checkPlaybackThread_l(output); + if (thread == NULL) { + return BAD_VALUE; + } + } + status_t ret = NO_ERROR; + if (stream == AudioSystem::VOICE_CALL || stream == AudioSystem::BLUETOOTH_SCO) { float hwValue; @@ -669,12 +488,18 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) 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 + mStreamTypes[stream].volume = value; + + if (thread == NULL) { + for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + mPlaybackThreads[i]->setStreamVolume(stream, value); + + } else { + thread->setStreamVolume(stream, value); + } return ret; } @@ -686,82 +511,116 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted) return PERMISSION_DENIED; } - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || + if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES || uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) { 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); - } + mStreamTypes[stream].mute = muted; + for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + mPlaybackThreads[i]->setStreamMute(stream, muted); return NO_ERROR; } -float AudioFlinger::streamVolume(int stream) const +float AudioFlinger::streamVolume(int stream, void *output) const { - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { + if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { return 0.0f; } - - float volume = mHardwareMixerThread->streamVolume(stream); + + AutoMutex lock(mLock); + float volume; + if (output) { + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread == NULL) { + return 0.0f; + } + volume = thread->streamVolume(stream); + } else { + volume = mStreamTypes[stream].volume; + } + // remove correction applied by setStreamVolume() if (stream == AudioSystem::VOICE_CALL) { volume = (volume - 0.01) / 0.99 ; } - + return volume; } bool AudioFlinger::streamMute(int stream) const { - if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) { + if (stream < 0 || stream >= (int)AudioSystem::NUM_STREAM_TYPES) { return true; } - - if (stream == AudioSystem::MUSIC && mForcedRoute != 0) - { - return mMusicMuteSaved; - } - return mHardwareMixerThread->streamMute(stream); + + return mStreamTypes[stream].mute; } bool AudioFlinger::isMusicActive() const { Mutex::Autolock _l(mLock); - #ifdef WITH_A2DP - if (isA2dpEnabled()) { - return mA2dpMixerThread->isMusicActive_l(); - } - #endif - return mHardwareMixerThread->isMusicActive_l(); + for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads[i]->isMusicActive()) { + return true; + } + } + return false; } -status_t AudioFlinger::setParameter(const char* key, const char* value) +status_t AudioFlinger::setParameters(void *ioHandle, const String8& keyValuePairs) { - 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; + status_t result; + + LOGV("setParameters(): io %p, keyvalue %s, tid %d, calling tid %d", + ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid()); + // check calling permissions + if (!settingsAllowed()) { + return PERMISSION_DENIED; } - mHardwareStatus = AUDIO_HW_IDLE; - return result; + + // ioHandle == 0 means the parameters are global to the audio hardware interface + if (ioHandle == 0) { + AutoMutex lock(mHardwareLock); + mHardwareStatus = AUDIO_SET_PARAMETER; + result = mAudioHardware->setParameters(keyValuePairs); + mHardwareStatus = AUDIO_HW_IDLE; + return result; + } + + // Check if parameters are for an output + PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle); + if (playbackThread != NULL) { + return playbackThread->setParameters(keyValuePairs); + } + + // Check if parameters are for an input + RecordThread *recordThread = checkRecordThread_l(ioHandle); + if (recordThread != NULL) { + return recordThread->setParameters(keyValuePairs); + } + + return BAD_VALUE; +} + +String8 AudioFlinger::getParameters(void *ioHandle, const String8& keys) +{ +// LOGV("getParameters() io %p, keys %s, tid %d, calling tid %d", +// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid()); + + if (ioHandle == 0) { + return mAudioHardware->getParameters(keys); + } + PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle); + if (playbackThread != NULL) { + return playbackThread->getParameters(keys); + } + RecordThread *recordThread = checkRecordThread_l(ioHandle); + if (recordThread != NULL) { + return recordThread->getParameters(keys); + } + return String8(""); } size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) @@ -771,7 +630,7 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha 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); @@ -780,12 +639,21 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) LOGV("Adding notification client %p", binder.get()); binder->linkToDeath(this); mNotificationClients.add(binder); - client->a2dpEnabledChanged(isA2dpEnabled()); + } + + // the config change is always sent from playback or record threads to avoid deadlock + // with AudioSystem::gLock + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + mPlaybackThreads[i]->sendConfigEvent(AudioSystem::OUTPUT_OPENED); + } + + for (size_t i = 0; i < mRecordThreads.size(); i++) { + mRecordThreads[i]->sendConfigEvent(AudioSystem::INPUT_OPENED); } } 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); @@ -800,6 +668,17 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) { } } +void AudioFlinger::audioConfigChanged(int event, void *param1, void *param2) { + Mutex::Autolock _l(mLock); + size_t size = mNotificationClients.size(); + for (size_t i = 0; i < size; i++) { + sp<IBinder> binder = mNotificationClients.itemAt(i); + LOGV("audioConfigChanged() Notifying change to client %p", binder.get()); + sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder); + client->ioConfigChanged(event, param1, param2); + } +} + void AudioFlinger::removeClient(pid_t pid) { LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid()); @@ -807,147 +686,139 @@ void AudioFlinger::removeClient(pid_t pid) mClients.removeItem(pid); } -bool AudioFlinger::isA2dpEnabled() const +// ---------------------------------------------------------------------------- + +AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger) + : Thread(false), + mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), + mFormat(0), mFrameSize(1), mNewParameters(String8("")), mStandby(false) { - return mA2dpEnabled; } -void AudioFlinger::handleForcedSpeakerRoute(int command) +AudioFlinger::ThreadBase::~ThreadBase() { - switch(command) { - case ACTIVE_TRACK_ADDED: - { - AutoMutex lock(mHardwareLock); - if (mForcedSpeakerCount++ == 0) { - if (mForcedRoute == 0) { - mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC); - LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime); - if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) { - LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER); - mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true); - 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); - } - } - mForcedRoute = AudioSystem::ROUTE_SPEAKER; - mRouteRestoreTime = 0; - } - 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 -// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held -void AudioFlinger::handleRouteDisablesA2dp_l(int routes) -{ - if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) { - if (mA2dpDisableCount++ == 0) { - if (mA2dpEnabled) { - setA2dpEnabled_l(false); - mA2dpSuppressed = true; - } - } - LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount); - } else { - if (mA2dpDisableCount > 0) { - if (--mA2dpDisableCount == 0) { - if (mA2dpSuppressed) { - setA2dpEnabled_l(true); - mA2dpSuppressed = false; - } - } - LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount); - } else { - LOGV("mA2dpDisableCount is already zero"); - } +void AudioFlinger::ThreadBase::exit() +{ + // keep a strong ref on ourself so that we want get + // destroyed in the middle of requestExitAndWait() + sp <ThreadBase> strongMe = this; + + LOGV("ThreadBase::exit"); + { + AutoMutex lock(&mLock); + requestExit(); + mWaitWorkCV.signal(); } + requestExitAndWait(); } -#endif -// ---------------------------------------------------------------------------- +uint32_t AudioFlinger::ThreadBase::sampleRate() const +{ + return mSampleRate; +} -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) +int AudioFlinger::ThreadBase::channelCount() const { - mSampleRate = output->sampleRate(); - mChannelCount = output->channelCount(); + return mChannelCount; +} - // FIXME - Current mixer implementation only supports stereo output - if (mChannelCount == 1) { - LOGE("Invalid audio hardware channel count"); +int AudioFlinger::ThreadBase::format() const +{ + return mFormat; +} + +size_t AudioFlinger::ThreadBase::frameCount() const +{ + return mFrameCount; +} + +status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs) +{ + status_t result; + + Mutex::Autolock _l(mLock); + mNewParameters = keyValuePairs; + + mWaitWorkCV.signal(); + mParamCond.wait(mLock); + + return mParamStatus; +} + +void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param) +{ + Mutex::Autolock _l(mLock); + ConfigEvent *configEvent = new ConfigEvent(); + configEvent->mEvent = event; + configEvent->mParam = param; + mConfigEvents.add(configEvent); + LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param); + mWaitWorkCV.signal(); +} + +void AudioFlinger::ThreadBase::processConfigEvents() +{ + mLock.lock(); + while(!mConfigEvents.isEmpty()) { + LOGV("processConfigEvents() remaining events %d", mConfigEvents.size()); + ConfigEvent *configEvent = mConfigEvents[0]; + mConfigEvents.removeAt(0); + // release mLock because audioConfigChanged() will call + // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating + // potential cross deadlock between AudioFlinger::mLock and mLock + mLock.unlock(); + audioConfigChanged(configEvent->mEvent, configEvent->mParam); + delete configEvent; + mLock.lock(); } + mLock.unlock(); +} - 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::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output) + : ThreadBase(audioFlinger), + mMixBuffer(0), mSuspended(false), mBytesWritten(0), mOutput(output), + mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) +{ + readOutputParameters(); + + mMasterVolume = mAudioFlinger->masterVolume(); + mMasterMute = mAudioFlinger->masterMute(); + + for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { + mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); + mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); + } + // notify client processes that a new input has been opened + sendConfigEvent(AudioSystem::OUTPUT_OPENED); } -AudioFlinger::MixerThread::~MixerThread() +AudioFlinger::PlaybackThread::~PlaybackThread() { delete [] mMixBuffer; - delete mAudioMixer; + if (mType != DUPLICATING) { + mAudioFlinger->mAudioHardware->closeOutputStream(mOutput); + } } -status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args) +status_t AudioFlinger::PlaybackThread::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) +status_t AudioFlinger::PlaybackThread::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); + snprintf(buffer, SIZE, "Output thread %p tracks\n", this); 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) { @@ -958,7 +829,7 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a } } - snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType); + snprintf(buffer, SIZE, "Output thread %p active tracks\n", this); 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) { @@ -975,15 +846,13 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a return NO_ERROR; } -status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) +status_t AudioFlinger::PlaybackThread::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()); + snprintf(buffer, SIZE, "Output thread %p internals\n", this); result.append(buffer); snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime)); result.append(buffer); @@ -1000,238 +869,354 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16> } // Thread virtuals +status_t AudioFlinger::PlaybackThread::readyToRun() +{ + if (mSampleRate == 0) { + LOGE("No working audio driver found."); + return NO_INIT; + } + LOGI("AudioFlinger's thread %p ready to run", this); + return NO_ERROR; +} + +void AudioFlinger::PlaybackThread::onFirstRef() +{ + const size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, "Playback Thread %p", this); + + run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); +} + +// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held +sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( + 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; + + if (mType == DIRECT) { + if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) { + LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p", + sampleRate, format, channelCount, mOutput); + lStatus = BAD_VALUE; + goto Exit; + } + } else { + // Resampler implementation limits input sampling rate to 2 x output sampling rate. + if (sampleRate > mSampleRate*2) { + LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); + lStatus = BAD_VALUE; + goto Exit; + } + } + + if (mOutput == 0) { + LOGE("Audio driver not initialized."); + lStatus = NO_INIT; + goto Exit; + } + + { // scope for mLock + 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; + +Exit: + if(status) { + *status = lStatus; + } + return track; +} + +uint32_t AudioFlinger::PlaybackThread::latency() const +{ + if (mOutput) { + return mOutput->latency(); + } + else { + return 0; + } +} + +status_t AudioFlinger::PlaybackThread::setMasterVolume(float value) +{ + mMasterVolume = value; + return NO_ERROR; +} + +status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted) +{ + mMasterMute = muted; + return NO_ERROR; +} + +float AudioFlinger::PlaybackThread::masterVolume() const +{ + return mMasterVolume; +} + +bool AudioFlinger::PlaybackThread::masterMute() const +{ + return mMasterMute; +} + +status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value) +{ + mStreamTypes[stream].volume = value; + return NO_ERROR; +} + +status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted) +{ + mStreamTypes[stream].mute = muted; + return NO_ERROR; +} + +float AudioFlinger::PlaybackThread::streamVolume(int stream) const +{ + return mStreamTypes[stream].volume; +} + +bool AudioFlinger::PlaybackThread::streamMute(int stream) const +{ + return mStreamTypes[stream].mute; +} + +bool AudioFlinger::PlaybackThread::isMusicActive() const +{ + Mutex::Autolock _l(mLock); + 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->type() == AudioSystem::MUSIC) + return true; + } + return false; +} + +// addTrack_l() must be called with ThreadBase::mLock held +status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) +{ + status_t status = ALREADY_EXISTS; + + // 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; + mActiveTracks.add(track); + status = NO_ERROR; + } + + LOGV("mWaitWorkCV.broadcast"); + mWaitWorkCV.broadcast(); + + return status; +} + +// destroyTrack_l() must be called with ThreadBase::mLock held +void AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track) +{ + track->mState = TrackBase::TERMINATED; + if (mActiveTracks.indexOf(track) < 0) { + LOGV("remove track (%d) and delete from mixer", track->name()); + mTracks.remove(track); + deleteTrackName_l(track->name()); + } +} + +String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys) +{ + return mOutput->getParameters(keys); +} + +void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) { + AudioSystem::OutputDescriptor desc; + void *param2 = 0; + + LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param); + + switch (event) { + case AudioSystem::OUTPUT_OPENED: + case AudioSystem::OUTPUT_CONFIG_CHANGED: + desc.channels = mChannelCount; + desc.samplingRate = mSampleRate; + desc.format = mFormat; + desc.frameCount = mFrameCount; + desc.latency = latency(); + param2 = &desc; + break; + + case AudioSystem::STREAM_CONFIG_CHANGED: + param2 = ¶m; + case AudioSystem::OUTPUT_CLOSED: + default: + break; + } + mAudioFlinger->audioConfigChanged(event, this, param2); +} + +void AudioFlinger::PlaybackThread::readOutputParameters() +{ + mSampleRate = mOutput->sampleRate(); + mChannelCount = AudioSystem::popCount(mOutput->channels()); + + mFormat = mOutput->format(); + mFrameSize = mOutput->frameSize(); + mFrameCount = mOutput->bufferSize() / mFrameSize; + + mMinBytesToWrite = (mOutput->latency() * mSampleRate * mFrameSize) / 1000; + // FIXME - Current mixer implementation only supports stereo output: Always + // Allocate a stereo buffer even if HW output is mono. + if (mMixBuffer != NULL) delete mMixBuffer; + mMixBuffer = new int16_t[mFrameCount * 2]; + memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); +} + +// ---------------------------------------------------------------------------- + +AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output) + : PlaybackThread(audioFlinger, output), + mAudioMixer(0) +{ + mType = PlaybackThread::MIXER; + mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); + + // FIXME - Current mixer implementation only supports stereo output + if (mChannelCount == 1) { + LOGE("Invalid audio hardware channel count"); + } +} + +AudioFlinger::MixerThread::~MixerThread() +{ + delete mAudioMixer; +} + 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 standbyTime = systemTime(); + size_t mixBufferSize = mFrameCount * mFrameSize; nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2; -#ifdef WITH_A2DP - bool outputTrackActive = false; -#endif + while (!exitPending()) + { + processConfigEvents(); - do { enabledTracks = 0; - { // scope for the AudioFlinger::mLock - - Mutex::Autolock _l(mAudioFlinger->mLock); + { // scope for mLock -#ifdef WITH_A2DP - if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) { - if (outputTrackActive) { - mAudioFlinger->mLock.unlock(); - mOutputTrack->stop(); - mAudioFlinger->mLock.lock(); - outputTrackActive = false; - } + Mutex::Autolock _l(mLock); + + if (checkForNewParameters_l()) { + mixBufferSize = mFrameCount * mFrameSize; + maxPeriod = seconds(mFrameCount) / mSampleRate * 2; } - 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, output %d\n", mOutputType); + if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || + mSuspended) { if (!mStandby) { + LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended); mOutput->standby(); mStandby = true; + mBytesWritten = 0; } - -#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(); - 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; - } - // Forced route to speaker is handled by hardware mixer thread - if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) { - mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME); - } + if (!activeTracks.size() && mConfigEvents.isEmpty()) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); - // 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; + if (exitPending()) break; - Track* const track = t.get(); - audio_track_cblk_t* cblk = track->cblk(); + // wait until we have something to do... + LOGV("MixerThread %p TID %d going to sleep\n", this, gettid()); + mWaitWorkCV.wait(mLock); + LOGV("MixerThread %p TID %d waking up\n", this, gettid()); - // 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(); + if (mMasterMute == false) { + char value[PROPERTY_VALUE_MAX]; + property_get("ro.audio.silent", value, "0"); + if (atoi(value)) { + LOGD("Silence is golden"); + setMasterMute(true); } - } 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); + standbyTime = systemTime() + kStandbyTimeInNsecs; + continue; } } - // 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_l(track); - if (track->isTerminated()) { - mTracks.remove(track); - deleteTrackName_l(track->mName); - } - } - } + enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); } - + 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; - } + if (mSuspended) { + usleep(kMaxBufferRecoveryInUsecs); + } else { + mLastWriteTime = systemTime(); + mInWrite = true; + int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); + if (bytesWritten > 0) mBytesWritten += bytesWritten; + 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; } -#endif + } else { // 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("thread %p no buffers - usleep(%lu)", this, sleepTime); usleep(sleepTime); if (sleepTime < kMaxBufferRecoveryInUsecs) { sleepTime += kBufferRecoveryInUsecs; @@ -1242,101 +1227,165 @@ bool AudioFlinger::MixerThread::threadLoop() // 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; + if (!mStandby) { + mOutput->standby(); } - LOGI("AudioFlinger's thread ready to run for output %d", mOutputType); - return NO_ERROR; + sendConfigEvent(AudioSystem::OUTPUT_CLOSED); + processConfigEvents(); + + LOGV("MixerThread %p exiting", this); + return false; } -void AudioFlinger::MixerThread::onFirstRef() +// prepareTracks_l() must be called with ThreadBase::mLock held +size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove) { - const size_t SIZE = 256; - char buffer[SIZE]; - snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType); - - run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); -} + size_t enabledTracks = 0; + // 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; -// 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, - 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 > mSampleRate*2) { - LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); - lStatus = BAD_VALUE; - goto Exit; - } + 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() || + mStreamTypes[track->type()].mute) { + left = right = 0; + if (track->isPausing()) { + 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); + } - if (mSampleRate == 0) { - LOGE("Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; + // 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. + tracksToRemove->add(track); + mAudioMixer->disable(AudioMixer::MIXING); + } 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); + } + // For tracks using static shared memry buffer, make sure that we have + // written enough data to audio hardware before disabling the track + // NOTE: this condition with arrive before track->mRetryCount <= 0 so we + // don't care about code removing track from active list above. + if ((track->mSharedBuffer == 0) || (mBytesWritten >= mMinBytesToWrite)) { + mAudioMixer->disable(AudioMixer::MIXING); + } else { + enabledTracks++; + } + } + } } - track = new Track(this, client, streamType, sampleRate, format, - channelCount, frameCount, sharedBuffer); - if (track->getCblk() == NULL) { - lStatus = NO_MEMORY; - goto Exit; + // 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->itemAt(i); + mActiveTracks.remove(track); + if (track->isTerminated()) { + mTracks.remove(track); + deleteTrackName_l(track->mName); + } + } } - mTracks.add(track); - lStatus = NO_ERROR; -Exit: - if(status) { - *status = lStatus; - } - return track; + return enabledTracks; } -// getTracks_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::getTracks_l( +void AudioFlinger::MixerThread::getTracks( SortedVector < sp<Track> >& tracks, - SortedVector < wp<Track> >& activeTracks) + SortedVector < wp<Track> >& activeTracks, + int streamType) { + LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.size()); + Mutex::Autolock _l(mLock); 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)) { + if (t->type() == streamType) { tracks.add(t); int j = mActiveTracks.indexOf(t); if (j >= 0) { t = mActiveTracks[j].promote(); if (t != NULL) { - activeTracks.add(t); - } + activeTracks.add(t); + } } } } size = activeTracks.size(); for (size_t i = 0; i < size; i++) { - removeActiveTrack_l(activeTracks[i]); + mActiveTracks.remove(activeTracks[i]); } - + size = tracks.size(); for (size_t i = 0; i < size; i++) { sp<Track> t = tracks[i]; @@ -1345,219 +1394,554 @@ void AudioFlinger::MixerThread::getTracks_l( } } -// putTracks_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::putTracks_l( +void AudioFlinger::MixerThread::putTracks( SortedVector < sp<Track> >& tracks, SortedVector < wp<Track> >& activeTracks) { - - LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size()); - + LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this, tracks.size(), activeTracks.size()); + Mutex::Autolock _l(mLock); size_t size = tracks.size(); for (size_t i = 0; i < size ; i++) { sp<Track> t = tracks[i]; int name = getTrackName_l(); if (name < 0) return; - + t->mName = name; - t->mMixerThread = this; + t->mThread = this; mTracks.add(t); int j = activeTracks.indexOf(t); if (j >= 0) { - addActiveTrack_l(t); - } + mActiveTracks.add(t); + } } } -uint32_t AudioFlinger::MixerThread::sampleRate() const -{ - return mSampleRate; -} - -int AudioFlinger::MixerThread::channelCount() const +// getTrackName_l() must be called with ThreadBase::mLock held +int AudioFlinger::MixerThread::getTrackName_l() { - return mChannelCount; + return mAudioMixer->getTrackName(); } -int AudioFlinger::MixerThread::format() const +// deleteTrackName_l() must be called with ThreadBase::mLock held +void AudioFlinger::MixerThread::deleteTrackName_l(int name) { - return mFormat; + mAudioMixer->deleteTrackName(name); } -size_t AudioFlinger::MixerThread::frameCount() const +// checkForNewParameters_l() must be called with ThreadBase::mLock held +bool AudioFlinger::MixerThread::checkForNewParameters_l() { - return mFrameCount; -} + bool reconfig = false; -uint32_t AudioFlinger::MixerThread::latency() const -{ - if (mOutput) { - return mOutput->latency(); - } - else { - return 0; + if (mNewParameters != "") { + status_t status = NO_ERROR; + AudioParameter param = AudioParameter(mNewParameters); + int value; + if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) { + reconfig = true; + } + if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { + if (value != AudioSystem::PCM_16_BIT) { + status = BAD_VALUE; + } else { + reconfig = true; + } + } + if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { + if (value != AudioSystem::CHANNEL_OUT_STEREO) { + status = BAD_VALUE; + } else { + reconfig = true; + } + } + if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { + // do not accept frame count changes if tracks are open as the track buffer + // size depends on frame count and correct behavior would not be garantied + // if frame count is changed after track creation + if (!mTracks.isEmpty()) { + status = INVALID_OPERATION; + } else { + reconfig = true; + } + } + if (status == NO_ERROR) { + status = mOutput->setParameters(mNewParameters); + if (!mStandby && status == INVALID_OPERATION) { + mOutput->standby(); + mStandby = true; + mBytesWritten = 0; + status = mOutput->setParameters(mNewParameters); + } + if (status == NO_ERROR && reconfig) { + delete mAudioMixer; + readOutputParameters(); + mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); + for (size_t i = 0; i < mTracks.size() ; i++) { + int name = getTrackName_l(); + if (name < 0) break; + mTracks[i]->mName = name; + } + sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED); + } + } + mParamStatus = status; + mNewParameters = ""; + mParamCond.signal(); } + return reconfig; } -status_t AudioFlinger::MixerThread::setMasterVolume(float value) +status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args) { - mMasterVolume = value; + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + PlaybackThread::dumpInternals(fd, args); + + snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames()); + result.append(buffer); + write(fd, result.string(), result.size()); return NO_ERROR; } -status_t AudioFlinger::MixerThread::setMasterMute(bool muted) +// ---------------------------------------------------------------------------- +AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output) + : PlaybackThread(audioFlinger, output), + mLeftVolume (1.0), mRightVolume(1.0) { - mMasterMute = muted; - return NO_ERROR; + mType = PlaybackThread::DIRECT; } -float AudioFlinger::MixerThread::masterVolume() const +AudioFlinger::DirectOutputThread::~DirectOutputThread() { - return mMasterVolume; } -bool AudioFlinger::MixerThread::masterMute() const + +bool AudioFlinger::DirectOutputThread::threadLoop() { - return mMasterMute; + unsigned long sleepTime = kBufferRecoveryInUsecs; + sp<Track> trackToRemove; + sp<Track> activeTrack; + nsecs_t standbyTime = systemTime(); + int8_t *curBuf; + size_t mixBufferSize = mFrameCount*mFrameSize; + + while (!exitPending()) + { + processConfigEvents(); + + { // scope for the mLock + + Mutex::Autolock _l(mLock); + + if (checkForNewParameters_l()) { + mixBufferSize = mFrameCount*mFrameSize; + } + + // put audio hardware into standby after short delay + if UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || + mSuspended) { + // wait until we have something to do... + if (!mStandby) { + LOGV("Audio hardware entering standby, mixer %p\n", this); + mOutput->standby(); + mStandby = true; + mBytesWritten = 0; + } + + if (!mActiveTracks.size() && mConfigEvents.isEmpty()) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + + if (exitPending()) break; + + LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid()); + mWaitWorkCV.wait(mLock); + LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid()); + + 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; + } + } + + // find out which tracks need to be processed + if (mActiveTracks.size() != 0) { + sp<Track> t = mActiveTracks[0].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 + 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 + float left, right; + if (track->isMuted() || mMasterMute || track->isPausing() || + mStreamTypes[track->type()].mute) { + left = right = 0; + if (track->isPausing()) { + 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 = v_clamped/MAX_GAIN; + v_clamped = v * cblk->volume[1]; + if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN; + right = v_clamped/MAX_GAIN; + } + + if (left != mLeftVolume || right != mRightVolume) { + mOutput->setVolume(left, right); + left = mLeftVolume; + right = mRightVolume; + } + + if (track->mFillingUpStatus == Track::FS_FILLED) { + track->mFillingUpStatus = Track::FS_ACTIVE; + if (track->mState == TrackBase::RESUMING) { + track->mState = TrackBase::ACTIVE; + } + } + + // reset retry count + track->mRetryCount = kMaxTrackRetries; + activeTrack = t; + } 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. + trackToRemove = 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()); + trackToRemove = track; + } + + // For tracks using static shared memry buffer, make sure that we have + // written enough data to audio hardware before disabling the track + // NOTE: this condition with arrive before track->mRetryCount <= 0 so we + // don't care about code removing track from active list above. + if ((track->mSharedBuffer != 0) && (mBytesWritten < mMinBytesToWrite)) { + activeTrack = t; + } + } + } + } + + // remove all the tracks that need to be... + if (UNLIKELY(trackToRemove != 0)) { + mActiveTracks.remove(trackToRemove); + if (trackToRemove->isTerminated()) { + mTracks.remove(trackToRemove); + deleteTrackName_l(trackToRemove->mName); + } + } + } + + if (activeTrack != 0) { + AudioBufferProvider::Buffer buffer; + size_t frameCount = mFrameCount; + curBuf = (int8_t *)mMixBuffer; + // output audio to hardware + mLastWriteTime = systemTime(); + mInWrite = true; + while(frameCount) { + buffer.frameCount = frameCount; + activeTrack->getNextBuffer(&buffer); + if (UNLIKELY(buffer.raw == 0)) { + memset(curBuf, 0, frameCount * mFrameSize); + break; + } + memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize); + frameCount -= buffer.frameCount; + curBuf += buffer.frameCount * mFrameSize; + activeTrack->releaseBuffer(&buffer); + } + if (mSuspended) { + usleep(kMaxBufferRecoveryInUsecs); + } else { + int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize); + if (bytesWritten) mBytesWritten += bytesWritten; + mNumWrites++; + mInWrite = false; + mStandby = false; + nsecs_t temp = systemTime(); + standbyTime = temp + kStandbyTimeInNsecs; + sleepTime = kBufferRecoveryInUsecs; + } + } else { + // 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 removed track, without the lock held + // since we can't guarantee the destructors won't acquire that + // same lock. + trackToRemove.clear(); + activeTrack.clear(); + } + + if (!mStandby) { + mOutput->standby(); + } + sendConfigEvent(AudioSystem::OUTPUT_CLOSED); + processConfigEvents(); + + LOGV("DirectOutputThread %p exiting", this); + return false; } -status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value) +// getTrackName_l() must be called with ThreadBase::mLock held +int AudioFlinger::DirectOutputThread::getTrackName_l() { - mStreamTypes[stream].volume = value; - return NO_ERROR; + return 0; } -status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted) +// deleteTrackName_l() must be called with ThreadBase::mLock held +void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name) { - mStreamTypes[stream].mute = muted; - return NO_ERROR; } -float AudioFlinger::MixerThread::streamVolume(int stream) const +// checkForNewParameters_l() must be called with ThreadBase::mLock held +bool AudioFlinger::DirectOutputThread::checkForNewParameters_l() { - return mStreamTypes[stream].volume; + bool reconfig = false; + + if (mNewParameters != "") { + status_t status = NO_ERROR; + AudioParameter param = AudioParameter(mNewParameters); + int value; + if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { + // do not accept frame count changes if tracks are open as the track buffer + // size depends on frame count and correct behavior would not be garantied + // if frame count is changed after track creation + if (!mTracks.isEmpty()) { + status = INVALID_OPERATION; + } else { + reconfig = true; + } + } + if (status == NO_ERROR) { + status = mOutput->setParameters(mNewParameters); + if (!mStandby && status == INVALID_OPERATION) { + mOutput->standby(); + mStandby = true; + mBytesWritten = 0; + status = mOutput->setParameters(mNewParameters); + } + if (status == NO_ERROR && reconfig) { + readOutputParameters(); + sendConfigEvent(AudioSystem::OUTPUT_CONFIG_CHANGED); + } + } + mParamStatus = status; + mNewParameters = ""; + mParamCond.signal(); + } + return reconfig; } -bool AudioFlinger::MixerThread::streamMute(int stream) const +// ---------------------------------------------------------------------------- + +AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread) + : MixerThread(audioFlinger, mainThread->getOutput()) { - return mStreamTypes[stream].mute; + mType = PlaybackThread::DUPLICATING; + addOutputTrack(mainThread); } -// isMusicActive_l() must be called with AudioFlinger::mLock held -bool AudioFlinger::MixerThread::isMusicActive_l() const +AudioFlinger::DuplicatingThread::~DuplicatingThread() { - 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; + mOutputTracks.clear(); } -// addTrack_l() must be called with AudioFlinger::mLock held -status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track) +bool AudioFlinger::DuplicatingThread::threadLoop() { - status_t status = ALREADY_EXISTS; + unsigned long sleepTime = kBufferRecoveryInUsecs; + int16_t* curBuf = mMixBuffer; + Vector< sp<Track> > tracksToRemove; + size_t enabledTracks = 0; + nsecs_t standbyTime = systemTime(); + size_t mixBufferSize = mFrameCount*mFrameSize; + SortedVector< sp<OutputTrack> > outputTracks; - // 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_l(track); - status = NO_ERROR; - } - - LOGV("mWaitWorkCV.broadcast"); - mAudioFlinger->mWaitWorkCV.broadcast(); + while (!exitPending()) + { + processConfigEvents(); - return status; -} + enabledTracks = 0; + { // scope for the mLock -// destroyTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track) -{ - track->mState = TrackBase::TERMINATED; - if (mActiveTracks.indexOf(track) < 0) { - LOGV("remove track (%d) and delete from mixer", track->name()); - mTracks.remove(track); - deleteTrackName_l(track->name()); - } -} + Mutex::Autolock _l(mLock); -// addActiveTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t) -{ - mActiveTracks.add(t); + if (checkForNewParameters_l()) { + mixBufferSize = mFrameCount*mFrameSize; + } - // 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); - } - } -} + const SortedVector< wp<Track> >& activeTracks = mActiveTracks; -// removeActiveTrack_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t) -{ - mActiveTracks.remove(t); + for (size_t i = 0; i < mOutputTracks.size(); i++) { + outputTracks.add(mOutputTracks[i]); + } + + // put audio hardware into standby after short delay + if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || + mSuspended) { + if (!mStandby) { + for (size_t i = 0; i < outputTracks.size(); i++) { + mLock.unlock(); + outputTracks[i]->stop(); + mLock.lock(); + } + mStandby = true; + mBytesWritten = 0; + } + + if (!activeTracks.size() && mConfigEvents.isEmpty()) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + outputTracks.clear(); + + if (exitPending()) break; + + LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid()); + mWaitWorkCV.wait(mLock); + LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid()); + 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; + sleepTime = kBufferRecoveryInUsecs; + continue; + } + } - // 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; + enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove); + } - if (streamForcedToSpeaker(track->type())) { - mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED); + bool mustSleep = true; + if (LIKELY(enabledTracks)) { + // mix buffers... + mAudioMixer->process(curBuf); + if (!mSuspended) { + for (size_t i = 0; i < outputTracks.size(); i++) { + outputTracks[i]->write(curBuf, mFrameCount); + } + mStandby = false; + mustSleep = false; + mBytesWritten += mixBufferSize; + } + } else { + // flush remaining overflow buffers in output tracks + for (size_t i = 0; i < outputTracks.size(); i++) { + if (outputTracks[i]->isActive()) { + outputTracks[i]->write(curBuf, 0); + standbyTime = systemTime() + kStandbyTimeInNsecs; + mustSleep = false; + } + } } + if (mustSleep) { +// LOGV("threadLoop() sleeping %d", sleepTime); + usleep(sleepTime); + if (sleepTime < kMaxBufferRecoveryInUsecs) { + sleepTime += kBufferRecoveryInUsecs; + } + } else { + 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(); + outputTracks.clear(); } -} -// getTrackName_l() must be called with AudioFlinger::mLock held -int AudioFlinger::MixerThread::getTrackName_l() -{ - return mAudioMixer->getTrackName(); + if (!mStandby) { + for (size_t i = 0; i < outputTracks.size(); i++) { + mLock.unlock(); + outputTracks[i]->stop(); + mLock.lock(); + } + } + + sendConfigEvent(AudioSystem::OUTPUT_CLOSED); + processConfigEvents(); + + return false; } -// deleteTrackName_l() must be called with AudioFlinger::mLock held -void AudioFlinger::MixerThread::deleteTrackName_l(int name) +void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { - mAudioMixer->deleteTrackName(name); + int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate(); + OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread, + mSampleRate, + mFormat, + mChannelCount, + frameCount); + thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f); + mOutputTracks.add(outputTrack); + LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); } -size_t AudioFlinger::MixerThread::getOutputFrameCount() +void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread) { - return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t); + Mutex::Autolock _l(mLock); + for (size_t i = 0; i < mOutputTracks.size(); i++) { + if (mOutputTracks[i]->thread() == (ThreadBase *)thread) { + mOutputTracks.removeAt(i); + return; + } + } + LOGV("removeOutputTrack(): unkonwn thread: %p", thread); } + // ---------------------------------------------------------------------------- // TrackBase constructor must be called with AudioFlinger::mLock held -AudioFlinger::MixerThread::TrackBase::TrackBase( - const sp<MixerThread>& mixerThread, +AudioFlinger::ThreadBase::TrackBase::TrackBase( + const wp<ThreadBase>& thread, const sp<Client>& client, uint32_t sampleRate, int format, @@ -1566,7 +1950,7 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( uint32_t flags, const sp<IMemory>& sharedBuffer) : RefBase(), - mMixerThread(mixerThread), + mThread(thread), mClient(client), mFrameCount(0), mState(IDLE), @@ -1574,13 +1958,6 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( mFormat(format), mFlags(flags & ~SYSTEM_FLAGS_MASK) { - 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; - } - LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize); @@ -1634,16 +2011,19 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( } } -AudioFlinger::MixerThread::TrackBase::~TrackBase() +AudioFlinger::PlaybackThread::TrackBase::~TrackBase() { if (mCblk) { - mCblk->~audio_track_cblk_t(); // destroy our shared-structure. + mCblk->~audio_track_cblk_t(); // destroy our shared-structure. + if (mClient == NULL) { + delete mCblk; + } } mCblkMemory.clear(); // and free the shared memory mClient.clear(); } -void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) +void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) { buffer->raw = 0; mFrameCount = buffer->frameCount; @@ -1651,7 +2031,7 @@ void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Bu buffer->frameCount = 0; } -bool AudioFlinger::MixerThread::TrackBase::step() { +bool AudioFlinger::PlaybackThread::TrackBase::step() { bool result; audio_track_cblk_t* cblk = this->cblk(); @@ -1663,7 +2043,7 @@ bool AudioFlinger::MixerThread::TrackBase::step() { return result; } -void AudioFlinger::MixerThread::TrackBase::reset() { +void AudioFlinger::PlaybackThread::TrackBase::reset() { audio_track_cblk_t* cblk = this->cblk(); cblk->user = 0; @@ -1674,27 +2054,27 @@ void AudioFlinger::MixerThread::TrackBase::reset() { LOGV("TrackBase::reset"); } -sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const +sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const { return mCblkMemory; } -int AudioFlinger::MixerThread::TrackBase::sampleRate() const { +int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const { return (int)mCblk->sampleRate; } -int AudioFlinger::MixerThread::TrackBase::channelCount() const { +int AudioFlinger::PlaybackThread::TrackBase::channelCount() const { return (int)mCblk->channels; } -void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { +void* AudioFlinger::PlaybackThread::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; + int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize; + int8_t *bufferEnd = bufferStart + frames * cblk->frameSize; // Check validity of returned pointer in case the track control block would have been corrupted. - if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || - (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) { + if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd || + ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) { LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \ server %d, serverBase %d, user %d, userBase %d, channels %d", bufferStart, bufferEnd, mBuffer, mBufferEnd, @@ -1707,9 +2087,9 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t // ---------------------------------------------------------------------------- -// Track constructor must be called with AudioFlinger::mLock held -AudioFlinger::MixerThread::Track::Track( - const sp<MixerThread>& mixerThread, +// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held +AudioFlinger::PlaybackThread::Track::Track( + const wp<ThreadBase>& thread, const sp<Client>& client, int streamType, uint32_t sampleRate, @@ -1717,40 +2097,58 @@ AudioFlinger::MixerThread::Track::Track( int channelCount, int frameCount, const sp<IMemory>& sharedBuffer) - : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer) + : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer), + mMute(false), mSharedBuffer(sharedBuffer), mName(-1) { + sp<ThreadBase> baseThread = thread.promote(); + if (baseThread != 0) { + PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get(); + mName = playbackThread->getTrackName_l(); + } + LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); + if (mName < 0) { + LOGE("no more track names available"); + } mVolume[0] = 1.0f; mVolume[1] = 1.0f; - mMute = false; - mSharedBuffer = sharedBuffer; mStreamType = streamType; + // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of + // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack + mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t); } -AudioFlinger::MixerThread::Track::~Track() +AudioFlinger::PlaybackThread::Track::~Track() { - wp<Track> weak(this); // never create a strong ref from the dtor - Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); - mState = TERMINATED; + LOGV("PlaybackThread::Track destructor"); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + mState = TERMINATED; + } } -void AudioFlinger::MixerThread::Track::destroy() +void AudioFlinger::PlaybackThread::Track::destroy() { - // NOTE: destroyTrack_l() can remove a strong reference to this Track + // 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 + // desctructor is called. As the destructor needs to lock mLock, + // we must acquire a strong reference on this Track before locking 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 + // 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); + { // scope for mLock + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + playbackThread->destroyTrack_l(this); + } } } -void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size) +void AudioFlinger::PlaybackThread::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, @@ -1769,7 +2167,7 @@ void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size) mCblk->user); } -status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) { audio_track_cblk_t* cblk = this->cblk(); uint32_t framesReady; @@ -1806,76 +2204,90 @@ status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Bu getNextBuffer_exit: buffer->raw = 0; buffer->frameCount = 0; + LOGV("getNextBuffer() no more data"); return NOT_ENOUGH_DATA; } -bool AudioFlinger::MixerThread::Track::isReady() const { +bool AudioFlinger::PlaybackThread::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() +status_t AudioFlinger::PlaybackThread::Track::start() { - 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); + LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + playbackThread->addTrack_l(this); + } return NO_ERROR; } -void AudioFlinger::MixerThread::Track::stop() +void AudioFlinger::PlaybackThread::Track::stop() { - 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 (mMixerThread->mActiveTracks.indexOf(this) < 0) { - reset(); + LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + if (mState > STOPPED) { + mState = STOPPED; + // If the track is not active (PAUSED and buffers full), flush buffers + PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); + if (playbackThread->mActiveTracks.indexOf(this) < 0) { + reset(); + } + LOGV("(> STOPPED) => STOPPED (%d)", mName); } - LOGV("(> STOPPED) => STOPPED (%d)", mName); } } -void AudioFlinger::MixerThread::Track::pause() +void AudioFlinger::PlaybackThread::Track::pause() { 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); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + if (mState == ACTIVE || mState == RESUMING) { + mState = PAUSING; + LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName); + } } } -void AudioFlinger::MixerThread::Track::flush() +void AudioFlinger::PlaybackThread::Track::flush() { LOGV("flush(%d)", mName); - Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); - if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { - return; - } - // No point remaining in PAUSED state after a flush => go to - // STOPPED state - mState = STOPPED; + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + Mutex::Autolock _l(thread->mLock); + if (mState != STOPPED && mState != PAUSED && mState != PAUSING) { + return; + } + // No point remaining in PAUSED state after a flush => go to + // STOPPED state + mState = STOPPED; - mCblk->lock.lock(); - // 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(); - mCblk->lock.unlock(); + mCblk->lock.lock(); + // 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(); + mCblk->lock.unlock(); + } } -void AudioFlinger::MixerThread::Track::reset() +void AudioFlinger::PlaybackThread::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. @@ -1885,17 +2297,17 @@ void AudioFlinger::MixerThread::Track::reset() // written to buffer mCblk->flowControlFlag = 1; mCblk->forceReady = 0; - mFillingUpStatus = FS_FILLING; + mFillingUpStatus = FS_FILLING; mResetDone = true; } } -void AudioFlinger::MixerThread::Track::mute(bool muted) +void AudioFlinger::PlaybackThread::Track::mute(bool muted) { mMute = muted; } -void AudioFlinger::MixerThread::Track::setVolume(float left, float right) +void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right) { mVolume[0] = left; mVolume[1] = right; @@ -1904,28 +2316,33 @@ void AudioFlinger::MixerThread::Track::setVolume(float left, float right) // ---------------------------------------------------------------------------- // RecordTrack constructor must be called with AudioFlinger::mLock held -AudioFlinger::MixerThread::RecordTrack::RecordTrack( - const sp<MixerThread>& mixerThread, +AudioFlinger::RecordThread::RecordTrack::RecordTrack( + const wp<ThreadBase>& thread, const sp<Client>& client, - int inputSource, uint32_t sampleRate, int format, int channelCount, int frameCount, uint32_t flags) - : TrackBase(mixerThread, client, sampleRate, format, + : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, flags, 0), - mOverflow(false), mInputSource(inputSource) + mOverflow(false) { + LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer); + if (format == AudioSystem::PCM_16_BIT) { + mCblk->frameSize = channelCount * sizeof(int16_t); + } else if (format == AudioSystem::PCM_8_BIT) { + mCblk->frameSize = channelCount * sizeof(int8_t); + } else { + mCblk->frameSize = sizeof(int8_t); + } } -AudioFlinger::MixerThread::RecordTrack::~RecordTrack() +AudioFlinger::RecordThread::RecordTrack::~RecordTrack() { - Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock); - mMixerThread->deleteTrackName_l(mName); } -status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) { audio_track_cblk_t* cblk = this->cblk(); uint32_t framesAvail; @@ -1964,180 +2381,231 @@ getNextBuffer_exit: return NOT_ENOUGH_DATA; } -status_t AudioFlinger::MixerThread::RecordTrack::start() +status_t AudioFlinger::RecordThread::RecordTrack::start() { - return mMixerThread->mAudioFlinger->startRecord(this); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + RecordThread *recordThread = (RecordThread *)thread.get(); + return recordThread->start(this); + } + return NO_INIT; } -void AudioFlinger::MixerThread::RecordTrack::stop() +void AudioFlinger::RecordThread::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; + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + RecordThread *recordThread = (RecordThread *)thread.get(); + recordThread->stop(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, +AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( + const wp<ThreadBase>& thread, uint32_t sampleRate, int format, int channelCount, int frameCount) - : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL), - mOutputMixerThread(mixerThread) + : Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL), + mActive(false) { - + + PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get(); 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); - + mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate(); + + LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d", + mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs); + } -AudioFlinger::MixerThread::OutputTrack::~OutputTrack() +AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() { stop(); } -status_t AudioFlinger::MixerThread::OutputTrack::start() +status_t AudioFlinger::PlaybackThread::OutputTrack::start() { status_t status = Track::start(); - + if (status != NO_ERROR) { + return status; + } + + mActive = true; mRetryCount = 127; return status; } -void AudioFlinger::MixerThread::OutputTrack::stop() +void AudioFlinger::PlaybackThread::OutputTrack::stop() { Track::stop(); clearBufferQueue(); mOutBuffer.frameCount = 0; + mActive = false; } -void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames) +bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; uint32_t channels = mCblk->channels; - + bool outputBufferFull = false; inBuffer.frameCount = frames; inBuffer.i16 = data; - - if (mCblk->user == 0) { - mOutputMixerThread->mAudioFlinger->mLock.lock(); - bool isMusicActive = mOutputMixerThread->isMusicActive_l(); - mOutputMixerThread->mAudioFlinger->mLock.unlock(); - if (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"); + + uint32_t waitTimeLeftMs = mWaitTimeMs; + + if (!mActive) { + start(); + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + MixerThread *mixerThread = (MixerThread *)thread.get(); + if (mCblk->frameCount > frames){ + if (mBufferQueue.size() < kMaxOverFlowBuffers) { + uint32_t startFrames = (mCblk->frameCount - frames); + 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() %p no more buffers in queue", this); + } } - } + } } - while (1) { + while (waitTimeLeftMs) { // 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) { + nsecs_t startTime = systemTime(); + if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) { + LOGV ("OutputTrack::write() %p no more output buffers", this); + outputBufferFull = true; break; } + uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime); +// LOGV("OutputTrack::write() waitTimeMs %d waitTimeLeftMs %d", waitTimeMs, waitTimeLeftMs) + if (waitTimeLeftMs >= waitTimeMs) { + waitTimeLeftMs -= waitTimeMs; + } else { + waitTimeLeftMs = 0; + } } - + 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; - + mOutBuffer.i16 += outFrames * channels; + if (pInBuffer->frameCount == 0) { if (mBufferQueue.size()) { mBufferQueue.removeAt(0); delete [] pInBuffer->mBuffer; delete pInBuffer; + LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size()); } 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) { + if (mBufferQueue.size() < kMaxOverFlowBuffers) { 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); + LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size()); } else { - LOGW("OutputTrack::write() no more buffers"); + LOGW("OutputTrack::write() %p no more overflow buffers", this); } } - + // 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 + // 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); + if (frames == 0 && mBufferQueue.size() == 0) { + if (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); + } else { + stop(); + } } + return outputBufferFull; } -status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs) { 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); +// 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; + Mutex::Autolock _l(cblk->lock); + goto start_loop_here; + while (framesAvail == 0) { + active = mActive; + if (UNLIKELY(!active)) { + LOGV("Not active and NO_MORE_BUFFERS"); + return AudioTrack::NO_MORE_BUFFERS; + } + result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + if (result != NO_ERROR) { + return AudioTrack::NO_MORE_BUFFERS; + } + // read the server count again + start_loop_here: + framesAvail = cblk->framesAvailable_l(); + } } +// if (framesAvail < framesReq) { +// return AudioTrack::NO_MORE_BUFFERS; +// } + if (framesReq > framesAvail) { framesReq = framesAvail; } @@ -2155,11 +2623,11 @@ status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvide } -void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue() +void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() { size_t size = mBufferQueue.size(); Buffer *pBuffer; - + for (size_t i = 0; i < size; i++) { pBuffer = mBufferQueue.itemAt(i); delete [] pBuffer->mBuffer; @@ -2191,7 +2659,7 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const // ---------------------------------------------------------------------------- -AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track) +AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track) : BnAudioTrack(), mTrack(track) { @@ -2243,7 +2711,7 @@ status_t AudioFlinger::TrackHandle::onTransact( sp<IAudioRecord> AudioFlinger::openRecord( pid_t pid, - int inputSource, + void *input, uint32_t sampleRate, int format, int channelCount, @@ -2251,14 +2719,13 @@ sp<IAudioRecord> AudioFlinger::openRecord( uint32_t flags, status_t *status) { - sp<MixerThread::RecordTrack> recordTrack; + sp<RecordThread::RecordTrack> recordTrack; sp<RecordHandle> recordHandle; sp<Client> client; wp<Client> wclient; - AudioStreamIn* input = 0; - int inFrameCount; - size_t inputBufferSize; status_t lStatus; + RecordThread *thread; + size_t inFrameCount; // check calling permissions if (!recordingAllowed()) { @@ -2266,30 +2733,15 @@ sp<IAudioRecord> AudioFlinger::openRecord( goto Exit; } - if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) { - LOGE("invalid stream type"); - 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 { // scope for mLock Mutex::Autolock _l(mLock); + thread = checkRecordThread_l(input); + if (thread == NULL) { + lStatus = BAD_VALUE; + goto Exit; + } + wclient = mClients.valueFor(pid); if (wclient != NULL) { client = wclient.promote(); @@ -2298,12 +2750,8 @@ sp<IAudioRecord> AudioFlinger::openRecord( 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. The record track uses one track in mHardwareMixerThread by convention. - recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate, + recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate, format, channelCount, frameCount, flags); } if (recordTrack->getCblk() == NULL) { @@ -2323,22 +2771,9 @@ Exit: 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) +AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack) : BnAudioRecord(), mRecordTrack(recordTrack) { @@ -2370,86 +2805,165 @@ status_t AudioFlinger::RecordHandle::onTransact( // ---------------------------------------------------------------------------- -AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware, - const sp<AudioFlinger>& audioFlinger) : - mAudioHardware(audioHardware), - mAudioFlinger(audioFlinger), - mActive(false) +AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels) : + ThreadBase(audioFlinger), + mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0) { + mReqChannelCount = AudioSystem::popCount(channels); + mReqSampleRate = sampleRate; + readInputParameters(); + sendConfigEvent(AudioSystem::INPUT_OPENED); } -AudioFlinger::AudioRecordThread::~AudioRecordThread() + +AudioFlinger::RecordThread::~RecordThread() { + mAudioFlinger->mAudioHardware->closeInputStream(mInput); + delete[] mRsmpInBuffer; + if (mResampler != 0) { + delete mResampler; + delete[] mRsmpOutBuffer; + } } -bool AudioFlinger::AudioRecordThread::threadLoop() +void AudioFlinger::RecordThread::onFirstRef() +{ + const size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, "Record Thread %p", this); + + run(buffer, PRIORITY_URGENT_AUDIO); +} +bool AudioFlinger::RecordThread::threadLoop() { - LOGV("AudioRecordThread: start record loop"); AudioBufferProvider::Buffer buffer; - int inBufferSize = 0; - int inFrameCount = 0; - AudioStreamIn* input = 0; + sp<RecordTrack> activeTrack; - mActive = 0; - // start recording while (!exitPending()) { - if (!mActive) { - mLock.lock(); - if (!mActive && !exitPending()) { - LOGV("AudioRecordThread: loop stopping"); - if (input) { - delete input; - input = 0; + + processConfigEvents(); + + { // scope for mLock + Mutex::Autolock _l(mLock); + checkForNewParameters_l(); + if (mActiveTrack == 0 && mConfigEvents.isEmpty()) { + if (!mStandby) { + mInput->standby(); + mStandby = true; } - mRecordTrack.clear(); - mStopped.signal(); + if (exitPending()) break; + + LOGV("RecordThread: loop stopping"); + // go to sleep mWaitWorkCV.wait(mLock); - - LOGV("AudioRecordThread: loop starting"); - if (mRecordTrack != 0) { - input = mAudioHardware->openInputStream( - mRecordTrack->inputSource(), - mRecordTrack->format(), - mRecordTrack->channelCount(), - mRecordTrack->sampleRate(), - &mStartStatus, - (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16)); - if (input != 0) { - inBufferSize = input->bufferSize(); - inFrameCount = inBufferSize/input->frameSize(); + LOGV("RecordThread: loop starting"); + continue; + } + if (mActiveTrack != 0) { + if (mActiveTrack->mState == TrackBase::PAUSING) { + mActiveTrack.clear(); + mStartStopCond.broadcast(); + } else if (mActiveTrack->mState == TrackBase::RESUMING) { + mRsmpInIndex = mFrameCount; + if (mReqChannelCount != mActiveTrack->channelCount()) { + mActiveTrack.clear(); + } else { + mActiveTrack->mState == TrackBase::ACTIVE; } - } else { - mStartStatus = NO_INIT; + mStartStopCond.broadcast(); } - if (mStartStatus !=NO_ERROR) { - LOGW("record start failed, status %d", mStartStatus); - mActive = false; - mRecordTrack.clear(); - } - mWaitWorkCV.signal(); + mStandby = false; } - mLock.unlock(); - } else if (mRecordTrack != 0) { - - buffer.frameCount = inFrameCount; - if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR && - (int)buffer.frameCount == inFrameCount)) { - 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); + } + + if (mActiveTrack != 0) { + buffer.frameCount = mFrameCount; + if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) { + size_t framesOut = buffer.frameCount; + if (mResampler == 0) { + // no resampling + while (framesOut) { + size_t framesIn = mFrameCount - mRsmpInIndex; + if (framesIn) { + int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize; + int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize; + if (framesIn > framesOut) + framesIn = framesOut; + mRsmpInIndex += framesIn; + framesOut -= framesIn; + if (mChannelCount == mReqChannelCount || + mFormat != AudioSystem::PCM_16_BIT) { + memcpy(dst, src, framesIn * mFrameSize); + } else { + int16_t *src16 = (int16_t *)src; + int16_t *dst16 = (int16_t *)dst; + if (mChannelCount == 1) { + while (framesIn--) { + *dst16++ = *src16; + *dst16++ = *src16++; + } + } else { + while (framesIn--) { + *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1); + src16 += 2; + } + } + } + } + if (framesOut && mFrameCount == mRsmpInIndex) { + ssize_t bytesRead; + if (framesOut == mFrameCount && + (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) { + bytesRead = mInput->read(buffer.raw, mInputBytes); + framesOut = 0; + } else { + bytesRead = mInput->read(mRsmpInBuffer, mInputBytes); + mRsmpInIndex = 0; + } + if (bytesRead < 0) { + LOGE("Error reading audio input"); + sleep(1); + mRsmpInIndex = mFrameCount; + framesOut = 0; + buffer.frameCount = 0; + } + } + } + } else { + // resampling + + memset(mRsmpOutBuffer, 0, framesOut * 2 * sizeof(int32_t)); + // alter output frame count as if we were expecting stereo samples + if (mChannelCount == 1 && mReqChannelCount == 1) { + framesOut >>= 1; + } + mResampler->resample(mRsmpOutBuffer, framesOut, this); + // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer() + // are 32 bit aligned which should be always true. + if (mChannelCount == 2 && mReqChannelCount == 1) { + AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut); + // the resampler always outputs stereo samples: do post stereo to mono conversion + int16_t *src = (int16_t *)mRsmpOutBuffer; + int16_t *dst = buffer.i16; + while (framesOut--) { + *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1); + src += 2; + } + } else { + AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut); + } + } - mRecordTrack->releaseBuffer(&buffer); - mRecordTrack->overflow(); + mActiveTrack->releaseBuffer(&buffer); + mActiveTrack->overflow(); } - // client isn't retrieving buffers fast enough else { - if (!mRecordTrack->setOverflow()) - LOGW("AudioRecordThread: buffer overflow"); + if (!mActiveTrack->setOverflow()) + LOGW("RecordThread: 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. @@ -2458,65 +2972,64 @@ bool AudioFlinger::AudioRecordThread::threadLoop() } } - - if (input) { - delete input; + if (!mStandby) { + mInput->standby(); } - mRecordTrack.clear(); - + mActiveTrack.clear(); + + sendConfigEvent(AudioSystem::INPUT_CLOSED); + processConfigEvents(); + + LOGV("RecordThread %p exiting", this); return false; } -status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack) +status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack) { - LOGV("AudioRecordThread::start"); + LOGV("RecordThread::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; + if (mActiveTrack != 0) { + if (recordTrack != mActiveTrack.get()) return -EBUSY; - mRecordTrack = recordTrack; + if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING; + return NO_ERROR; + } + + mActiveTrack = recordTrack; + mActiveTrack->mState = TrackBase::RESUMING; // 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); + mStartStopCond.wait(mLock); + if (mActiveTrack != 0) { + LOGV("Record started OK"); + return NO_ERROR; + } else { + LOGV("Record failed to start"); + return BAD_VALUE; } } -void AudioFlinger::AudioRecordThread::exit() -{ - LOGV("AudioRecordThread::exit"); - { - AutoMutex lock(&mLock); - requestExit(); - mWaitWorkCV.signal(); +void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) { + LOGV("RecordThread::stop"); + AutoMutex lock(&mLock); + if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) { + mActiveTrack->mState = TrackBase::PAUSING; + mStartStopCond.wait(mLock); } - requestExitAndWait(); } -status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args) +status_t AudioFlinger::RecordThread::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()); + if (mActiveTrack != 0 && mActiveTrack->mClient != 0) { + snprintf(buffer, SIZE, "Record client pid: %d\n", mActiveTrack->mClient->pid()); result.append(buffer); } else { result.append("No record client\n"); @@ -2525,6 +3038,463 @@ status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& a return NO_ERROR; } +status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer) +{ + size_t framesReq = buffer->frameCount; + size_t framesReady = mFrameCount - mRsmpInIndex; + int channelCount; + + if (framesReady == 0) { + ssize_t bytesRead = mInput->read(mRsmpInBuffer, mInputBytes); + if (bytesRead < 0) { + LOGE("RecordThread::getNextBuffer() Error reading audio input"); + sleep(1); + buffer->raw = 0; + buffer->frameCount = 0; + return NOT_ENOUGH_DATA; + } + mRsmpInIndex = 0; + framesReady = mFrameCount; + } + + if (framesReq > framesReady) { + framesReq = framesReady; + } + + if (mChannelCount == 1 && mReqChannelCount == 2) { + channelCount = 1; + } else { + channelCount = 2; + } + buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount; + buffer->frameCount = framesReq; + return NO_ERROR; +} + +void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer) +{ + mRsmpInIndex += buffer->frameCount; + buffer->frameCount = 0; +} + +bool AudioFlinger::RecordThread::checkForNewParameters_l() +{ + bool reconfig = false; + + if (mNewParameters != "") { + status_t status = NO_ERROR; + AudioParameter param = AudioParameter(mNewParameters); + int value; + int reqFormat = mFormat; + int reqSamplingRate = mReqSampleRate; + int reqChannelCount = mReqChannelCount; + if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) { + reqSamplingRate = value; + reconfig = true; + } + if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) { + reqFormat = value; + reconfig = true; + } + if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) { + reqChannelCount = AudioSystem::popCount(value); + reconfig = true; + } + if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { + // do not accept frame count changes if tracks are open as the track buffer + // size depends on frame count and correct behavior would not be garantied + // if frame count is changed after track creation + if (mActiveTrack != 0) { + status = INVALID_OPERATION; + } else { + reconfig = true; + } + } + if (status == NO_ERROR) { + status = mInput->setParameters(mNewParameters); + if (status == INVALID_OPERATION) { + mInput->standby(); + status = mInput->setParameters(mNewParameters); + } + if (reconfig) { + if (status == BAD_VALUE && + reqFormat == mInput->format() && reqFormat == AudioSystem::PCM_16_BIT && + ((int)mInput->sampleRate() <= 2 * reqSamplingRate) && + (AudioSystem::popCount(mInput->channels()) < 3) && (reqChannelCount < 3)) { + status = NO_ERROR; + } + if (status == NO_ERROR) { + readInputParameters(); + sendConfigEvent(AudioSystem::INPUT_CONFIG_CHANGED); + } + } + } + mNewParameters = ""; + mParamStatus = status; + mParamCond.signal(); + } + return reconfig; +} + +String8 AudioFlinger::RecordThread::getParameters(const String8& keys) +{ + return mInput->getParameters(keys); +} + +void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) { + AudioSystem::OutputDescriptor desc; + void *param2 = 0; + + switch (event) { + case AudioSystem::INPUT_OPENED: + case AudioSystem::INPUT_CONFIG_CHANGED: + desc.channels = mChannelCount; + desc.samplingRate = mSampleRate; + desc.format = mFormat; + desc.frameCount = mFrameCount; + desc.latency = 0; + param2 = &desc; + break; + + case AudioSystem::INPUT_CLOSED: + default: + break; + } + mAudioFlinger->audioConfigChanged(event, this, param2); +} + +void AudioFlinger::RecordThread::readInputParameters() +{ + if (mRsmpInBuffer) delete mRsmpInBuffer; + if (mRsmpOutBuffer) delete mRsmpOutBuffer; + if (mResampler) delete mResampler; + mResampler = 0; + + mSampleRate = mInput->sampleRate(); + mChannelCount = AudioSystem::popCount(mInput->channels()); + mFormat = mInput->format(); + mFrameSize = mInput->frameSize(); + mInputBytes = mInput->bufferSize(); + mFrameCount = mInputBytes / mFrameSize; + mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount]; + + if (mSampleRate != mReqSampleRate && mChannelCount < 3 && mReqChannelCount < 3) + { + int channelCount; + // optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid + // stereo to mono post process as the resampler always outputs stereo. + if (mChannelCount == 1 && mReqChannelCount == 2) { + channelCount = 1; + } else { + channelCount = 2; + } + mResampler = AudioResampler::create(16, channelCount, mReqSampleRate); + mResampler->setSampleRate(mSampleRate); + mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN); + mRsmpOutBuffer = new int32_t[mFrameCount * 2]; + + // optmization: if mono to mono, alter input frame count as if we were inputing stereo samples + if (mChannelCount == 1 && mReqChannelCount == 1) { + mFrameCount >>= 1; + } + + } + mRsmpInIndex = mFrameCount; +} + +// ---------------------------------------------------------------------------- + +void *AudioFlinger::openOutput(uint32_t *pDevices, + uint32_t *pSamplingRate, + uint32_t *pFormat, + uint32_t *pChannels, + uint32_t *pLatencyMs, + uint32_t flags) +{ + status_t status; + PlaybackThread *thread = NULL; + mHardwareStatus = AUDIO_HW_OUTPUT_OPEN; + uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; + uint32_t format = pFormat ? *pFormat : 0; + uint32_t channels = pChannels ? *pChannels : 0; + uint32_t latency = pLatencyMs ? *pLatencyMs : 0; + + LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x", + pDevices ? *pDevices : 0, + samplingRate, + format, + channels, + flags); + + if (pDevices == NULL || *pDevices == 0) { + return NULL; + } + Mutex::Autolock _l(mLock); + + AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices, + (int *)&format, + &channels, + &samplingRate, + &status); + LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d", + output, + samplingRate, + format, + channels, + status); + + mHardwareStatus = AUDIO_HW_IDLE; + if (output != 0) { + if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || + (format != AudioSystem::PCM_16_BIT) || + (channels != AudioSystem::CHANNEL_OUT_STEREO)) { + thread = new DirectOutputThread(this, output); + LOGV("openOutput() created direct output %p", thread); + } else { + thread = new MixerThread(this, output); + LOGV("openOutput() created mixer output %p", thread); + } + mPlaybackThreads.add(thread); + + if (pSamplingRate) *pSamplingRate = samplingRate; + if (pFormat) *pFormat = format; + if (pChannels) *pChannels = channels; + if (pLatencyMs) *pLatencyMs = thread->latency(); + } + + return thread; +} + +void *AudioFlinger::openDuplicateOutput(void *output1, void *output2) +{ + Mutex::Autolock _l(mLock); + + if (checkMixerThread_l(output1) == NULL || + checkMixerThread_l(output2) == NULL) { + LOGW("openDuplicateOutput() wrong output mixer type %p or %p", output1, output2); + return NULL; + } + + DuplicatingThread *thread = new DuplicatingThread(this, (MixerThread *)output1); + thread->addOutputTrack( (MixerThread *)output2); + mPlaybackThreads.add(thread); + return thread; +} + +status_t AudioFlinger::closeOutput(void *output) +{ + PlaybackThread *thread; + { + Mutex::Autolock _l(mLock); + thread = checkPlaybackThread_l(output); + if (thread == NULL) { + return BAD_VALUE; + } + + LOGV("closeOutput() %p", thread); + + if (thread->type() == PlaybackThread::MIXER) { + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads[i]->type() == PlaybackThread::DUPLICATING) { + DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads[i].get(); + dupThread->removeOutputTrack((MixerThread *)thread); + } + } + } + mPlaybackThreads.remove(thread); + } + thread->exit(); + + return NO_ERROR; +} + +status_t AudioFlinger::suspendOutput(void *output) +{ + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + + if (thread == NULL) { + return BAD_VALUE; + } + + LOGV("suspendOutput() %p", output); + thread->suspend(); + + return NO_ERROR; +} + +status_t AudioFlinger::restoreOutput(void *output) +{ + Mutex::Autolock _l(mLock); + PlaybackThread *thread = checkPlaybackThread_l(output); + + if (thread == NULL) { + return BAD_VALUE; + } + + LOGV("restoreOutput() %p", output); + + thread->restore(); + + return NO_ERROR; +} + +void *AudioFlinger::openInput(uint32_t *pDevices, + uint32_t *pSamplingRate, + uint32_t *pFormat, + uint32_t *pChannels, + uint32_t acoustics) +{ + status_t status; + RecordThread *thread = NULL; + uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; + uint32_t format = pFormat ? *pFormat : 0; + uint32_t channels = pChannels ? *pChannels : 0; + uint32_t reqSamplingRate = samplingRate; + uint32_t reqFormat = format; + uint32_t reqChannels = channels; + + if (pDevices == NULL || *pDevices == 0) { + return NULL; + } + Mutex::Autolock _l(mLock); + + AudioStreamIn *input = mAudioHardware->openInputStream(*pDevices, + (int *)&format, + &channels, + &samplingRate, + &status, + (AudioSystem::audio_in_acoustics)acoustics); + LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d", + input, + samplingRate, + format, + channels, + acoustics, + status); + + // If the input could not be opened with the requested parameters and we can handle the conversion internally, + // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo + // or stereo to mono conversions on 16 bit PCM inputs. + if (input == 0 && status == BAD_VALUE && + reqFormat == format && format == AudioSystem::PCM_16_BIT && + (samplingRate <= 2 * reqSamplingRate) && + (AudioSystem::popCount(channels) < 3) && (AudioSystem::popCount(reqChannels) < 3)) { + LOGV("openInput() reopening with proposed sampling rate and channels"); + input = mAudioHardware->openInputStream(*pDevices, + (int *)&format, + &channels, + &samplingRate, + &status, + (AudioSystem::audio_in_acoustics)acoustics); + } + + if (input != 0) { + // Start record thread + thread = new RecordThread(this, input, reqSamplingRate, reqChannels); + mRecordThreads.add(thread); + + if (pSamplingRate) *pSamplingRate = reqSamplingRate; + if (pFormat) *pFormat = format; + if (pChannels) *pChannels = reqChannels; + + input->standby(); + } + + return thread; +} + +status_t AudioFlinger::closeInput(void *input) +{ + RecordThread *thread; + { + Mutex::Autolock _l(mLock); + thread = checkRecordThread_l(input); + if (thread == NULL) { + return BAD_VALUE; + } + + LOGV("closeInput() %p", thread); + mRecordThreads.remove(thread); + } + thread->exit(); + + return NO_ERROR; +} + +status_t AudioFlinger::setStreamOutput(uint32_t stream, void *output) +{ + Mutex::Autolock _l(mLock); + MixerThread *dstThread = checkMixerThread_l(output); + if (dstThread == NULL) { + LOGW("setStreamOutput() bad output thread %p", output); + return BAD_VALUE; + } + + LOGV("setStreamOutput() stream %d to output %p", stream, dstThread); + + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + PlaybackThread *thread = mPlaybackThreads[i].get(); + if (thread != dstThread && + thread->type() != PlaybackThread::DIRECT) { + MixerThread *srcThread = (MixerThread *)thread; + SortedVector < sp<MixerThread::Track> > tracks; + SortedVector < wp<MixerThread::Track> > activeTracks; + srcThread->getTracks(tracks, activeTracks, stream); + if (tracks.size()) { + dstThread->putTracks(tracks, activeTracks); + dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream); + } + } + } + + return NO_ERROR; +} + +// checkPlaybackThread_l() must be called with AudioFlinger::mLock held +AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(void *output) const +{ + PlaybackThread *thread = NULL; + + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads[i] == output) { + thread = (PlaybackThread *)output; + break; + } + } + + return thread; +} + +// checkMixerThread_l() must be called with AudioFlinger::mLock held +AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(void *output) const +{ + PlaybackThread *thread = checkPlaybackThread_l(output); + if (thread != NULL) { + if (thread->type() == PlaybackThread::DIRECT) { + thread = NULL; + } + } + return (MixerThread *)thread; +} + +// checkRecordThread_l() must be called with AudioFlinger::mLock held +AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(void *input) const +{ + RecordThread *thread = NULL; + + for (size_t i = 0; i < mRecordThreads.size(); i++) { + if (mRecordThreads[i] == input) { + thread = (RecordThread *)input; + break; + } + } + + return thread; +} + +// ---------------------------------------------------------------------------- + status_t AudioFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -2532,6 +3502,7 @@ status_t AudioFlinger::onTransact( } // ---------------------------------------------------------------------------- + void AudioFlinger::instantiate() { defaultServiceManager()->addService( String16("media.audio_flinger"), new AudioFlinger()); |