am bc86bda4: Merge change 22897 into eclair

Merge commit 'bc86bda499b8600cc3dc900bba0e6421304c26dd' into eclair-plus-aosp

* commit 'bc86bda499b8600cc3dc900bba0e6421304c26dd':
  Fix issue 2045911: Camera Shutter tone does not play correctly while listening to music.
This commit is contained in:
Eric Laurent
2009-08-27 11:38:29 -07:00
committed by Android Git Automerger
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 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(); }

View File

@@ -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");

View File

@@ -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

View File

@@ -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