Merge change 22897 into eclair

* changes:
  Fix issue 2045911: Camera Shutter tone does not play correctly while listening to music.
This commit is contained in:
Android (Google) Code Review
2009-08-27 11:37:35 -07:00
4 changed files with 212 additions and 75 deletions

View File

@@ -451,6 +451,7 @@ public:
status_t get(const String8& key, String8& value); status_t get(const String8& key, String8& value);
status_t getInt(const String8& key, int& value); status_t getInt(const String8& key, int& value);
status_t getFloat(const String8& key, float& 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(); } size_t size() { return mParameters.size(); }

View File

@@ -16,6 +16,13 @@
#define LOG_TAG "AudioPolicyService" #define LOG_TAG "AudioPolicyService"
//#define LOG_NDEBUG 0 //#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 <binder/IServiceManager.h>
#include <utils/Log.h> #include <utils/Log.h>
#include <cutils/properties.h> #include <cutils/properties.h>
@@ -54,7 +61,7 @@ AudioPolicyService::AudioPolicyService()
char value[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX];
// start tone playback thread // start tone playback thread
mTonePlaybacThread = new AudioCommandThread(); mTonePlaybackThread = new AudioCommandThread();
// start audio commands thread // start audio commands thread
mAudioCommandThread = new AudioCommandThread(); mAudioCommandThread = new AudioCommandThread();
@@ -80,8 +87,8 @@ AudioPolicyService::AudioPolicyService()
AudioPolicyService::~AudioPolicyService() AudioPolicyService::~AudioPolicyService()
{ {
mTonePlaybacThread->exit(); mTonePlaybackThread->exit();
mTonePlaybacThread.clear(); mTonePlaybackThread.clear();
mAudioCommandThread->exit(); mAudioCommandThread->exit();
mAudioCommandThread.clear(); mAudioCommandThread.clear();
@@ -451,9 +458,9 @@ status_t AudioPolicyService::closeInput(audio_io_handle_t input)
return af->closeInput(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) 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) 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) status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
{ {
mTonePlaybacThread->startToneCommand(tone, stream); mTonePlaybackThread->startToneCommand(tone, stream);
return NO_ERROR; return NO_ERROR;
} }
status_t AudioPolicyService::stopTone() status_t AudioPolicyService::stopTone()
{ {
mTonePlaybacThread->stopToneCommand(); mTonePlaybackThread->stopToneCommand();
return NO_ERROR; return NO_ERROR;
} }
@@ -516,58 +523,72 @@ void AudioPolicyService::AudioCommandThread::onFirstRef()
bool AudioPolicyService::AudioCommandThread::threadLoop() bool AudioPolicyService::AudioCommandThread::threadLoop()
{ {
nsecs_t waitTime = INT64_MAX;
mLock.lock(); mLock.lock();
while (!exitPending()) while (!exitPending())
{ {
while(!mAudioCommands.isEmpty()) { while(!mAudioCommands.isEmpty()) {
AudioCommand *command = mAudioCommands[0]; nsecs_t curTime = systemTime();
mAudioCommands.removeAt(0); // commands are sorted by increasing time stamp: execute them from index 0 and up
switch (command->mCommand) { if (mAudioCommands[0]->mTime <= curTime) {
case START_TONE: { AudioCommand *command = mAudioCommands[0];
mLock.unlock(); mAudioCommands.removeAt(0);
ToneData *data = (ToneData *)command->mParam; switch (command->mCommand) {
LOGV("AudioCommandThread() processing start tone %d on stream %d", case START_TONE: {
data->mType, data->mStream); mLock.unlock();
if (mpToneGenerator != NULL) ToneData *data = (ToneData *)command->mParam;
delete mpToneGenerator; LOGV("AudioCommandThread() processing start tone %d on stream %d",
mpToneGenerator = new ToneGenerator(data->mStream, 1.0); data->mType, data->mStream);
mpToneGenerator->startTone(data->mType); if (mpToneGenerator != NULL)
delete data; delete mpToneGenerator;
mLock.lock(); mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
}break; mpToneGenerator->startTone(data->mType);
case STOP_TONE: { delete data;
mLock.unlock(); mLock.lock();
LOGV("AudioCommandThread() processing stop tone"); }break;
if (mpToneGenerator != NULL) { case STOP_TONE: {
mpToneGenerator->stopTone(); mLock.unlock();
delete mpToneGenerator; LOGV("AudioCommandThread() processing stop tone");
mpToneGenerator = NULL; 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(); delete command;
}break; waitTime = INT64_MAX;
case SET_VOLUME: { } else {
VolumeData *data = (VolumeData *)command->mParam; waitTime = mAudioCommands[0]->mTime - curTime;
LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO); break;
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;
} }
LOGV("AudioCommandThread() going to sleep"); LOGV("AudioCommandThread() going to sleep");
mWaitWorkCV.wait(mLock); mWaitWorkCV.waitRelative(mLock, waitTime);
LOGV("AudioCommandThread() waking up"); LOGV("AudioCommandThread() waking up");
} }
mLock.unlock(); mLock.unlock();
@@ -583,7 +604,8 @@ void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stre
data->mType = type; data->mType = type;
data->mStream = stream; data->mStream = stream;
command->mParam = (void *)data; command->mParam = (void *)data;
mAudioCommands.add(command); command->mWaitStatus = false;
insertCommand_l(command);
LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream); LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
mWaitWorkCV.signal(); mWaitWorkCV.signal();
} }
@@ -594,13 +616,16 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand()
AudioCommand *command = new AudioCommand(); AudioCommand *command = new AudioCommand();
command->mCommand = STOP_TONE; command->mCommand = STOP_TONE;
command->mParam = NULL; command->mParam = NULL;
mAudioCommands.add(command); command->mWaitStatus = false;
insertCommand_l(command);
LOGV("AudioCommandThread() adding tone stop"); LOGV("AudioCommandThread() adding tone stop");
mWaitWorkCV.signal(); 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); Mutex::Autolock _l(mLock);
AudioCommand *command = new AudioCommand(); AudioCommand *command = new AudioCommand();
command->mCommand = SET_VOLUME; command->mCommand = SET_VOLUME;
@@ -609,17 +634,26 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float
data->mVolume = volume; data->mVolume = volume;
data->mIO = output; data->mIO = output;
command->mParam = data; 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); LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
mWaitWorkCV.signal(); mWaitWorkCV.signal();
mCommandCond.wait(mLock); if (command->mWaitStatus) {
status_t status = mCommandStatus; command->mCond.wait(mLock);
mWaitWorkCV.signal(); status = command->mStatus;
mWaitWorkCV.signal();
}
return status; 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); Mutex::Autolock _l(mLock);
AudioCommand *command = new AudioCommand(); AudioCommand *command = new AudioCommand();
command->mCommand = SET_PARAMETERS; command->mCommand = SET_PARAMETERS;
@@ -627,15 +661,102 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
data->mIO = ioHandle; data->mIO = ioHandle;
data->mKeyValuePairs = keyValuePairs; data->mKeyValuePairs = keyValuePairs;
command->mParam = data; command->mParam = data;
mAudioCommands.add(command); if (delayMs == 0) {
LOGV("AudioCommandThread() adding set parameter string %s, io %d", keyValuePairs.string(), ioHandle); command->mWaitStatus = true;
mWaitWorkCV.signal(); } else {
mCommandCond.wait(mLock); command->mWaitStatus = false;
status_t status = mCommandStatus; }
insertCommand_l(command, delayMs);
LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs);
mWaitWorkCV.signal(); mWaitWorkCV.signal();
if (command->mWaitStatus) {
command->mCond.wait(mLock);
status = command->mStatus;
mWaitWorkCV.signal();
}
return status; 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() void AudioPolicyService::AudioCommandThread::exit()
{ {
LOGV("AudioCommandThread::exit"); LOGV("AudioCommandThread::exit");

View File

@@ -20,6 +20,7 @@
#include <media/IAudioPolicyService.h> #include <media/IAudioPolicyService.h>
#include <hardware_legacy/AudioPolicyInterface.h> #include <hardware_legacy/AudioPolicyInterface.h>
#include <media/ToneGenerator.h> #include <media/ToneGenerator.h>
#include <utils/Vector.h>
namespace android { namespace android {
@@ -98,9 +99,9 @@ public:
uint32_t *pChannels, uint32_t *pChannels,
uint32_t acoustics); uint32_t acoustics);
virtual status_t closeInput(audio_io_handle_t input); 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 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 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 startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
virtual status_t stopTone(); 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) // For audio config commands, it is necessary because audio flinger requires that the calling process (user)
// has permission to modify audio settings. // has permission to modify audio settings.
class AudioCommandThread : public Thread { class AudioCommandThread : public Thread {
class AudioCommand;
public: public:
// commands for tone AudioCommand // commands for tone AudioCommand
@@ -136,15 +138,20 @@ private:
void exit(); void exit();
void startToneCommand(int type = 0, int stream = 0); void startToneCommand(int type = 0, int stream = 0);
void stopToneCommand(); void stopToneCommand();
status_t volumeCommand(int stream, float volume, int output); status_t volumeCommand(int stream, float volume, int output, int delayMs = 0);
status_t parametersCommand(int ioHandle, const String8& keyValuePairs); status_t parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs = 0);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private: private:
// descriptor for requested tone playback event // descriptor for requested tone playback event
class AudioCommand { class AudioCommand {
public: public:
int mCommand; // START_TONE, STOP_TONE ... 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 { class ToneData {
@@ -168,9 +175,7 @@ private:
Mutex mLock; Mutex mLock;
Condition mWaitWorkCV; Condition mWaitWorkCV;
Vector<AudioCommand *> mAudioCommands; // list of pending tone events Vector <AudioCommand *> mAudioCommands; // list of pending commands
Condition mCommandCond;
status_t mCommandStatus;
ToneGenerator *mpToneGenerator; // the tone generator ToneGenerator *mpToneGenerator; // the tone generator
}; };
@@ -182,7 +187,7 @@ private:
// connection stated our routing // connection stated our routing
AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
sp <AudioCommandThread> mAudioCommandThread; // audio commands thread sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
sp <AudioCommandThread> mTonePlaybacThread; // tone playback thread sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread
}; };
}; // namespace android }; // namespace android

View File

@@ -883,5 +883,15 @@ status_t AudioParameter::getFloat(const String8& key, float& value)
return result; 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 }; // namespace android