summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2009-08-27 00:48:47 -0700
committerEric Laurent <elaurent@google.com>2009-08-27 05:58:10 -0700
commit327c27be19ad333c4835c84397152a0b2cb33081 (patch)
tree829f4323a59b922a47f6e7a60750be8e2c64a089
parent42b1648212d31dbc63518ca8379f145fef1efcb8 (diff)
downloadframeworks_base-327c27be19ad333c4835c84397152a0b2cb33081.zip
frameworks_base-327c27be19ad333c4835c84397152a0b2cb33081.tar.gz
frameworks_base-327c27be19ad333c4835c84397152a0b2cb33081.tar.bz2
Fix issue 2045911: Camera Shutter tone does not play correctly while listening to music.
Add the possibility to delay routing and volume commands in AudioPolicyClientInterface. The delay is not blocking for the caller.
-rw-r--r--include/media/AudioSystem.h1
-rw-r--r--libs/audioflinger/AudioPolicyService.cpp253
-rw-r--r--libs/audioflinger/AudioPolicyService.h23
-rw-r--r--media/libmedia/AudioSystem.cpp10
4 files changed, 212 insertions, 75 deletions
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 1f726fe..57f8102 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -451,6 +451,7 @@ public:
status_t get(const String8& key, String8& value);
status_t getInt(const String8& key, int& value);
status_t getFloat(const String8& key, float& value);
+ status_t getAt(size_t index, String8& key, String8& value);
size_t size() { return mParameters.size(); }
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
index ae17d76..5c3cc8e 100644
--- a/libs/audioflinger/AudioPolicyService.cpp
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -16,6 +16,13 @@
#define LOG_TAG "AudioPolicyService"
//#define LOG_NDEBUG 0
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include <sys/time.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <cutils/properties.h>
@@ -54,7 +61,7 @@ AudioPolicyService::AudioPolicyService()
char value[PROPERTY_VALUE_MAX];
// start tone playback thread
- mTonePlaybacThread = new AudioCommandThread();
+ mTonePlaybackThread = new AudioCommandThread();
// start audio commands thread
mAudioCommandThread = new AudioCommandThread();
@@ -80,8 +87,8 @@ AudioPolicyService::AudioPolicyService()
AudioPolicyService::~AudioPolicyService()
{
- mTonePlaybacThread->exit();
- mTonePlaybacThread.clear();
+ mTonePlaybackThread->exit();
+ mTonePlaybackThread.clear();
mAudioCommandThread->exit();
mAudioCommandThread.clear();
@@ -451,9 +458,9 @@ status_t AudioPolicyService::closeInput(audio_io_handle_t input)
return af->closeInput(input);
}
-status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output)
+status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs)
{
- return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output);
+ return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
}
status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
@@ -465,9 +472,9 @@ status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, au
}
-void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs)
{
- mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs);
+ mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs);
}
String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys)
@@ -478,13 +485,13 @@ String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const Stri
status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
{
- mTonePlaybacThread->startToneCommand(tone, stream);
+ mTonePlaybackThread->startToneCommand(tone, stream);
return NO_ERROR;
}
status_t AudioPolicyService::stopTone()
{
- mTonePlaybacThread->stopToneCommand();
+ mTonePlaybackThread->stopToneCommand();
return NO_ERROR;
}
@@ -516,58 +523,72 @@ void AudioPolicyService::AudioCommandThread::onFirstRef()
bool AudioPolicyService::AudioCommandThread::threadLoop()
{
+ nsecs_t waitTime = INT64_MAX;
+
mLock.lock();
while (!exitPending())
{
while(!mAudioCommands.isEmpty()) {
- AudioCommand *command = mAudioCommands[0];
- mAudioCommands.removeAt(0);
- switch (command->mCommand) {
- case START_TONE: {
- mLock.unlock();
- ToneData *data = (ToneData *)command->mParam;
- LOGV("AudioCommandThread() processing start tone %d on stream %d",
- data->mType, data->mStream);
- if (mpToneGenerator != NULL)
- delete mpToneGenerator;
- mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
- mpToneGenerator->startTone(data->mType);
- delete data;
- mLock.lock();
- }break;
- case STOP_TONE: {
- mLock.unlock();
- LOGV("AudioCommandThread() processing stop tone");
- if (mpToneGenerator != NULL) {
- mpToneGenerator->stopTone();
- delete mpToneGenerator;
- mpToneGenerator = NULL;
+ nsecs_t curTime = systemTime();
+ // commands are sorted by increasing time stamp: execute them from index 0 and up
+ if (mAudioCommands[0]->mTime <= curTime) {
+ AudioCommand *command = mAudioCommands[0];
+ mAudioCommands.removeAt(0);
+ switch (command->mCommand) {
+ case START_TONE: {
+ mLock.unlock();
+ ToneData *data = (ToneData *)command->mParam;
+ LOGV("AudioCommandThread() processing start tone %d on stream %d",
+ data->mType, data->mStream);
+ if (mpToneGenerator != NULL)
+ delete mpToneGenerator;
+ mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
+ mpToneGenerator->startTone(data->mType);
+ delete data;
+ mLock.lock();
+ }break;
+ case STOP_TONE: {
+ mLock.unlock();
+ LOGV("AudioCommandThread() processing stop tone");
+ if (mpToneGenerator != NULL) {
+ mpToneGenerator->stopTone();
+ delete mpToneGenerator;
+ mpToneGenerator = NULL;
+ }
+ mLock.lock();
+ }break;
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+ command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
+ command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ default:
+ LOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
- mLock.lock();
- }break;
- case SET_VOLUME: {
- VolumeData *data = (VolumeData *)command->mParam;
- LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
- mCommandStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
- mCommandCond.signal();
- mWaitWorkCV.wait(mLock);
- delete data;
- }break;
- case SET_PARAMETERS: {
- ParametersData *data = (ParametersData *)command->mParam;
- LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
- mCommandStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
- mCommandCond.signal();
- mWaitWorkCV.wait(mLock);
- delete data;
- }break;
- default:
- LOGW("AudioCommandThread() unknown command %d", command->mCommand);
+ delete command;
+ waitTime = INT64_MAX;
+ } else {
+ waitTime = mAudioCommands[0]->mTime - curTime;
+ break;
}
- delete command;
}
LOGV("AudioCommandThread() going to sleep");
- mWaitWorkCV.wait(mLock);
+ mWaitWorkCV.waitRelative(mLock, waitTime);
LOGV("AudioCommandThread() waking up");
}
mLock.unlock();
@@ -583,7 +604,8 @@ void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stre
data->mType = type;
data->mStream = stream;
command->mParam = (void *)data;
- mAudioCommands.add(command);
+ command->mWaitStatus = false;
+ insertCommand_l(command);
LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
mWaitWorkCV.signal();
}
@@ -594,13 +616,16 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand()
AudioCommand *command = new AudioCommand();
command->mCommand = STOP_TONE;
command->mParam = NULL;
- mAudioCommands.add(command);
+ command->mWaitStatus = false;
+ insertCommand_l(command);
LOGV("AudioCommandThread() adding tone stop");
mWaitWorkCV.signal();
}
-status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output)
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs)
{
+ status_t status = NO_ERROR;
+
Mutex::Autolock _l(mLock);
AudioCommand *command = new AudioCommand();
command->mCommand = SET_VOLUME;
@@ -609,17 +634,26 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float
data->mVolume = volume;
data->mIO = output;
command->mParam = data;
- mAudioCommands.add(command);
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ insertCommand_l(command, delayMs);
LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
mWaitWorkCV.signal();
- mCommandCond.wait(mLock);
- status_t status = mCommandStatus;
- mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
return status;
}
-status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs)
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs)
{
+ status_t status = NO_ERROR;
+
Mutex::Autolock _l(mLock);
AudioCommand *command = new AudioCommand();
command->mCommand = SET_PARAMETERS;
@@ -627,15 +661,102 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
data->mIO = ioHandle;
data->mKeyValuePairs = keyValuePairs;
command->mParam = data;
- mAudioCommands.add(command);
- LOGV("AudioCommandThread() adding set parameter string %s, io %d", keyValuePairs.string(), ioHandle);
- mWaitWorkCV.signal();
- mCommandCond.wait(mLock);
- status_t status = mCommandStatus;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs);
mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
return status;
}
+// insertCommand_l() must be called with mLock held
+void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
+{
+ ssize_t i;
+ Vector <AudioCommand *> removedCommands;
+
+ command->mTime = systemTime() + milliseconds(delayMs);
+
+ // check same pending commands with later time stamps and eliminate them
+ for (i = mAudioCommands.size()-1; i >= 0; i--) {
+ AudioCommand *command2 = mAudioCommands[i];
+ // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
+ if (command2->mTime <= command->mTime) break;
+ if (command2->mCommand != command->mCommand) continue;
+
+ switch (command->mCommand) {
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ ParametersData *data2 = (ParametersData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
+ AudioParameter param = AudioParameter(data->mKeyValuePairs);
+ AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
+ for (size_t j = 0; j < param.size(); j++) {
+ String8 key;
+ String8 value;
+ param.getAt(j, key, value);
+ for (size_t k = 0; k < param2.size(); k++) {
+ String8 key2;
+ String8 value2;
+ param2.getAt(k, key2, value2);
+ if (key2 == key) {
+ param2.remove(key2);
+ LOGV("Filtering out parameter %s", key2.string());
+ break;
+ }
+ }
+ }
+ // if all keys have been filtered out, remove the command.
+ // otherwise, update the key value pairs
+ if (param2.size() == 0) {
+ removedCommands.add(command2);
+ } else {
+ data2->mKeyValuePairs = param2.toString();
+ }
+ } break;
+
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ VolumeData *data2 = (VolumeData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ if (data->mStream != data2->mStream) break;
+ LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream);
+ removedCommands.add(command2);
+ } break;
+ case START_TONE:
+ case STOP_TONE:
+ default:
+ break;
+ }
+ }
+
+ // remove filtered commands
+ for (size_t j = 0; j < removedCommands.size(); j++) {
+ // removed commands always have time stamps greater than current command
+ for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
+ if (mAudioCommands[k] == removedCommands[j]) {
+ LOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
+ mAudioCommands.removeAt(k);
+ break;
+ }
+ }
+ }
+ removedCommands.clear();
+
+ // insert command at the right place according to its time stamp
+ LOGV("inserting command: %d at index %ld, num commands %d", command->mCommand, i+1, mAudioCommands.size());
+ mAudioCommands.insertAt(command, i + 1);
+}
+
void AudioPolicyService::AudioCommandThread::exit()
{
LOGV("AudioCommandThread::exit");
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
index 3909fa4..56a85e1 100644
--- a/libs/audioflinger/AudioPolicyService.h
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -20,6 +20,7 @@
#include <media/IAudioPolicyService.h>
#include <hardware_legacy/AudioPolicyInterface.h>
#include <media/ToneGenerator.h>
+#include <utils/Vector.h>
namespace android {
@@ -98,9 +99,9 @@ public:
uint32_t *pChannels,
uint32_t acoustics);
virtual status_t closeInput(audio_io_handle_t input);
- virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0);
virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
- virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
virtual status_t stopTone();
@@ -116,6 +117,7 @@ private:
// For audio config commands, it is necessary because audio flinger requires that the calling process (user)
// has permission to modify audio settings.
class AudioCommandThread : public Thread {
+ class AudioCommand;
public:
// commands for tone AudioCommand
@@ -136,15 +138,20 @@ private:
void exit();
void startToneCommand(int type = 0, int stream = 0);
void stopToneCommand();
- status_t volumeCommand(int stream, float volume, int output);
- status_t parametersCommand(int ioHandle, const String8& keyValuePairs);
+ status_t volumeCommand(int stream, float volume, int output, int delayMs = 0);
+ status_t parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs = 0);
+ void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
// descriptor for requested tone playback event
class AudioCommand {
public:
int mCommand; // START_TONE, STOP_TONE ...
- void *mParam;
+ nsecs_t mTime; // time stamp
+ Condition mCond; // condition for status return
+ status_t mStatus; // command status
+ bool mWaitStatus; // true if caller is waiting for status
+ void *mParam; // command parameter (ToneData, VolumeData, ParametersData)
};
class ToneData {
@@ -168,9 +175,7 @@ private:
Mutex mLock;
Condition mWaitWorkCV;
- Vector<AudioCommand *> mAudioCommands; // list of pending tone events
- Condition mCommandCond;
- status_t mCommandStatus;
+ Vector <AudioCommand *> mAudioCommands; // list of pending commands
ToneGenerator *mpToneGenerator; // the tone generator
};
@@ -182,7 +187,7 @@ private:
// connection stated our routing
AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
- sp <AudioCommandThread> mTonePlaybacThread; // tone playback thread
+ sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread
};
}; // namespace android
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 98b55e9..bd1b2d7 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -883,5 +883,15 @@ status_t AudioParameter::getFloat(const String8& key, float& value)
return result;
}
+status_t AudioParameter::getAt(size_t index, String8& key, String8& value)
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ value = mParameters.valueAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
}; // namespace android