summaryrefslogtreecommitdiffstats
path: root/libs/audioflinger
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-02-10 15:44:00 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-02-10 15:44:00 -0800
commitd24b8183b93e781080b2c16c487e60d51c12da31 (patch)
treefbb89154858984eb8e41556da7e9433040d55cd4 /libs/audioflinger
parentf1e484acb594a726fb57ad0ae4cfe902c7f35858 (diff)
downloadframeworks_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.cpp27
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h3
-rw-r--r--libs/audioflinger/AudioFlinger.cpp154
-rw-r--r--libs/audioflinger/AudioFlinger.h20
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;
};
// ----------------------------------------------------------------------------