Create base class for audio policy manager.
First implementations of audio policy manager in Eclair branch have shown that most code is common to all platforms. Creating AudioPolicyManagerBase base class will improve code maintainability and readability. Audio policy manager code for platforms using generic audio previously in AudioPolicyManagerGeneric is replaced by AudioPolicyManagerBase. Audio policy manager test code previously in AudioPolicyManagerGeneric is moved to AudioPolicyManagerBase. Also added a wake lock for delayed commands in AudioPolicyService.
This commit is contained in:
@@ -244,6 +244,8 @@ public:
|
||||
DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
|
||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
|
||||
DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
|
||||
|
||||
// input devices
|
||||
DEVICE_IN_COMMUNICATION = 0x10000,
|
||||
|
||||
@@ -47,7 +47,7 @@ include $(BUILD_STATIC_LIBRARY)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
AudioPolicyManagerGeneric.cpp
|
||||
AudioPolicyManagerBase.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
@@ -60,7 +60,7 @@ else
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
LOCAL_MODULE:= libaudiopolicygeneric
|
||||
LOCAL_MODULE:= libaudiopolicybase
|
||||
|
||||
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
|
||||
LOCAL_CFLAGS += -DWITH_A2DP
|
||||
@@ -70,7 +70,7 @@ ifeq ($(AUDIO_POLICY_TEST),true)
|
||||
LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
@@ -87,11 +87,10 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libutils \
|
||||
libbinder \
|
||||
libmedia \
|
||||
libhardware_legacy \
|
||||
libaudiopolicygeneric
|
||||
libhardware_legacy
|
||||
|
||||
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
|
||||
LOCAL_STATIC_LIBRARIES += libaudiointerface
|
||||
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase
|
||||
LOCAL_CFLAGS += -DGENERIC_AUDIO
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
|
||||
|
||||
1925
libs/audioflinger/AudioPolicyManagerBase.cpp
Normal file
1925
libs/audioflinger/AudioPolicyManagerBase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,945 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "AudioPolicyManagerGeneric"
|
||||
//#define LOG_NDEBUG 0
|
||||
#include <utils/Log.h>
|
||||
#include "AudioPolicyManagerGeneric.h"
|
||||
#include <media/mediarecorder.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// AudioPolicyInterface implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device,
|
||||
AudioSystem::device_connection_state state,
|
||||
const char *device_address)
|
||||
{
|
||||
|
||||
LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
|
||||
|
||||
// connect/disconnect only 1 device at a time
|
||||
if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
|
||||
|
||||
if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
|
||||
LOGE("setDeviceConnectionState() invalid address: %s", device_address);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// handle output devices
|
||||
if (AudioSystem::isOutputDevice(device)) {
|
||||
switch (state)
|
||||
{
|
||||
// handle output device connection
|
||||
case AudioSystem::DEVICE_STATE_AVAILABLE:
|
||||
if (mAvailableOutputDevices & device) {
|
||||
LOGW("setDeviceConnectionState() device already connected: %x", device);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
LOGV("setDeviceConnectionState() connecting device %x", device);
|
||||
|
||||
// register new device as available
|
||||
mAvailableOutputDevices |= device;
|
||||
break;
|
||||
// handle output device disconnection
|
||||
case AudioSystem::DEVICE_STATE_UNAVAILABLE:
|
||||
if (!(mAvailableOutputDevices & device)) {
|
||||
LOGW("setDeviceConnectionState() device not connected: %x", device);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
LOGV("setDeviceConnectionState() disconnecting device %x", device);
|
||||
// remove device from available output devices
|
||||
mAvailableOutputDevices &= ~device;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("setDeviceConnectionState() invalid state: %x", state);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
// handle input devices
|
||||
if (AudioSystem::isInputDevice(device)) {
|
||||
switch (state)
|
||||
{
|
||||
// handle input device connection
|
||||
case AudioSystem::DEVICE_STATE_AVAILABLE:
|
||||
if (mAvailableInputDevices & device) {
|
||||
LOGW("setDeviceConnectionState() device already connected: %d", device);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
mAvailableInputDevices |= device;
|
||||
break;
|
||||
|
||||
// handle input device disconnection
|
||||
case AudioSystem::DEVICE_STATE_UNAVAILABLE:
|
||||
if (!(mAvailableInputDevices & device)) {
|
||||
LOGW("setDeviceConnectionState() device not connected: %d", device);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
mAvailableInputDevices &= ~device;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("setDeviceConnectionState() invalid state: %x", state);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
LOGW("setDeviceConnectionState() invalid device: %x", device);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device,
|
||||
const char *device_address)
|
||||
{
|
||||
AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
|
||||
String8 address = String8(device_address);
|
||||
if (AudioSystem::isOutputDevice(device)) {
|
||||
if (device & mAvailableOutputDevices) {
|
||||
state = AudioSystem::DEVICE_STATE_AVAILABLE;
|
||||
}
|
||||
} else if (AudioSystem::isInputDevice(device)) {
|
||||
if (device & mAvailableInputDevices) {
|
||||
state = AudioSystem::DEVICE_STATE_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::setPhoneState(int state)
|
||||
{
|
||||
LOGV("setPhoneState() state %d", state);
|
||||
uint32_t newDevice = 0;
|
||||
if (state < 0 || state >= AudioSystem::NUM_MODES) {
|
||||
LOGW("setPhoneState() invalid state %d", state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == mPhoneState ) {
|
||||
LOGW("setPhoneState() setting same state %d", state);
|
||||
return;
|
||||
}
|
||||
// store previous phone state for management of sonification strategy below
|
||||
int oldState = mPhoneState;
|
||||
mPhoneState = state;
|
||||
|
||||
// if leaving or entering in call state, handle special case of active streams
|
||||
// pertaining to sonification strategy see handleIncallSonification()
|
||||
if (state == AudioSystem::MODE_IN_CALL ||
|
||||
oldState == AudioSystem::MODE_IN_CALL) {
|
||||
bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false;
|
||||
LOGV("setPhoneState() in call state management: new state is %d", state);
|
||||
for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
|
||||
handleIncallSonification(stream, starting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask)
|
||||
{
|
||||
LOGV("setRingerMode() mode %x, mask %x", mode, mask);
|
||||
|
||||
mRingerMode = mode;
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
|
||||
{
|
||||
LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
|
||||
mForceUse[usage] = config;
|
||||
}
|
||||
|
||||
AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage)
|
||||
{
|
||||
return mForceUse[usage];
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value)
|
||||
{
|
||||
LOGV("setSystemProperty() property %s, value %s", property, value);
|
||||
if (strcmp(property, "ro.camera.sound.forced") == 0) {
|
||||
if (atoi(value)) {
|
||||
LOGV("ENFORCED_AUDIBLE cannot be muted");
|
||||
mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
|
||||
} else {
|
||||
LOGV("ENFORCED_AUDIBLE can be muted");
|
||||
mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream,
|
||||
uint32_t samplingRate,
|
||||
uint32_t format,
|
||||
uint32_t channels,
|
||||
AudioSystem::output_flags flags)
|
||||
{
|
||||
LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
if (mCurOutput != 0) {
|
||||
LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
|
||||
mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
|
||||
|
||||
if (mTestOutputs[mCurOutput] == 0) {
|
||||
LOGV("getOutput() opening test output");
|
||||
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
|
||||
outputDesc->mDevice = mTestDevice;
|
||||
outputDesc->mSamplingRate = mTestSamplingRate;
|
||||
outputDesc->mFormat = mTestFormat;
|
||||
outputDesc->mChannels = mTestChannels;
|
||||
outputDesc->mLatency = mTestLatencyMs;
|
||||
outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
|
||||
outputDesc->mRefCount[stream] = 0;
|
||||
mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
|
||||
&outputDesc->mSamplingRate,
|
||||
&outputDesc->mFormat,
|
||||
&outputDesc->mChannels,
|
||||
&outputDesc->mLatency,
|
||||
outputDesc->mFlags);
|
||||
if (mTestOutputs[mCurOutput]) {
|
||||
AudioParameter outputCmd = AudioParameter();
|
||||
outputCmd.addInt(String8("set_id"),mCurOutput);
|
||||
mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
|
||||
mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
|
||||
}
|
||||
}
|
||||
return mTestOutputs[mCurOutput];
|
||||
}
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
|
||||
(format != 0 && !AudioSystem::isLinearPCM(format)) ||
|
||||
(channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mHardwareOutput;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
{
|
||||
LOGV("startOutput() output %d, stream %d", output, stream);
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("startOutput() unknow output %d", output);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
|
||||
|
||||
// handle special case for sonification while in call
|
||||
if (mPhoneState == AudioSystem::MODE_IN_CALL) {
|
||||
handleIncallSonification(stream, true);
|
||||
}
|
||||
|
||||
// incremenent usage count for this stream on the requested output:
|
||||
outputDesc->changeRefCount(stream, 1);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
{
|
||||
LOGV("stopOutput() output %d, stream %d", output, stream);
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("stopOutput() unknow output %d", output);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
|
||||
|
||||
// handle special case for sonification while in call
|
||||
if (mPhoneState == AudioSystem::MODE_IN_CALL) {
|
||||
handleIncallSonification(stream, false);
|
||||
}
|
||||
|
||||
if (outputDesc->isUsedByStream(stream)) {
|
||||
// decrement usage count of this stream on the output
|
||||
outputDesc->changeRefCount(stream, -1);
|
||||
return NO_ERROR;
|
||||
} else {
|
||||
LOGW("stopOutput() refcount is already 0 for output %d", output);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
|
||||
{
|
||||
LOGV("releaseOutput() %d", output);
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("releaseOutput() releasing unknown output %d", output);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
int testIndex = testOutputIndex(output);
|
||||
if (testIndex != 0) {
|
||||
AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
|
||||
if (outputDesc->refCount() == 0) {
|
||||
mpClientInterface->closeOutput(output);
|
||||
delete mOutputs.valueAt(index);
|
||||
mOutputs.removeItem(output);
|
||||
mTestOutputs[testIndex] = 0;
|
||||
}
|
||||
}
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource,
|
||||
uint32_t samplingRate,
|
||||
uint32_t format,
|
||||
uint32_t channels,
|
||||
AudioSystem::audio_in_acoustics acoustics)
|
||||
{
|
||||
audio_io_handle_t input = 0;
|
||||
uint32_t device;
|
||||
|
||||
LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
|
||||
|
||||
AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
|
||||
inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC;
|
||||
inputDesc->mSamplingRate = samplingRate;
|
||||
inputDesc->mFormat = format;
|
||||
inputDesc->mChannels = channels;
|
||||
inputDesc->mAcoustics = acoustics;
|
||||
inputDesc->mRefCount = 0;
|
||||
input = mpClientInterface->openInput(&inputDesc->mDevice,
|
||||
&inputDesc->mSamplingRate,
|
||||
&inputDesc->mFormat,
|
||||
&inputDesc->mChannels,
|
||||
inputDesc->mAcoustics);
|
||||
|
||||
// only accept input with the exact requested set of parameters
|
||||
if ((samplingRate != inputDesc->mSamplingRate) ||
|
||||
(format != inputDesc->mFormat) ||
|
||||
(channels != inputDesc->mChannels)) {
|
||||
LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d",
|
||||
samplingRate, format, channels);
|
||||
mpClientInterface->closeInput(input);
|
||||
delete inputDesc;
|
||||
return 0;
|
||||
}
|
||||
mInputs.add(input, inputDesc);
|
||||
return input;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
|
||||
{
|
||||
LOGV("startInput() input %d", input);
|
||||
ssize_t index = mInputs.indexOfKey(input);
|
||||
if (index < 0) {
|
||||
LOGW("startInput() unknow input %d", input);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
if (mTestInput == 0)
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
{
|
||||
// refuse 2 active AudioRecord clients at the same time
|
||||
for (size_t i = 0; i < mInputs.size(); i++) {
|
||||
if (mInputs.valueAt(i)->mRefCount > 0) {
|
||||
LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i));
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inputDesc->mRefCount = 1;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
|
||||
{
|
||||
LOGV("stopInput() input %d", input);
|
||||
ssize_t index = mInputs.indexOfKey(input);
|
||||
if (index < 0) {
|
||||
LOGW("stopInput() unknow input %d", input);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
|
||||
|
||||
if (inputDesc->mRefCount == 0) {
|
||||
LOGW("stopInput() input %d already stopped", input);
|
||||
return INVALID_OPERATION;
|
||||
} else {
|
||||
inputDesc->mRefCount = 0;
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
|
||||
{
|
||||
LOGV("releaseInput() %d", input);
|
||||
ssize_t index = mInputs.indexOfKey(input);
|
||||
if (index < 0) {
|
||||
LOGW("releaseInput() releasing unknown input %d", input);
|
||||
return;
|
||||
}
|
||||
mpClientInterface->closeInput(input);
|
||||
delete mInputs.valueAt(index);
|
||||
mInputs.removeItem(input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream,
|
||||
int indexMin,
|
||||
int indexMax)
|
||||
{
|
||||
LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
|
||||
mStreams[stream].mIndexMin = indexMin;
|
||||
mStreams[stream].mIndexMax = indexMax;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
|
||||
{
|
||||
|
||||
if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
|
||||
mStreams[stream].mIndexCur = index;
|
||||
|
||||
// do not change actual stream volume if the stream is muted
|
||||
if (mStreams[stream].mMuteCount != 0) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Do not changed in call volume if bluetooth is connected and vice versa
|
||||
if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
|
||||
(stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
|
||||
LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm",
|
||||
stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// compute and apply stream volume on all outputs according to connected device
|
||||
for (size_t i = 0; i < mOutputs.size(); i++) {
|
||||
AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
|
||||
uint32_t device = outputDesc->device();
|
||||
|
||||
float volume = computeVolume((int)stream, index, device);
|
||||
|
||||
LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
|
||||
mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
|
||||
{
|
||||
if (index == 0) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
LOGV("getStreamVolumeIndex() stream %d", stream);
|
||||
*index = mStreams[stream].mIndexCur;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::dump(int fd)
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
String8 result;
|
||||
|
||||
snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Hardware Output: %d\n", mHardwareOutput);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Ringer mode: %d\n", mRingerMode);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
|
||||
result.append(buffer);
|
||||
write(fd, result.string(), result.size());
|
||||
|
||||
snprintf(buffer, SIZE, "\nOutputs dump:\n");
|
||||
write(fd, buffer, strlen(buffer));
|
||||
for (size_t i = 0; i < mOutputs.size(); i++) {
|
||||
snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
|
||||
write(fd, buffer, strlen(buffer));
|
||||
mOutputs.valueAt(i)->dump(fd);
|
||||
}
|
||||
|
||||
snprintf(buffer, SIZE, "\nInputs dump:\n");
|
||||
write(fd, buffer, strlen(buffer));
|
||||
for (size_t i = 0; i < mInputs.size(); i++) {
|
||||
snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
|
||||
write(fd, buffer, strlen(buffer));
|
||||
mInputs.valueAt(i)->dump(fd);
|
||||
}
|
||||
|
||||
snprintf(buffer, SIZE, "\nStreams dump:\n");
|
||||
write(fd, buffer, strlen(buffer));
|
||||
snprintf(buffer, SIZE, " Stream Index Min Index Max Index Cur Mute Count Can be muted\n");
|
||||
write(fd, buffer, strlen(buffer));
|
||||
for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
snprintf(buffer, SIZE, " %02d", i);
|
||||
mStreams[i].dump(buffer + 3, SIZE);
|
||||
write(fd, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// AudioPolicyManagerGeneric
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// --- class factory
|
||||
|
||||
AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface)
|
||||
:
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
Thread(false),
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0)
|
||||
{
|
||||
mpClientInterface = clientInterface;
|
||||
|
||||
for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
|
||||
mForceUse[i] = AudioSystem::FORCE_NONE;
|
||||
}
|
||||
|
||||
// devices available by default are speaker, ear piece and microphone
|
||||
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER;
|
||||
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
|
||||
|
||||
// open hardware output
|
||||
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
|
||||
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
|
||||
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
|
||||
&outputDesc->mSamplingRate,
|
||||
&outputDesc->mFormat,
|
||||
&outputDesc->mChannels,
|
||||
&outputDesc->mLatency,
|
||||
outputDesc->mFlags);
|
||||
|
||||
if (mHardwareOutput == 0) {
|
||||
LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
|
||||
outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
|
||||
} else {
|
||||
mOutputs.add(mHardwareOutput, outputDesc);
|
||||
}
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
AudioParameter outputCmd = AudioParameter();
|
||||
outputCmd.addInt(String8("set_id"), 0);
|
||||
mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
|
||||
|
||||
mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
|
||||
mTestSamplingRate = 44100;
|
||||
mTestFormat = AudioSystem::PCM_16_BIT;
|
||||
mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
|
||||
mTestLatencyMs = 0;
|
||||
mCurOutput = 0;
|
||||
mDirectOutput = false;
|
||||
for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
|
||||
mTestOutputs[i] = 0;
|
||||
}
|
||||
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
snprintf(buffer, SIZE, "AudioPolicyManagerTest");
|
||||
run(buffer, ANDROID_PRIORITY_AUDIO);
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
}
|
||||
|
||||
AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric()
|
||||
{
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
exit();
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
|
||||
for (size_t i = 0; i < mOutputs.size(); i++) {
|
||||
mpClientInterface->closeOutput(mOutputs.keyAt(i));
|
||||
delete mOutputs.valueAt(i);
|
||||
}
|
||||
mOutputs.clear();
|
||||
for (size_t i = 0; i < mInputs.size(); i++) {
|
||||
mpClientInterface->closeInput(mInputs.keyAt(i));
|
||||
delete mInputs.valueAt(i);
|
||||
}
|
||||
mInputs.clear();
|
||||
}
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
bool AudioPolicyManagerGeneric::threadLoop()
|
||||
{
|
||||
LOGV("entering threadLoop()");
|
||||
while (!exitPending())
|
||||
{
|
||||
String8 command;
|
||||
int valueInt;
|
||||
String8 value;
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
mWaitWorkCV.waitRelative(mLock, milliseconds(50));
|
||||
|
||||
command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
|
||||
AudioParameter param = AudioParameter(command);
|
||||
|
||||
if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
|
||||
valueInt != 0) {
|
||||
LOGV("Test command %s received", command.string());
|
||||
String8 target;
|
||||
if (param.get(String8("target"), target) != NO_ERROR) {
|
||||
target = "Manager";
|
||||
}
|
||||
if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_output"));
|
||||
mCurOutput = valueInt;
|
||||
}
|
||||
if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_direct"));
|
||||
if (value == "false") {
|
||||
mDirectOutput = false;
|
||||
} else if (value == "true") {
|
||||
mDirectOutput = true;
|
||||
}
|
||||
}
|
||||
if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_input"));
|
||||
mTestInput = valueInt;
|
||||
}
|
||||
|
||||
if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_format"));
|
||||
int format = AudioSystem::INVALID_FORMAT;
|
||||
if (value == "PCM 16 bits") {
|
||||
format = AudioSystem::PCM_16_BIT;
|
||||
} else if (value == "PCM 8 bits") {
|
||||
format = AudioSystem::PCM_8_BIT;
|
||||
} else if (value == "Compressed MP3") {
|
||||
format = AudioSystem::MP3;
|
||||
}
|
||||
if (format != AudioSystem::INVALID_FORMAT) {
|
||||
if (target == "Manager") {
|
||||
mTestFormat = format;
|
||||
} else if (mTestOutputs[mCurOutput] != 0) {
|
||||
AudioParameter outputParam = AudioParameter();
|
||||
outputParam.addInt(String8("format"), format);
|
||||
mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_channels"));
|
||||
int channels = 0;
|
||||
|
||||
if (value == "Channels Stereo") {
|
||||
channels = AudioSystem::CHANNEL_OUT_STEREO;
|
||||
} else if (value == "Channels Mono") {
|
||||
channels = AudioSystem::CHANNEL_OUT_MONO;
|
||||
}
|
||||
if (channels != 0) {
|
||||
if (target == "Manager") {
|
||||
mTestChannels = channels;
|
||||
} else if (mTestOutputs[mCurOutput] != 0) {
|
||||
AudioParameter outputParam = AudioParameter();
|
||||
outputParam.addInt(String8("channels"), channels);
|
||||
mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_sampleRate"));
|
||||
if (valueInt >= 0 && valueInt <= 96000) {
|
||||
int samplingRate = valueInt;
|
||||
if (target == "Manager") {
|
||||
mTestSamplingRate = samplingRate;
|
||||
} else if (mTestOutputs[mCurOutput] != 0) {
|
||||
AudioParameter outputParam = AudioParameter();
|
||||
outputParam.addInt(String8("sampling_rate"), samplingRate);
|
||||
mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
|
||||
param.remove(String8("test_cmd_policy_reopen"));
|
||||
|
||||
mpClientInterface->closeOutput(mHardwareOutput);
|
||||
delete mOutputs.valueFor(mHardwareOutput);
|
||||
mOutputs.removeItem(mHardwareOutput);
|
||||
|
||||
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
|
||||
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
|
||||
mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
|
||||
&outputDesc->mSamplingRate,
|
||||
&outputDesc->mFormat,
|
||||
&outputDesc->mChannels,
|
||||
&outputDesc->mLatency,
|
||||
outputDesc->mFlags);
|
||||
if (mHardwareOutput == 0) {
|
||||
LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
|
||||
outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
|
||||
} else {
|
||||
AudioParameter outputCmd = AudioParameter();
|
||||
outputCmd.addInt(String8("set_id"), 0);
|
||||
mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
|
||||
mOutputs.add(mHardwareOutput, outputDesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mpClientInterface->setParameters(0, String8("test_cmd_policy="));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::exit()
|
||||
{
|
||||
{
|
||||
AutoMutex _l(mLock);
|
||||
requestExit();
|
||||
mWaitWorkCV.signal();
|
||||
}
|
||||
requestExitAndWait();
|
||||
}
|
||||
|
||||
int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output)
|
||||
{
|
||||
for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
|
||||
if (output == mTestOutputs[i]) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
|
||||
// ---
|
||||
|
||||
AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream)
|
||||
{
|
||||
// stream to strategy mapping
|
||||
switch (stream) {
|
||||
case AudioSystem::VOICE_CALL:
|
||||
case AudioSystem::BLUETOOTH_SCO:
|
||||
return STRATEGY_PHONE;
|
||||
case AudioSystem::RING:
|
||||
case AudioSystem::NOTIFICATION:
|
||||
case AudioSystem::ALARM:
|
||||
case AudioSystem::ENFORCED_AUDIBLE:
|
||||
return STRATEGY_SONIFICATION;
|
||||
case AudioSystem::DTMF:
|
||||
return STRATEGY_DTMF;
|
||||
default:
|
||||
LOGE("unknown stream type");
|
||||
case AudioSystem::SYSTEM:
|
||||
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
|
||||
// while key clicks are played produces a poor result
|
||||
case AudioSystem::TTS:
|
||||
case AudioSystem::MUSIC:
|
||||
return STRATEGY_MEDIA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device)
|
||||
{
|
||||
float volume = 1.0;
|
||||
|
||||
StreamDescriptor &streamDesc = mStreams[stream];
|
||||
|
||||
// Force max volume if stream cannot be muted
|
||||
if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax;
|
||||
|
||||
int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
|
||||
volume = AudioSystem::linearToLog(volInt);
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
|
||||
{
|
||||
LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output);
|
||||
|
||||
StreamDescriptor &streamDesc = mStreams[stream];
|
||||
|
||||
if (on) {
|
||||
if (streamDesc.mMuteCount++ == 0) {
|
||||
if (streamDesc.mCanBeMuted) {
|
||||
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (streamDesc.mMuteCount == 0) {
|
||||
LOGW("setStreamMute() unmuting non muted stream!");
|
||||
return;
|
||||
}
|
||||
if (--streamDesc.mMuteCount == 0) {
|
||||
uint32_t device = mOutputs.valueFor(output)->mDevice;
|
||||
float volume = computeVolume(stream, streamDesc.mIndexCur, device);
|
||||
mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting)
|
||||
{
|
||||
// if the stream pertains to sonification strategy and we are in call we must
|
||||
// mute the stream if it is low visibility. If it is high visibility, we must play a tone
|
||||
// in the device used for phone strategy and play the tone if the selected device does not
|
||||
// interfere with the device used for phone strategy
|
||||
if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
|
||||
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
|
||||
LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice);
|
||||
if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) {
|
||||
if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
|
||||
LOGV("handleIncallSonification() low visibility");
|
||||
setStreamMute(stream, starting, mHardwareOutput);
|
||||
} else {
|
||||
if (starting) {
|
||||
mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
|
||||
} else {
|
||||
mpClientInterface->stopTone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- AudioOutputDescriptor class implementation
|
||||
|
||||
AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor()
|
||||
: mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
|
||||
mFlags((AudioSystem::output_flags)0), mDevice(0)
|
||||
{
|
||||
// clear usage count for all stream types
|
||||
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
mRefCount[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
|
||||
{
|
||||
if ((delta + (int)mRefCount[stream]) < 0) {
|
||||
LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
|
||||
mRefCount[stream] = 0;
|
||||
return;
|
||||
}
|
||||
mRefCount[stream] += delta;
|
||||
LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
|
||||
}
|
||||
|
||||
uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount()
|
||||
{
|
||||
uint32_t refcount = 0;
|
||||
for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
refcount += mRefCount[i];
|
||||
}
|
||||
return refcount;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::AudioOutputDescriptor::dump(int fd)
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
String8 result;
|
||||
|
||||
snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Format: %d\n", mFormat);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Stream refCount\n");
|
||||
result.append(buffer);
|
||||
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
snprintf(buffer, SIZE, " %02d %d\n", i, mRefCount[i]);
|
||||
result.append(buffer);
|
||||
}
|
||||
write(fd, result.string(), result.size());
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// --- AudioInputDescriptor class implementation
|
||||
|
||||
AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
|
||||
: mSamplingRate(0), mFormat(0), mChannels(0),
|
||||
mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerGeneric::AudioInputDescriptor::dump(int fd)
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
String8 result;
|
||||
|
||||
snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Format: %d\n", mFormat);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Channels: %08x\n", mChannels);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Acoustics %08x\n", mAcoustics);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
|
||||
result.append(buffer);
|
||||
write(fd, result.string(), result.size());
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// --- StreamDescriptor class implementation
|
||||
|
||||
void AudioPolicyManagerGeneric::StreamDescriptor::dump(char* buffer, size_t size)
|
||||
{
|
||||
snprintf(buffer, size, " %02d %02d %02d %02d %d\n",
|
||||
mIndexMin,
|
||||
mIndexMax,
|
||||
mIndexCur,
|
||||
mMuteCount,
|
||||
mCanBeMuted);
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <hardware_legacy/AudioPolicyInterface.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define MAX_DEVICE_ADDRESS_LEN 20
|
||||
#define NUM_TEST_OUTPUTS 5
|
||||
|
||||
class AudioPolicyManagerGeneric: public AudioPolicyInterface
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
, public Thread
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
{
|
||||
|
||||
public:
|
||||
AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface);
|
||||
virtual ~AudioPolicyManagerGeneric();
|
||||
|
||||
// AudioPolicyInterface
|
||||
virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
|
||||
AudioSystem::device_connection_state state,
|
||||
const char *device_address);
|
||||
virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
|
||||
const char *device_address);
|
||||
virtual void setPhoneState(int state);
|
||||
virtual void setRingerMode(uint32_t mode, uint32_t mask);
|
||||
virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
|
||||
virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
|
||||
virtual void setSystemProperty(const char* property, const char* value);
|
||||
virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
|
||||
uint32_t samplingRate,
|
||||
uint32_t format,
|
||||
uint32_t channels,
|
||||
AudioSystem::output_flags flags);
|
||||
virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
|
||||
virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
|
||||
virtual void releaseOutput(audio_io_handle_t output);
|
||||
virtual audio_io_handle_t getInput(int inputSource,
|
||||
uint32_t samplingRate,
|
||||
uint32_t format,
|
||||
uint32_t channels,
|
||||
AudioSystem::audio_in_acoustics acoustics);
|
||||
// indicates to the audio policy manager that the input starts being used.
|
||||
virtual status_t startInput(audio_io_handle_t input);
|
||||
// indicates to the audio policy manager that the input stops being used.
|
||||
virtual status_t stopInput(audio_io_handle_t input);
|
||||
virtual void releaseInput(audio_io_handle_t input);
|
||||
virtual void initStreamVolume(AudioSystem::stream_type stream,
|
||||
int indexMin,
|
||||
int indexMax);
|
||||
virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
|
||||
virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
|
||||
|
||||
virtual status_t dump(int fd);
|
||||
|
||||
private:
|
||||
|
||||
enum routing_strategy {
|
||||
STRATEGY_MEDIA,
|
||||
STRATEGY_PHONE,
|
||||
STRATEGY_SONIFICATION,
|
||||
STRATEGY_DTMF,
|
||||
NUM_STRATEGIES
|
||||
};
|
||||
|
||||
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
|
||||
// and keep track of the usage of this output by each audio stream type.
|
||||
class AudioOutputDescriptor
|
||||
{
|
||||
public:
|
||||
AudioOutputDescriptor();
|
||||
|
||||
status_t dump(int fd);
|
||||
|
||||
uint32_t device();
|
||||
void changeRefCount(AudioSystem::stream_type, int delta);
|
||||
bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; }
|
||||
uint32_t refCount();
|
||||
|
||||
uint32_t mSamplingRate; //
|
||||
uint32_t mFormat; //
|
||||
uint32_t mChannels; // output configuration
|
||||
uint32_t mLatency; //
|
||||
AudioSystem::output_flags mFlags; //
|
||||
uint32_t mDevice; // current device this output is routed to
|
||||
uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
|
||||
};
|
||||
|
||||
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
|
||||
// and keep track of the usage of this input.
|
||||
class AudioInputDescriptor
|
||||
{
|
||||
public:
|
||||
AudioInputDescriptor();
|
||||
|
||||
status_t dump(int fd);
|
||||
|
||||
uint32_t mSamplingRate; //
|
||||
uint32_t mFormat; // input configuration
|
||||
uint32_t mChannels; //
|
||||
AudioSystem::audio_in_acoustics mAcoustics; //
|
||||
uint32_t mDevice; // current device this input is routed to
|
||||
uint32_t mRefCount; // number of AudioRecord clients using this output
|
||||
};
|
||||
|
||||
// stream descriptor used for volume control
|
||||
class StreamDescriptor
|
||||
{
|
||||
public:
|
||||
StreamDescriptor()
|
||||
: mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {}
|
||||
|
||||
void dump(char* buffer, size_t size);
|
||||
|
||||
int mIndexMin; // min volume index
|
||||
int mIndexMax; // max volume index
|
||||
int mIndexCur; // current volume index
|
||||
int mMuteCount; // mute request counter
|
||||
bool mCanBeMuted; // true is the stream can be muted
|
||||
};
|
||||
|
||||
// return the strategy corresponding to a given stream type
|
||||
static routing_strategy getStrategy(AudioSystem::stream_type stream);
|
||||
// return the output handle of an output routed to the specified device, 0 if no output
|
||||
// is routed to the device
|
||||
float computeVolume(int stream, int index, uint32_t device);
|
||||
// Mute or unmute the stream on the specified output
|
||||
void setStreamMute(int stream, bool on, audio_io_handle_t output);
|
||||
// handle special cases for sonification strategy while in call: mute streams or replace by
|
||||
// a special tone in the device used for communication
|
||||
void handleIncallSonification(int stream, bool starting);
|
||||
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
virtual bool threadLoop();
|
||||
void exit();
|
||||
int testOutputIndex(audio_io_handle_t output);
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
|
||||
|
||||
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
|
||||
audio_io_handle_t mHardwareOutput; // hardware output handler
|
||||
|
||||
KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; // list ot output descritors
|
||||
KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors
|
||||
uint32_t mAvailableOutputDevices; // bit field of all available output devices
|
||||
uint32_t mAvailableInputDevices; // bit field of all available input devices
|
||||
int mPhoneState; // current phone state
|
||||
uint32_t mRingerMode; // current ringer mode
|
||||
AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
|
||||
|
||||
StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
|
||||
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
Mutex mLock;
|
||||
Condition mWaitWorkCV;
|
||||
|
||||
int mCurOutput;
|
||||
bool mDirectOutput;
|
||||
audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
|
||||
int mTestInput;
|
||||
uint32_t mTestDevice;
|
||||
uint32_t mTestSamplingRate;
|
||||
uint32_t mTestFormat;
|
||||
uint32_t mTestChannels;
|
||||
uint32_t mTestLatencyMs;
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
@@ -30,9 +30,10 @@
|
||||
#include <utils/String16.h>
|
||||
#include <utils/threads.h>
|
||||
#include "AudioPolicyService.h"
|
||||
#include "AudioPolicyManagerGeneric.h"
|
||||
#include <hardware_legacy/AudioPolicyManagerBase.h>
|
||||
#include <cutils/properties.h>
|
||||
#include <dlfcn.h>
|
||||
#include <hardware_legacy/power.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// the sim build doesn't have gettid
|
||||
@@ -43,8 +44,9 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* kDeadlockedString = "AudioPolicyService may be deadlocked\n";
|
||||
static const char* kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n";
|
||||
|
||||
static const char *kDeadlockedString = "AudioPolicyService may be deadlocked\n";
|
||||
static const char *kCmdDeadlockedString = "AudioPolicyService command thread may be deadlocked\n";
|
||||
|
||||
static const int kDumpLockRetries = 50;
|
||||
static const int kDumpLockSleep = 20000;
|
||||
@@ -67,18 +69,18 @@ AudioPolicyService::AudioPolicyService()
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
|
||||
// start tone playback thread
|
||||
mTonePlaybackThread = new AudioCommandThread();
|
||||
mTonePlaybackThread = new AudioCommandThread(String8(""));
|
||||
// start audio commands thread
|
||||
mAudioCommandThread = new AudioCommandThread();
|
||||
mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));
|
||||
|
||||
#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
|
||||
mpPolicyManager = new AudioPolicyManagerGeneric(this);
|
||||
mpPolicyManager = new AudioPolicyManagerBase(this);
|
||||
LOGV("build for GENERIC_AUDIO - using generic audio policy");
|
||||
#else
|
||||
// if running in emulation - use the emulator driver
|
||||
if (property_get("ro.kernel.qemu", value, 0)) {
|
||||
LOGV("Running in emulation - using generic audio policy");
|
||||
mpPolicyManager = new AudioPolicyManagerGeneric(this);
|
||||
mpPolicyManager = new AudioPolicyManagerBase(this);
|
||||
}
|
||||
else {
|
||||
LOGV("Using hardware specific audio policy");
|
||||
@@ -556,8 +558,8 @@ status_t AudioPolicyService::setVoiceVolume(float volume, int delayMs)
|
||||
|
||||
// ----------- AudioPolicyService::AudioCommandThread implementation ----------
|
||||
|
||||
AudioPolicyService::AudioCommandThread::AudioCommandThread()
|
||||
: Thread(false)
|
||||
AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name)
|
||||
: Thread(false), mName(name)
|
||||
{
|
||||
mpToneGenerator = NULL;
|
||||
}
|
||||
@@ -565,18 +567,20 @@ AudioPolicyService::AudioCommandThread::AudioCommandThread()
|
||||
|
||||
AudioPolicyService::AudioCommandThread::~AudioCommandThread()
|
||||
{
|
||||
if (mName != "" && !mAudioCommands.isEmpty()) {
|
||||
release_wake_lock(mName.string());
|
||||
}
|
||||
mAudioCommands.clear();
|
||||
if (mpToneGenerator != NULL) delete mpToneGenerator;
|
||||
}
|
||||
|
||||
void AudioPolicyService::AudioCommandThread::onFirstRef()
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
|
||||
snprintf(buffer, SIZE, "AudioCommandThread");
|
||||
|
||||
run(buffer, ANDROID_PRIORITY_AUDIO);
|
||||
if (mName != "") {
|
||||
run(mName.string(), ANDROID_PRIORITY_AUDIO);
|
||||
} else {
|
||||
run("AudioCommandThread", ANDROID_PRIORITY_AUDIO);
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioPolicyService::AudioCommandThread::threadLoop()
|
||||
@@ -657,6 +661,10 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release delayed commands wake lock
|
||||
if (mName != "" && mAudioCommands.isEmpty()) {
|
||||
release_wake_lock(mName.string());
|
||||
}
|
||||
LOGV("AudioCommandThread() going to sleep");
|
||||
mWaitWorkCV.waitRelative(mLock, waitTime);
|
||||
LOGV("AudioCommandThread() waking up");
|
||||
@@ -815,6 +823,11 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
|
||||
|
||||
command->mTime = systemTime() + milliseconds(delayMs);
|
||||
|
||||
// acquire wake lock to make sure delayed commands are processed
|
||||
if (mName != "" && mAudioCommands.isEmpty()) {
|
||||
acquire_wake_lock(PARTIAL_WAKE_LOCK, mName.string());
|
||||
}
|
||||
|
||||
// check same pending commands with later time stamps and eliminate them
|
||||
for (i = mAudioCommands.size()-1; i >= 0; i--) {
|
||||
AudioCommand *command2 = mAudioCommands[i];
|
||||
@@ -883,7 +896,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
|
||||
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());
|
||||
LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size());
|
||||
mAudioCommands.insertAt(command, i + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ private:
|
||||
SET_VOICE_VOLUME
|
||||
};
|
||||
|
||||
AudioCommandThread ();
|
||||
AudioCommandThread (String8 name);
|
||||
virtual ~AudioCommandThread();
|
||||
|
||||
status_t dump(int fd);
|
||||
@@ -195,7 +195,8 @@ private:
|
||||
Condition mWaitWorkCV;
|
||||
Vector <AudioCommand *> mAudioCommands; // list of pending commands
|
||||
ToneGenerator *mpToneGenerator; // the tone generator
|
||||
AudioCommand mLastCommand;
|
||||
AudioCommand mLastCommand; // last processed command (used by dump)
|
||||
String8 mName; // string used by wake lock fo delayed commands
|
||||
};
|
||||
|
||||
// Internal dump utilities.
|
||||
|
||||
Reference in New Issue
Block a user