diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
commit | d24b8183b93e781080b2c16c487e60d51c12da31 (patch) | |
tree | fbb89154858984eb8e41556da7e9433040d55cd4 /libs/audioflinger | |
parent | f1e484acb594a726fb57ad0ae4cfe902c7f35858 (diff) | |
download | frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.zip frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.gz frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'libs/audioflinger')
-rw-r--r-- | libs/audioflinger/A2dpAudioInterface.cpp | 27 | ||||
-rw-r--r-- | libs/audioflinger/A2dpAudioInterface.h | 3 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 154 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.h | 20 |
4 files changed, 176 insertions, 28 deletions
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp index c8c8431..3c18036 100644 --- a/libs/audioflinger/A2dpAudioInterface.cpp +++ b/libs/audioflinger/A2dpAudioInterface.cpp @@ -99,6 +99,10 @@ status_t A2dpAudioInterface::setParameter(const char *key, const char *value) if (strcmp(key, "a2dp_sink_address") == 0) { return mOutput->setAddress(value); } + if (strcmp(key, "bluetooth_enabled") == 0 && + strcmp(value, "false") == 0) { + return mOutput->close(); + } return 0; } @@ -154,8 +158,7 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::set( A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut() { - if (mData) - a2dp_cleanup(mData); + close(); } ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes) @@ -186,7 +189,8 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t return bytes; -Error: +Error: + close(); // Simulate audio output timing in case of error usleep(bytes * 1000000 / frameSize() / sampleRate()); @@ -213,17 +217,22 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address) if (strcmp(address, mA2dpAddress)) { strcpy(mA2dpAddress, address); - - if (mInitialized) { - a2dp_cleanup(mData); - mData = NULL; - mInitialized = false; - } + close(); } return NO_ERROR; } +status_t A2dpAudioInterface::A2dpAudioStreamOut::close() +{ + if (mData) { + a2dp_cleanup(mData); + mData = NULL; + mInitialized = false; + } + return NO_ERROR; +} + status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args) { return NO_ERROR; diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h index 2197d0e..38ba684 100644 --- a/libs/audioflinger/A2dpAudioInterface.h +++ b/libs/audioflinger/A2dpAudioInterface.h @@ -77,10 +77,11 @@ private: virtual size_t bufferSize() const { return 512 * 20; } virtual int channelCount() const { return 2; } virtual int format() const { return AudioSystem::PCM_16_BIT; } - virtual uint32_t latency() const { return ((1000*channelCount()*bufferSize())/frameSize())/sampleRate() + 200; } + virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; } virtual status_t setVolume(float volume) { return INVALID_OPERATION; } virtual ssize_t write(const void* buffer, size_t bytes); status_t standby(); + status_t close(); virtual status_t dump(int fd, const Vector<String16>& args); private: diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index c330bc8..017a298 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -183,6 +183,7 @@ AudioFlinger::~AudioFlinger() void AudioFlinger::setOutput(AudioStreamOut* output) { mRequestedOutput = output; + mWaitWorkCV.broadcast(); } void AudioFlinger::doSetOutput(AudioStreamOut* output) @@ -198,6 +199,7 @@ void AudioFlinger::doSetOutput(AudioStreamOut* output) mFrameCount = getOutputFrameCount(output); mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer); mOutput = output; + notifyOutputChange_l(); } size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) @@ -211,6 +213,8 @@ bool AudioFlinger::streamDisablesA2dp(int streamType) return (streamType == AudioTrack::SYSTEM || streamType == AudioTrack::RING || streamType == AudioTrack::ALARM || + streamType == AudioTrack::VOICE_CALL || + streamType == AudioTrack::BLUETOOTH_SCO || streamType == AudioTrack::NOTIFICATION); } @@ -344,7 +348,8 @@ bool AudioFlinger::threadLoop() int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; size_t enabledTracks = 0; - nsecs_t standbyTime = systemTime(); + nsecs_t standbyTime = systemTime(); + nsecs_t outputSwitchStandbyTime = 0; do { enabledTracks = 0; @@ -362,6 +367,11 @@ bool AudioFlinger::threadLoop() mOutput->standby(); mStandby = true; } + if (outputSwitchStandbyTime) { + AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput; + output->standby(); + outputSwitchStandbyTime = 0; + } mHardwareStatus = AUDIO_HW_IDLE; // we're about to wait, flush the binder command buffer IPCThreadState::self()->flushCommands(); @@ -375,11 +385,18 @@ bool AudioFlinger::threadLoop() if (mRequestedOutput != mOutput) { // put current output into standby mode - if (mOutput) mOutput->standby(); + if (mOutput) { + outputSwitchStandbyTime = systemTime() + milliseconds(mOutput->latency()); + } // change output doSetOutput(mRequestedOutput); } + if (outputSwitchStandbyTime && systemTime() > outputSwitchStandbyTime) { + AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput; + output->standby(); + outputSwitchStandbyTime = 0; + } // find out which tracks need to be processed size_t count = activeTracks.size(); @@ -481,7 +498,7 @@ bool AudioFlinger::threadLoop() removeActiveTrack(track); if (track->isTerminated()) { mTracks.remove(track); - mAudioMixer->deleteTrackName(track->mName); + deleteTrackName(track->mName); } } } @@ -512,7 +529,7 @@ bool AudioFlinger::threadLoop() // active tracks were late. Sleep a little bit to give // them another chance. If we're too late, the audio // hardware will zero-fill for us. - LOGV("no buffers - usleep(%lu)", sleepTime); +// LOGV("no buffers - usleep(%lu)", sleepTime); usleep(sleepTime); if (sleepTime < kMaxBufferRecoveryInUsecs) { sleepTime += kBufferRecoveryInUsecs; @@ -802,12 +819,14 @@ status_t AudioFlinger::setStreamVolume(int stream, float value) mStreamTypes[stream].volume = value; status_t ret = NO_ERROR; - if (stream == AudioTrack::VOICE_CALL) { + if (stream == AudioTrack::VOICE_CALL || + stream == AudioTrack::BLUETOOTH_SCO) { AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_VOICE_VOLUME; ret = mAudioHardware->setVoiceVolume(value); mHardwareStatus = AUDIO_HW_IDLE; } + return ret; } @@ -821,7 +840,20 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted) if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { return BAD_VALUE; } +#ifdef WITH_A2DP + if (stream == AudioTrack::MUSIC) + { + AutoMutex lock(&mLock); + if (mA2dpDisableCount > 0) + mMusicMuteSaved = muted; + else + mStreamTypes[stream].mute = muted; + } else { + mStreamTypes[stream].mute = muted; + } +#else mStreamTypes[stream].mute = muted; +#endif return NO_ERROR; } @@ -838,6 +870,12 @@ bool AudioFlinger::streamMute(int stream) const if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) { return true; } +#ifdef WITH_A2DP + if (stream == AudioTrack::MUSIC && mA2dpDisableCount > 0) + { + return mMusicMuteSaved; + } +#endif return mStreamTypes[stream].mute; } @@ -869,6 +907,59 @@ status_t AudioFlinger::setParameter(const char* key, const char* value) return result; } + +void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) +{ + Mutex::Autolock _l(mLock); + + sp<IBinder> binder = client->asBinder(); + if (mNotificationClients.indexOf(binder) < 0) { + LOGV("Adding notification client %p", binder.get()); + binder->linkToDeath(this); + mNotificationClients.add(binder); + } +} + + +size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) +{ + return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount); +} + +void AudioFlinger::wakeUp() +{ + mWaitWorkCV.broadcast(); +} + +void AudioFlinger::binderDied(const wp<IBinder>& who) { + Mutex::Autolock _l(mLock); + + IBinder *binder = who.unsafe_get(); + + if (binder != NULL) { + int index = mNotificationClients.indexOf(binder); + if (index >= 0) { + LOGV("Removing notification client %p", binder); + mNotificationClients.removeAt(index); + } + } +} + +// must be called with mLock held +void AudioFlinger::notifyOutputChange_l() +{ + size_t size = mNotificationClients.size(); + uint32_t latency = mOutput->latency(); + 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->audioOutputChanged(mFrameCount, mSampleRate, latency); + } + } +} + void AudioFlinger::removeClient(pid_t pid) { Mutex::Autolock _l(mLock); @@ -920,7 +1011,7 @@ void AudioFlinger::remove_track_l(wp<Track> track, int name) if (t!=NULL) { t->reset(); } - audioMixer()->deleteTrackName(name); + deleteTrackName(name); removeActiveTrack(track); mWaitWorkCV.broadcast(); } @@ -938,7 +1029,7 @@ void AudioFlinger::destroyTrack(const sp<Track>& track) if (mActiveTracks.indexOf(track) < 0) { LOGV("remove track (%d) and delete from mixer", track->name()); mTracks.remove(track); - audioMixer()->deleteTrackName(keep->name()); + deleteTrackName(keep->name()); } } @@ -953,9 +1044,11 @@ void AudioFlinger::addActiveTrack(const wp<Track>& t) if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) { setA2dpEnabled(false); mA2dpSuppressed = true; - LOGD("mA2dpSuppressed = true\n"); + mMusicMuteSaved = mStreamTypes[AudioTrack::MUSIC].mute; + mStreamTypes[AudioTrack::MUSIC].mute = true; + LOGV("mA2dpSuppressed = true, track %d\n", track->name()); } - LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount); + LOGV("mA2dpDisableCount incremented to %d, track %d\n", mA2dpDisableCount, track->name()); } #endif } @@ -969,17 +1062,45 @@ void AudioFlinger::removeActiveTrack(const wp<Track>& t) if (streamDisablesA2dp(track->type())) { if (mA2dpDisableCount > 0) { mA2dpDisableCount--; + LOGV("mA2dpDisableCount decremented to %d, track %d\n", mA2dpDisableCount, track->name()); if (mA2dpDisableCount == 0 && mA2dpSuppressed) { setA2dpEnabled(true); mA2dpSuppressed = false; - } - LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount); + mStreamTypes[AudioTrack::MUSIC].mute = mMusicMuteSaved; + LOGV("mA2dpSuppressed = false, track %d\n", track->name()); + } } else LOGE("mA2dpDisableCount is already zero"); } #endif } +int AudioFlinger::getTrackName() +{ + // Both mixers must have the same set of track used to avoid mismatches when + // switching from A2DP output to hardware output + int a2DpName; + int hwName; +#ifdef WITH_A2DP + a2DpName = mA2dpAudioMixer->getTrackName(); +#endif + hwName = mHardwareAudioMixer->getTrackName(); + + LOGW_IF((a2DpName != hwName), "getTrackName track name mismatch! A2DP %d, HW %d", a2DpName, hwName); + + return hwName; +} + +void AudioFlinger::deleteTrackName(int name) +{ + // Both mixers must have the same set of track used to avoid mismatches when + // switching from A2DP output to hardware output + mHardwareAudioMixer->deleteTrackName(name); +#ifdef WITH_A2DP + mA2dpAudioMixer->deleteTrackName(name); +#endif +} + // ---------------------------------------------------------------------------- AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) @@ -1022,7 +1143,8 @@ AudioFlinger::TrackBase::TrackBase( mFormat(format), mFlags(0) { - mName = audioFlinger->audioMixer()->getTrackName(); + mName = audioFlinger->getTrackName(); + LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid()); if (mName < 0) { LOGE("no more track names availlable"); return; @@ -1237,14 +1359,14 @@ bool AudioFlinger::Track::isReady() const { status_t AudioFlinger::Track::start() { - LOGV("start(%d)", mName); + LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); mAudioFlinger->addTrack(this); return NO_ERROR; } void AudioFlinger::Track::stop() { - LOGV("stop(%d)", mName); + LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); Mutex::Autolock _l(mAudioFlinger->mLock); if (mState > STOPPED) { mState = STOPPED; @@ -1258,7 +1380,7 @@ void AudioFlinger::Track::stop() void AudioFlinger::Track::pause() { - LOGV("pause(%d)", mName); + LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid()); Mutex::Autolock _l(mAudioFlinger->mLock); if (mState == ACTIVE || mState == RESUMING) { mState = PAUSING; @@ -1485,7 +1607,7 @@ AudioFlinger::RecordTrack::RecordTrack( AudioFlinger::RecordTrack::~RecordTrack() { - mAudioFlinger->audioMixer()->deleteTrackName(mName); + mAudioFlinger->deleteTrackName(mName); } status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index 9ab362a..38fa001 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -22,6 +22,7 @@ #include <sys/types.h> #include <media/IAudioFlinger.h> +#include <media/IAudioFlingerClient.h> #include <media/IAudioTrack.h> #include <media/IAudioRecord.h> #include <media/AudioTrack.h> @@ -54,7 +55,7 @@ class AudioBuffer; static const nsecs_t kStandbyTimeInNsecs = seconds(3); -class AudioFlinger : public BnAudioFlinger, protected Thread +class AudioFlinger : public BnAudioFlinger, protected Thread, public IBinder::DeathRecipient { public: static void instantiate(); @@ -109,6 +110,15 @@ public: virtual status_t setParameter(const char* key, const char* value); + virtual void registerClient(const sp<IAudioFlingerClient>& client); + + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount); + + virtual void wakeUp(); + + // IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder>& who); + enum hardware_call_state { AUDIO_HW_IDLE = 0, AUDIO_HW_INIT, @@ -314,7 +324,7 @@ private: virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); bool isMuted() const { - return mMute; + return (mMute || mAudioFlinger->mStreamTypes[mStreamType].mute); } bool isPausing() const { @@ -382,6 +392,8 @@ private: void destroyTrack(const sp<Track>& track); void addActiveTrack(const wp<Track>& track); void removeActiveTrack(const wp<Track>& track); + int getTrackName(); + void deleteTrackName(int name); AudioMixer* audioMixer() { return mAudioMixer; @@ -460,6 +472,8 @@ private: status_t startRecord(RecordTrack* recordTrack); void stopRecord(RecordTrack* recordTrack); + void notifyOutputChange_l(); + mutable Mutex mHardwareLock; mutable Mutex mLock; mutable Condition mWaitWorkCV; @@ -494,6 +508,8 @@ private: bool mInWrite; int mA2dpDisableCount; bool mA2dpSuppressed; + bool mMusicMuteSaved; + SortedVector< wp<IBinder> > mNotificationClients; }; // ---------------------------------------------------------------------------- |