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:
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user