am 22a2d718: Merge "Audio policy manager changes for audio effects" into gingerbread
Merge commit '22a2d7186d015efcd648dff99500f8467463be82' into gingerbread-plus-aosp * commit '22a2d7186d015efcd648dff99500f8467463be82': Audio policy manager changes for audio effects
This commit is contained in:
@@ -168,6 +168,15 @@ public:
|
||||
TX_DISABLE = 0
|
||||
};
|
||||
|
||||
// special audio session values
|
||||
enum audio_sessions {
|
||||
SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream
|
||||
// (value must be less than 0)
|
||||
SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can
|
||||
// be moved by audio policy manager to another output stream
|
||||
// (value must be 0)
|
||||
};
|
||||
|
||||
/* These are static methods to control the system-wide AudioFlinger
|
||||
* only privileged processes can have access to them
|
||||
*/
|
||||
@@ -353,8 +362,12 @@ public:
|
||||
uint32_t format = FORMAT_DEFAULT,
|
||||
uint32_t channels = CHANNEL_OUT_STEREO,
|
||||
output_flags flags = OUTPUT_FLAG_INDIRECT);
|
||||
static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
|
||||
static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
|
||||
static status_t startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
static status_t stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
static void releaseOutput(audio_io_handle_t output);
|
||||
static audio_io_handle_t getInput(int inputSource,
|
||||
uint32_t samplingRate = 0,
|
||||
@@ -370,6 +383,16 @@ public:
|
||||
static status_t setStreamVolumeIndex(stream_type stream, int index);
|
||||
static status_t getStreamVolumeIndex(stream_type stream, int *index);
|
||||
|
||||
static uint32_t getStrategyForStream(stream_type stream);
|
||||
|
||||
static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
|
||||
static status_t registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id);
|
||||
static status_t unregisterEffect(int id);
|
||||
|
||||
static const sp<IAudioPolicyService>& get_audio_policy_service();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -161,6 +161,8 @@ public:
|
||||
status_t *status,
|
||||
int *id,
|
||||
int *enabled) = 0;
|
||||
|
||||
virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -53,8 +53,12 @@ public:
|
||||
uint32_t format = AudioSystem::FORMAT_DEFAULT,
|
||||
uint32_t channels = 0,
|
||||
AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
|
||||
virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
|
||||
virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
|
||||
virtual status_t startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0) = 0;
|
||||
virtual status_t stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0) = 0;
|
||||
virtual void releaseOutput(audio_io_handle_t output) = 0;
|
||||
virtual audio_io_handle_t getInput(int inputSource,
|
||||
uint32_t samplingRate = 0,
|
||||
@@ -69,6 +73,14 @@ public:
|
||||
int indexMax) = 0;
|
||||
virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0;
|
||||
virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0;
|
||||
virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
|
||||
virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0;
|
||||
virtual status_t registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id) = 0;
|
||||
virtual status_t unregisterEffect(int id) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ static list_elem_t *gCurLib; // current library in enumeration process
|
||||
static list_elem_t *gCurEffect; // current effect in enumeration process
|
||||
static uint32_t gCurEffectIdx; // current effect index in enumeration process
|
||||
|
||||
static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
|
||||
const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
|
||||
static int gInitDone; // true is global initialization has been preformed
|
||||
static int gNextLibId; // used by loadLibrary() to allocate unique library handles
|
||||
static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define LOG_TAG "Bundle"
|
||||
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
|
||||
#define LVM_BUNDLE // Include all the bundle code
|
||||
#define LOG_NDEBUG 0
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -590,18 +590,22 @@ audio_io_handle_t AudioSystem::getOutput(stream_type stream,
|
||||
return output;
|
||||
}
|
||||
|
||||
status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioSystem::startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return PERMISSION_DENIED;
|
||||
return aps->startOutput(output, stream);
|
||||
return aps->startOutput(output, stream, session);
|
||||
}
|
||||
|
||||
status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioSystem::stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return PERMISSION_DENIED;
|
||||
return aps->stopOutput(output, stream);
|
||||
return aps->stopOutput(output, stream, session);
|
||||
}
|
||||
|
||||
void AudioSystem::releaseOutput(audio_io_handle_t output)
|
||||
@@ -666,6 +670,38 @@ status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index)
|
||||
return aps->getStreamVolumeIndex(stream, index);
|
||||
}
|
||||
|
||||
uint32_t AudioSystem::getStrategyForStream(AudioSystem::stream_type stream)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return 0;
|
||||
return aps->getStrategyForStream(stream);
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return PERMISSION_DENIED;
|
||||
return aps->getOutputForEffect(desc);
|
||||
}
|
||||
|
||||
status_t AudioSystem::registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return PERMISSION_DENIED;
|
||||
return aps->registerEffect(desc, output, strategy, session, id);
|
||||
}
|
||||
|
||||
status_t AudioSystem::unregisterEffect(int id)
|
||||
{
|
||||
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
|
||||
if (aps == 0) return PERMISSION_DENIED;
|
||||
return aps->unregisterEffect(id);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
|
||||
|
||||
@@ -69,7 +69,8 @@ enum {
|
||||
QUERY_NUM_EFFECTS,
|
||||
QUERY_EFFECT,
|
||||
GET_EFFECT_DESCRIPTOR,
|
||||
CREATE_EFFECT
|
||||
CREATE_EFFECT,
|
||||
MOVE_EFFECTS
|
||||
};
|
||||
|
||||
class BpAudioFlinger : public BpInterface<IAudioFlinger>
|
||||
@@ -676,6 +677,17 @@ public:
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
virtual status_t moveEffects(int session, int srcOutput, int dstOutput)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
|
||||
data.writeInt32(session);
|
||||
data.writeInt32(srcOutput);
|
||||
data.writeInt32(dstOutput);
|
||||
remote()->transact(MOVE_EFFECTS, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
|
||||
@@ -1024,6 +1036,14 @@ status_t BnAudioFlinger::onTransact(
|
||||
reply->write(&desc, sizeof(effect_descriptor_t));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case MOVE_EFFECTS: {
|
||||
CHECK_INTERFACE(IAudioFlinger, data, reply);
|
||||
int session = data.readInt32();
|
||||
int srcOutput = data.readInt32();
|
||||
int dstOutput = data.readInt32();
|
||||
reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,11 @@ enum {
|
||||
RELEASE_INPUT,
|
||||
INIT_STREAM_VOLUME,
|
||||
SET_STREAM_VOLUME,
|
||||
GET_STREAM_VOLUME
|
||||
GET_STREAM_VOLUME,
|
||||
GET_STRATEGY_FOR_STREAM,
|
||||
GET_OUTPUT_FOR_EFFECT,
|
||||
REGISTER_EFFECT,
|
||||
UNREGISTER_EFFECT
|
||||
};
|
||||
|
||||
class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
|
||||
@@ -137,22 +141,28 @@ public:
|
||||
return static_cast <audio_io_handle_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
virtual status_t startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.writeInt32(output);
|
||||
data.writeInt32(stream);
|
||||
data.writeInt32(session);
|
||||
remote()->transact(START_OUTPUT, data, &reply);
|
||||
return static_cast <status_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
virtual status_t stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.writeInt32(output);
|
||||
data.writeInt32(stream);
|
||||
data.writeInt32(session);
|
||||
remote()->transact(STOP_OUTPUT, data, &reply);
|
||||
return static_cast <status_t> (reply.readInt32());
|
||||
}
|
||||
@@ -242,6 +252,51 @@ public:
|
||||
if (index) *index = lIndex;
|
||||
return static_cast <status_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.writeInt32(static_cast <uint32_t>(stream));
|
||||
remote()->transact(GET_STRATEGY_FOR_STREAM, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.write(desc, sizeof(effect_descriptor_t));
|
||||
remote()->transact(GET_OUTPUT_FOR_EFFECT, data, &reply);
|
||||
return static_cast <audio_io_handle_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
virtual status_t registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.write(desc, sizeof(effect_descriptor_t));
|
||||
data.writeInt32(output);
|
||||
data.writeInt32(strategy);
|
||||
data.writeInt32(session);
|
||||
data.writeInt32(id);
|
||||
remote()->transact(REGISTER_EFFECT, data, &reply);
|
||||
return static_cast <status_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
virtual status_t unregisterEffect(int id)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
|
||||
data.writeInt32(id);
|
||||
remote()->transact(UNREGISTER_EFFECT, data, &reply);
|
||||
return static_cast <status_t> (reply.readInt32());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
|
||||
@@ -255,18 +310,24 @@ status_t BnAudioPolicyService::onTransact(
|
||||
switch(code) {
|
||||
case SET_DEVICE_CONNECTION_STATE: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
|
||||
AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32());
|
||||
AudioSystem::audio_devices device =
|
||||
static_cast <AudioSystem::audio_devices>(data.readInt32());
|
||||
AudioSystem::device_connection_state state =
|
||||
static_cast <AudioSystem::device_connection_state>(data.readInt32());
|
||||
const char *device_address = data.readCString();
|
||||
reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));
|
||||
reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,
|
||||
state,
|
||||
device_address)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
case GET_DEVICE_CONNECTION_STATE: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
|
||||
AudioSystem::audio_devices device =
|
||||
static_cast<AudioSystem::audio_devices> (data.readInt32());
|
||||
const char *device_address = data.readCString();
|
||||
reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address)));
|
||||
reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device,
|
||||
device_address)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
@@ -287,7 +348,8 @@ status_t BnAudioPolicyService::onTransact(
|
||||
case SET_FORCE_USE: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
|
||||
AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32());
|
||||
AudioSystem::forced_config config =
|
||||
static_cast <AudioSystem::forced_config>(data.readInt32());
|
||||
reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
@@ -301,11 +363,13 @@ status_t BnAudioPolicyService::onTransact(
|
||||
|
||||
case GET_OUTPUT: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
AudioSystem::stream_type stream =
|
||||
static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
uint32_t samplingRate = data.readInt32();
|
||||
uint32_t format = data.readInt32();
|
||||
uint32_t channels = data.readInt32();
|
||||
AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32());
|
||||
AudioSystem::output_flags flags =
|
||||
static_cast <AudioSystem::output_flags>(data.readInt32());
|
||||
|
||||
audio_io_handle_t output = getOutput(stream,
|
||||
samplingRate,
|
||||
@@ -320,7 +384,10 @@ status_t BnAudioPolicyService::onTransact(
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
|
||||
uint32_t stream = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
|
||||
int session = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(startOutput(output,
|
||||
(AudioSystem::stream_type)stream,
|
||||
session)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
@@ -328,7 +395,10 @@ status_t BnAudioPolicyService::onTransact(
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
|
||||
uint32_t stream = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
|
||||
int session = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(stopOutput(output,
|
||||
(AudioSystem::stream_type)stream,
|
||||
session)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
@@ -345,7 +415,8 @@ status_t BnAudioPolicyService::onTransact(
|
||||
uint32_t samplingRate = data.readInt32();
|
||||
uint32_t format = data.readInt32();
|
||||
uint32_t channels = data.readInt32();
|
||||
AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
|
||||
AudioSystem::audio_in_acoustics acoustics =
|
||||
static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
|
||||
audio_io_handle_t input = getInput(inputSource,
|
||||
samplingRate,
|
||||
format,
|
||||
@@ -378,7 +449,8 @@ status_t BnAudioPolicyService::onTransact(
|
||||
|
||||
case INIT_STREAM_VOLUME: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
AudioSystem::stream_type stream =
|
||||
static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
int indexMin = data.readInt32();
|
||||
int indexMax = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax)));
|
||||
@@ -387,7 +459,8 @@ status_t BnAudioPolicyService::onTransact(
|
||||
|
||||
case SET_STREAM_VOLUME: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
AudioSystem::stream_type stream =
|
||||
static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
int index = data.readInt32();
|
||||
reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index)));
|
||||
return NO_ERROR;
|
||||
@@ -395,7 +468,8 @@ status_t BnAudioPolicyService::onTransact(
|
||||
|
||||
case GET_STREAM_VOLUME: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
AudioSystem::stream_type stream =
|
||||
static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
int index;
|
||||
status_t status = getStreamVolumeIndex(stream, &index);
|
||||
reply->writeInt32(index);
|
||||
@@ -403,6 +477,46 @@ status_t BnAudioPolicyService::onTransact(
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
case GET_STRATEGY_FOR_STREAM: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
AudioSystem::stream_type stream =
|
||||
static_cast <AudioSystem::stream_type>(data.readInt32());
|
||||
reply->writeInt32(getStrategyForStream(stream));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
case GET_OUTPUT_FOR_EFFECT: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
effect_descriptor_t desc;
|
||||
data.read(&desc, sizeof(effect_descriptor_t));
|
||||
audio_io_handle_t output = getOutputForEffect(&desc);
|
||||
reply->writeInt32(static_cast <int>(output));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
case REGISTER_EFFECT: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
effect_descriptor_t desc;
|
||||
data.read(&desc, sizeof(effect_descriptor_t));
|
||||
audio_io_handle_t output = data.readInt32();
|
||||
uint32_t strategy = data.readInt32();
|
||||
int session = data.readInt32();
|
||||
int id = data.readInt32();
|
||||
reply->writeInt32(static_cast <int32_t>(registerEffect(&desc,
|
||||
output,
|
||||
strategy,
|
||||
session,
|
||||
id)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
case UNREGISTER_EFFECT: {
|
||||
CHECK_INTERFACE(IAudioPolicyService, data, reply);
|
||||
int id = data.readInt32();
|
||||
reply->writeInt32(static_cast <int32_t>(unregisterEffect(id)));
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char * const gEffectLibPath;
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n";
|
||||
@@ -127,8 +129,7 @@ static bool settingsAllowed() {
|
||||
|
||||
AudioFlinger::AudioFlinger()
|
||||
: BnAudioFlinger(),
|
||||
mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
|
||||
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
|
||||
mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
|
||||
{
|
||||
mHardwareStatus = AUDIO_HW_IDLE;
|
||||
|
||||
@@ -321,13 +322,19 @@ sp<IAudioTrack> AudioFlinger::createTrack(
|
||||
mClients.add(pid, client);
|
||||
}
|
||||
|
||||
// If no audio session id is provided, create one here
|
||||
// TODO: enforce same stream type for all tracks in same audio session?
|
||||
// TODO: prevent same audio session on different output threads
|
||||
LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
|
||||
if (sessionId != NULL && *sessionId != 0) {
|
||||
if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
|
||||
// prevent same audio session on different output threads
|
||||
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
||||
if (mPlaybackThreads.keyAt(i) != output &&
|
||||
mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) {
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
lSessionId = *sessionId;
|
||||
} else {
|
||||
// if no audio session id is provided, create one here
|
||||
lSessionId = nextUniqueId();
|
||||
if (sessionId != NULL) {
|
||||
*sessionId = lSessionId;
|
||||
@@ -1141,6 +1148,23 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra
|
||||
|
||||
{ // scope for mLock
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
// all tracks in same audio session must share the same routing strategy otherwise
|
||||
// conflicts will happen when tracks are moved from one output to another by audio policy
|
||||
// manager
|
||||
uint32_t strategy =
|
||||
AudioSystem::getStrategyForStream((AudioSystem::stream_type)streamType);
|
||||
for (size_t i = 0; i < mTracks.size(); ++i) {
|
||||
sp<Track> t = mTracks[i];
|
||||
if (t != 0) {
|
||||
if (sessionId == t->sessionId() &&
|
||||
strategy != AudioSystem::getStrategyForStream((AudioSystem::stream_type)t->type())) {
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
track = new Track(this, client, streamType, sampleRate, format,
|
||||
channelCount, frameCount, sharedBuffer, sessionId);
|
||||
if (track->getCblk() == NULL || track->name() < 0) {
|
||||
@@ -1153,6 +1177,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra
|
||||
if (chain != 0) {
|
||||
LOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
|
||||
track->setMainBuffer(chain->inBuffer());
|
||||
chain->setStrategy(AudioSystem::getStrategyForStream((AudioSystem::stream_type)track->type()));
|
||||
}
|
||||
}
|
||||
lStatus = NO_ERROR;
|
||||
@@ -1344,7 +1369,16 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
|
||||
mMixBuffer = new int16_t[mFrameCount * 2];
|
||||
memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
|
||||
|
||||
//TODO handle effects reconfig
|
||||
// force reconfiguration of effect chains and engines to take new buffer size and audio
|
||||
// parameters into account
|
||||
// Note that mLock is not held when readOutputParameters() is called from the constructor
|
||||
// but in this case nothing is done below as no audio sessions have effect yet so it doesn't
|
||||
// matter.
|
||||
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
|
||||
Vector< sp<EffectChain> > effectChains = mEffectChains;
|
||||
for (size_t i = 0; i < effectChains.size(); i ++) {
|
||||
mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this);
|
||||
}
|
||||
}
|
||||
|
||||
status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
|
||||
@@ -1369,7 +1403,8 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
|
||||
|
||||
for (size_t i = 0; i < mTracks.size(); ++i) {
|
||||
sp<Track> track = mTracks[i];
|
||||
if (sessionId == track->sessionId()) {
|
||||
if (sessionId == track->sessionId() &&
|
||||
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1377,6 +1412,23 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
|
||||
{
|
||||
// session AudioSystem::SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that
|
||||
// it is moved to correct output by audio policy manager when A2DP is connected or disconnected
|
||||
if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
|
||||
return AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
|
||||
}
|
||||
for (size_t i = 0; i < mTracks.size(); i++) {
|
||||
sp<Track> track = mTracks[i];
|
||||
if (sessionId == track->sessionId() &&
|
||||
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
|
||||
return AudioSystem::getStrategyForStream((AudioSystem::stream_type) track->type());
|
||||
}
|
||||
}
|
||||
return AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
|
||||
}
|
||||
|
||||
sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
@@ -1503,8 +1555,7 @@ bool AudioFlinger::MixerThread::threadLoop()
|
||||
// prevent any changes in effect chain list and in each effect chain
|
||||
// during mixing and effect process as the audio buffers could be deleted
|
||||
// or modified if an effect is created or deleted
|
||||
lockEffectChains_l();
|
||||
effectChains = mEffectChains;
|
||||
lockEffectChains_l(effectChains);
|
||||
}
|
||||
|
||||
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
|
||||
@@ -1540,7 +1591,7 @@ bool AudioFlinger::MixerThread::threadLoop()
|
||||
effectChains[i]->process_l();
|
||||
}
|
||||
// enable changes in effect chain
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
#ifdef LVMX
|
||||
int audioOutputType = LifeVibes::getMixerType(mId, mType);
|
||||
if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
|
||||
@@ -1571,7 +1622,7 @@ bool AudioFlinger::MixerThread::threadLoop()
|
||||
mStandby = false;
|
||||
} else {
|
||||
// enable changes in effect chain
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
usleep(sleepTime);
|
||||
}
|
||||
|
||||
@@ -1625,7 +1676,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
|
||||
}
|
||||
#endif
|
||||
// Delegate master volume control to effect in output mix effect chain if needed
|
||||
sp<EffectChain> chain = getEffectChain_l(0);
|
||||
sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
|
||||
if (chain != 0) {
|
||||
uint32_t v = (uint32_t)(masterVolume * (1 << 24));
|
||||
chain->setVolume_l(&v, &v);
|
||||
@@ -1814,8 +1865,10 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
|
||||
|
||||
void AudioFlinger::MixerThread::invalidateTracks(int streamType)
|
||||
{
|
||||
LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size());
|
||||
LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d",
|
||||
this, streamType, mTracks.size());
|
||||
Mutex::Autolock _l(mLock);
|
||||
|
||||
size_t size = mTracks.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
sp<Track> t = mTracks[i];
|
||||
@@ -2070,7 +2123,6 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
|
||||
// hardware resources as soon as possible
|
||||
nsecs_t standbyDelay = microseconds(activeSleepTime*2);
|
||||
|
||||
|
||||
while (!exitPending())
|
||||
{
|
||||
bool rampVolume;
|
||||
@@ -2246,7 +2298,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
|
||||
if (UNLIKELY(trackToRemove != 0)) {
|
||||
mActiveTracks.remove(trackToRemove);
|
||||
if (!effectChains.isEmpty()) {
|
||||
LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId());
|
||||
LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
|
||||
trackToRemove->sessionId());
|
||||
effectChains[0]->stopTrack();
|
||||
}
|
||||
if (trackToRemove->isTerminated()) {
|
||||
@@ -2255,7 +2308,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
|
||||
}
|
||||
}
|
||||
|
||||
lockEffectChains_l();
|
||||
lockEffectChains_l(effectChains);
|
||||
}
|
||||
|
||||
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
|
||||
@@ -2301,7 +2354,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
|
||||
for (size_t i = 0; i < effectChains.size(); i ++) {
|
||||
effectChains[i]->process_l();
|
||||
}
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
|
||||
mLastWriteTime = systemTime();
|
||||
mInWrite = true;
|
||||
@@ -2312,7 +2365,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
|
||||
mInWrite = false;
|
||||
mStandby = false;
|
||||
} else {
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
usleep(sleepTime);
|
||||
}
|
||||
|
||||
@@ -2505,8 +2558,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
|
||||
// prevent any changes in effect chain list and in each effect chain
|
||||
// during mixing and effect process as the audio buffers could be deleted
|
||||
// or modified if an effect is created or deleted
|
||||
lockEffectChains_l();
|
||||
effectChains = mEffectChains;
|
||||
lockEffectChains_l(effectChains);
|
||||
}
|
||||
|
||||
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
|
||||
@@ -2547,7 +2599,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
|
||||
effectChains[i]->process_l();
|
||||
}
|
||||
// enable changes in effect chain
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
|
||||
standbyTime = systemTime() + kStandbyTimeInNsecs;
|
||||
for (size_t i = 0; i < outputTracks.size(); i++) {
|
||||
@@ -2557,7 +2609,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
|
||||
mBytesWritten += mixBufferSize;
|
||||
} else {
|
||||
// enable changes in effect chain
|
||||
unlockEffectChains();
|
||||
unlockEffectChains(effectChains);
|
||||
usleep(sleepTime);
|
||||
}
|
||||
|
||||
@@ -2859,7 +2911,9 @@ void AudioFlinger::PlaybackThread::Track::destroy()
|
||||
if (thread != 0) {
|
||||
if (!isOutputTrack()) {
|
||||
if (mState == ACTIVE || mState == RESUMING) {
|
||||
AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
|
||||
AudioSystem::stopOutput(thread->id(),
|
||||
(AudioSystem::stream_type)mStreamType,
|
||||
mSessionId);
|
||||
}
|
||||
AudioSystem::releaseOutput(thread->id());
|
||||
}
|
||||
@@ -2966,7 +3020,9 @@ status_t AudioFlinger::PlaybackThread::Track::start()
|
||||
|
||||
if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
|
||||
thread->mLock.unlock();
|
||||
status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
|
||||
status = AudioSystem::startOutput(thread->id(),
|
||||
(AudioSystem::stream_type)mStreamType,
|
||||
mSessionId);
|
||||
thread->mLock.lock();
|
||||
}
|
||||
if (status == NO_ERROR) {
|
||||
@@ -2999,7 +3055,9 @@ void AudioFlinger::PlaybackThread::Track::stop()
|
||||
}
|
||||
if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
|
||||
thread->mLock.unlock();
|
||||
AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
|
||||
AudioSystem::stopOutput(thread->id(),
|
||||
(AudioSystem::stream_type)mStreamType,
|
||||
mSessionId);
|
||||
thread->mLock.lock();
|
||||
}
|
||||
}
|
||||
@@ -3016,7 +3074,9 @@ void AudioFlinger::PlaybackThread::Track::pause()
|
||||
LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
|
||||
if (!isOutputTrack()) {
|
||||
thread->mLock.unlock();
|
||||
AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
|
||||
AudioSystem::stopOutput(thread->id(),
|
||||
(AudioSystem::stream_type)mStreamType,
|
||||
mSessionId);
|
||||
thread->mLock.lock();
|
||||
}
|
||||
}
|
||||
@@ -3585,7 +3645,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
|
||||
}
|
||||
|
||||
// If no audio session id is provided, create one here
|
||||
if (sessionId != NULL && *sessionId != 0) {
|
||||
if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
|
||||
lSessionId = *sessionId;
|
||||
} else {
|
||||
lSessionId = nextUniqueId();
|
||||
@@ -4416,8 +4476,8 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
|
||||
thread->type() != PlaybackThread::DIRECT) {
|
||||
MixerThread *srcThread = (MixerThread *)thread;
|
||||
srcThread->invalidateTracks(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -4472,12 +4532,26 @@ int AudioFlinger::nextUniqueId()
|
||||
|
||||
status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle)
|
||||
{
|
||||
// check calling permissions
|
||||
if (!settingsAllowed()) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
// only allow libraries loaded from /system/lib/soundfx for now
|
||||
if (strncmp(gEffectLibPath, libPath, strlen(gEffectLibPath)) != 0) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
return EffectLoadLibrary(libPath, handle);
|
||||
}
|
||||
|
||||
status_t AudioFlinger::unloadEffectLibrary(int handle)
|
||||
{
|
||||
// check calling permissions
|
||||
if (!settingsAllowed()) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
return EffectUnloadLibrary(handle);
|
||||
}
|
||||
@@ -4522,7 +4596,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
sp<Client> client;
|
||||
wp<Client> wclient;
|
||||
|
||||
LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", pid, effectClient.get(), priority, sessionId, output);
|
||||
LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d",
|
||||
pid, effectClient.get(), priority, sessionId, output);
|
||||
|
||||
if (pDesc == NULL) {
|
||||
lStatus = BAD_VALUE;
|
||||
@@ -4577,7 +4652,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
// an auxiliary version of this effect type is available
|
||||
found = true;
|
||||
memcpy(&d, &desc, sizeof(effect_descriptor_t));
|
||||
if (sessionId != 0 ||
|
||||
if (sessionId != AudioSystem::SESSION_OUTPUT_MIX ||
|
||||
(desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
break;
|
||||
}
|
||||
@@ -4590,22 +4665,23 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
}
|
||||
// For same effect type, chose auxiliary version over insert version if
|
||||
// connect to output mix (Compliance to OpenSL ES)
|
||||
if (sessionId == 0 &&
|
||||
if (sessionId == AudioSystem::SESSION_OUTPUT_MIX &&
|
||||
(d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
memcpy(&desc, &d, sizeof(effect_descriptor_t));
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow auxiliary effects on a session different from 0 (output mix)
|
||||
if (sessionId != 0 &&
|
||||
if (sessionId != AudioSystem::SESSION_OUTPUT_MIX &&
|
||||
(desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
lStatus = INVALID_OPERATION;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Session -1 is reserved for output stage effects that can only be created
|
||||
// by audio policy manager (running in same process)
|
||||
if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) {
|
||||
// Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
|
||||
// that can only be created by audio policy manager (running in same process)
|
||||
if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE &&
|
||||
getpid() != IPCThreadState::self()->getCallingPid()) {
|
||||
lStatus = INVALID_OPERATION;
|
||||
goto Exit;
|
||||
}
|
||||
@@ -4617,13 +4693,14 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
// output threads.
|
||||
// TODO: allow attachment of effect to inputs
|
||||
if (output == 0) {
|
||||
if (sessionId <= 0) {
|
||||
// default to first output
|
||||
// TODO: define criteria to choose output when not specified. Or
|
||||
// receive output from audio policy manager
|
||||
if (mPlaybackThreads.size() != 0) {
|
||||
output = mPlaybackThreads.keyAt(0);
|
||||
}
|
||||
if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
|
||||
// output must be specified by AudioPolicyManager when using session
|
||||
// AudioSystem::SESSION_OUTPUT_STAGE
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
} else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
|
||||
output = AudioSystem::getOutputForEffect(&desc);
|
||||
LOGV("createEffect() got output %d for effect %s", output, desc.name);
|
||||
} else {
|
||||
// look for the thread where the specified audio session is present
|
||||
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
|
||||
@@ -4636,7 +4713,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
}
|
||||
PlaybackThread *thread = checkPlaybackThread_l(output);
|
||||
if (thread == NULL) {
|
||||
LOGE("unknown output thread");
|
||||
LOGE("createEffect() unknown output thread");
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
@@ -4651,7 +4728,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
|
||||
}
|
||||
|
||||
// create effect on selected output trhead
|
||||
handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus);
|
||||
handle = thread->createEffect_l(client, effectClient, priority, sessionId,
|
||||
&desc, enabled, &lStatus);
|
||||
if (handle != 0 && id != NULL) {
|
||||
*id = handle->id();
|
||||
}
|
||||
@@ -4664,31 +4742,64 @@ Exit:
|
||||
return handle;
|
||||
}
|
||||
|
||||
status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) {
|
||||
if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) {
|
||||
LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
|
||||
desc->name, (float)desc->cpuLoad/10);
|
||||
return INVALID_OPERATION;
|
||||
status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
|
||||
{
|
||||
LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
|
||||
session, srcOutput, dstOutput);
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (srcOutput == dstOutput) {
|
||||
LOGW("moveEffects() same dst and src outputs %d", dstOutput);
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) {
|
||||
LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB",
|
||||
desc->name, desc->memoryUsage);
|
||||
return INVALID_OPERATION;
|
||||
PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput);
|
||||
if (srcThread == NULL) {
|
||||
LOGW("moveEffects() bad srcOutput %d", srcOutput);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
mTotalEffectsCpuLoad += desc->cpuLoad;
|
||||
mTotalEffectsMemory += desc->memoryUsage;
|
||||
LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d",
|
||||
desc->name, desc->cpuLoad, desc->memoryUsage);
|
||||
LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
|
||||
PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput);
|
||||
if (dstThread == NULL) {
|
||||
LOGW("moveEffects() bad dstOutput %d", dstOutput);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
Mutex::Autolock _dl(dstThread->mLock);
|
||||
Mutex::Autolock _sl(srcThread->mLock);
|
||||
moveEffectChain_l(session, srcThread, dstThread);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) {
|
||||
mTotalEffectsCpuLoad -= desc->cpuLoad;
|
||||
mTotalEffectsMemory -= desc->memoryUsage;
|
||||
LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d",
|
||||
desc->name, desc->cpuLoad, desc->memoryUsage);
|
||||
LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
|
||||
// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
|
||||
status_t AudioFlinger::moveEffectChain_l(int session,
|
||||
AudioFlinger::PlaybackThread *srcThread,
|
||||
AudioFlinger::PlaybackThread *dstThread)
|
||||
{
|
||||
LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
|
||||
session, srcThread, dstThread);
|
||||
|
||||
sp<EffectChain> chain = srcThread->getEffectChain_l(session);
|
||||
if (chain == 0) {
|
||||
LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p",
|
||||
session, srcThread);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// remove chain first. This is usefull only if reconfiguring effect chain on same output thread,
|
||||
// so that a new chain is created with correct parameters when first effect is added. This is
|
||||
// otherwise unecessary as removeEffect_l() will remove the chain when last effect is
|
||||
// removed.
|
||||
srcThread->removeEffectChain_l(chain);
|
||||
|
||||
// transfer all effects one by one so that new effect chain is created on new thread with
|
||||
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
|
||||
sp<EffectModule> effect = chain->getEffectFromId_l(0);
|
||||
while (effect != 0) {
|
||||
srcThread->removeEffect_l(effect);
|
||||
dstThread->addEffect_l(effect);
|
||||
effect = chain->getEffectFromId_l(0);
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
|
||||
@@ -4707,6 +4818,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
|
||||
status_t lStatus;
|
||||
sp<Track> track;
|
||||
sp<EffectChain> chain;
|
||||
bool chainCreated = false;
|
||||
bool effectCreated = false;
|
||||
bool effectRegistered = false;
|
||||
|
||||
@@ -4718,16 +4830,18 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
|
||||
|
||||
// Do not allow auxiliary effect on session other than 0
|
||||
if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
|
||||
sessionId != 0) {
|
||||
LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
|
||||
sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
|
||||
LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
|
||||
desc->name, sessionId);
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Do not allow effects with session ID 0 on direct output or duplicating threads
|
||||
// TODO: add rule for hw accelerated effects on direct outputs with non PCM format
|
||||
if (sessionId == 0 && mType != MIXER) {
|
||||
LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId);
|
||||
if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) {
|
||||
LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
|
||||
desc->name, sessionId);
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
@@ -4744,6 +4858,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
|
||||
LOGV("createEffect_l() new effect chain for session %d", sessionId);
|
||||
chain = new EffectChain(this, sessionId);
|
||||
addEffectChain_l(chain);
|
||||
chain->setStrategy(getStrategyForSession_l(sessionId));
|
||||
chainCreated = true;
|
||||
} else {
|
||||
effect = chain->getEffectFromDesc_l(desc);
|
||||
}
|
||||
@@ -4751,14 +4867,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
|
||||
LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
|
||||
|
||||
if (effect == 0) {
|
||||
int id = mAudioFlinger->nextUniqueId();
|
||||
// Check CPU and memory usage
|
||||
lStatus = mAudioFlinger->registerEffectResource_l(desc);
|
||||
lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
|
||||
if (lStatus != NO_ERROR) {
|
||||
goto Exit;
|
||||
}
|
||||
effectRegistered = true;
|
||||
// create a new effect module if none present in the chain
|
||||
effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId);
|
||||
effect = new EffectModule(this, chain, desc, id, sessionId);
|
||||
lStatus = effect->status();
|
||||
if (lStatus != NO_ERROR) {
|
||||
goto Exit;
|
||||
@@ -4782,14 +4899,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
|
||||
|
||||
Exit:
|
||||
if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (effectCreated) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (chain->removeEffect_l(effect) == 0) {
|
||||
removeEffectChain_l(chain);
|
||||
}
|
||||
chain->removeEffect_l(effect);
|
||||
}
|
||||
if (effectRegistered) {
|
||||
mAudioFlinger->unregisterEffectResource_l(desc);
|
||||
AudioSystem::unregisterEffect(effect->id());
|
||||
}
|
||||
if (chainCreated) {
|
||||
removeEffectChain_l(chain);
|
||||
}
|
||||
handle.clear();
|
||||
}
|
||||
@@ -4800,26 +4918,71 @@ Exit:
|
||||
return handle;
|
||||
}
|
||||
|
||||
void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect,
|
||||
const wp<EffectHandle>& handle) {
|
||||
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
|
||||
// PlaybackThread::mLock held
|
||||
status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect)
|
||||
{
|
||||
// check for existing effect chain with the requested audio session
|
||||
int sessionId = effect->sessionId();
|
||||
sp<EffectChain> chain = getEffectChain_l(sessionId);
|
||||
bool chainCreated = false;
|
||||
|
||||
if (chain == 0) {
|
||||
// create a new chain for this session
|
||||
LOGV("addEffect_l() new effect chain for session %d", sessionId);
|
||||
chain = new EffectChain(this, sessionId);
|
||||
addEffectChain_l(chain);
|
||||
chain->setStrategy(getStrategyForSession_l(sessionId));
|
||||
chainCreated = true;
|
||||
}
|
||||
LOGV("addEffect_l() %p chain %p effect %p", this, chain.get(), effect.get());
|
||||
|
||||
if (chain->getEffectFromId_l(effect->id()) != 0) {
|
||||
LOGW("addEffect_l() %p effect %s already present in chain %p",
|
||||
this, effect->desc().name, chain.get());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
status_t status = chain->addEffect_l(effect);
|
||||
if (status != NO_ERROR) {
|
||||
if (chainCreated) {
|
||||
removeEffectChain_l(chain);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
effect->setDevice(mDevice);
|
||||
effect->setMode(mAudioFlinger->getMode());
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) {
|
||||
|
||||
LOGV("removeEffect_l() %p effect %p", this, effect.get());
|
||||
effect_descriptor_t desc = effect->desc();
|
||||
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
detachAuxEffect_l(effect->id());
|
||||
}
|
||||
|
||||
sp<EffectChain> chain = effect->chain().promote();
|
||||
if (chain != 0) {
|
||||
// remove effect chain if removing last effect
|
||||
if (chain->removeEffect_l(effect) == 0) {
|
||||
removeEffectChain_l(chain);
|
||||
}
|
||||
} else {
|
||||
LOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get());
|
||||
}
|
||||
}
|
||||
|
||||
void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect,
|
||||
const wp<EffectHandle>& handle) {
|
||||
Mutex::Autolock _l(mLock);
|
||||
LOGV("disconnectEffect() %p effect %p", this, effect.get());
|
||||
// delete the effect module if removing last handle on it
|
||||
if (effect->removeHandle(handle) == 0) {
|
||||
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
detachAuxEffect_l(effect->id());
|
||||
}
|
||||
sp<EffectChain> chain = effect->chain().promote();
|
||||
if (chain != 0) {
|
||||
// remove effect chain if remove last effect
|
||||
if (chain->removeEffect_l(effect) == 0) {
|
||||
removeEffectChain_l(chain);
|
||||
}
|
||||
}
|
||||
mLock.unlock();
|
||||
mAudioFlinger->mLock.lock();
|
||||
mAudioFlinger->unregisterEffectResource_l(&desc);
|
||||
mAudioFlinger->mLock.unlock();
|
||||
removeEffect_l(effect);
|
||||
AudioSystem::unregisterEffect(effect->id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4863,13 +5026,16 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c
|
||||
|
||||
chain->setInBuffer(buffer, ownsBuffer);
|
||||
chain->setOutBuffer(mMixBuffer);
|
||||
// Effect chain for session -1 is inserted at end of effect chains list
|
||||
// in order to be processed last as it contains output stage effects
|
||||
// Effect chain for session 0 is inserted before session -1 to be processed
|
||||
// Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect
|
||||
// chains list in order to be processed last as it contains output stage effects
|
||||
// Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before
|
||||
// session AudioSystem::SESSION_OUTPUT_STAGE to be processed
|
||||
// after track specific effects and before output stage
|
||||
// Effect chain for session other than 0 is inserted at beginning of effect
|
||||
// chains list to be processed before output mix effects. Relative order between
|
||||
// sessions other than 0 is not important
|
||||
// It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and
|
||||
// that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX
|
||||
// Effect chain for other sessions are inserted at beginning of effect
|
||||
// chains list to be processed before output mix effects. Relative order between other
|
||||
// sessions is not important
|
||||
size_t size = mEffectChains.size();
|
||||
size_t i = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
@@ -4896,26 +5062,30 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>&
|
||||
track->setMainBuffer(mMixBuffer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mEffectChains.size();
|
||||
}
|
||||
|
||||
void AudioFlinger::PlaybackThread::lockEffectChains_l()
|
||||
void AudioFlinger::PlaybackThread::lockEffectChains_l(
|
||||
Vector<sp <AudioFlinger::EffectChain> >& effectChains)
|
||||
{
|
||||
effectChains = mEffectChains;
|
||||
for (size_t i = 0; i < mEffectChains.size(); i++) {
|
||||
mEffectChains[i]->lock();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioFlinger::PlaybackThread::unlockEffectChains()
|
||||
void AudioFlinger::PlaybackThread::unlockEffectChains(
|
||||
Vector<sp <AudioFlinger::EffectChain> >& effectChains)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
for (size_t i = 0; i < mEffectChains.size(); i++) {
|
||||
mEffectChains[i]->unlock();
|
||||
for (size_t i = 0; i < effectChains.size(); i++) {
|
||||
effectChains[i]->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
|
||||
{
|
||||
sp<EffectModule> effect;
|
||||
@@ -4927,21 +5097,23 @@ sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int ses
|
||||
return effect;
|
||||
}
|
||||
|
||||
status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
|
||||
status_t AudioFlinger::PlaybackThread::attachAuxEffect(
|
||||
const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
return attachAuxEffect_l(track, EffectId);
|
||||
}
|
||||
|
||||
status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
|
||||
status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(
|
||||
const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
|
||||
{
|
||||
status_t status = NO_ERROR;
|
||||
|
||||
if (EffectId == 0) {
|
||||
track->setAuxBuffer(0, NULL);
|
||||
} else {
|
||||
// Auxiliary effects are always in audio session 0
|
||||
sp<EffectModule> effect = getEffect_l(0, EffectId);
|
||||
// Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX
|
||||
sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId);
|
||||
if (effect != 0) {
|
||||
if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer());
|
||||
@@ -5137,7 +5309,7 @@ void AudioFlinger::EffectModule::process()
|
||||
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
|
||||
mConfig.inputCfg.buffer.s32,
|
||||
mConfig.inputCfg.buffer.frameCount);
|
||||
mConfig.inputCfg.buffer.frameCount/2);
|
||||
}
|
||||
|
||||
// do the actual processing in the effect engine
|
||||
@@ -5214,7 +5386,8 @@ status_t AudioFlinger::EffectModule::configure()
|
||||
mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
|
||||
mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
|
||||
// Insert effect:
|
||||
// - in session 0 or -1, always overwrites output buffer: input buffer == output buffer
|
||||
// - in session AudioSystem::SESSION_OUTPUT_MIX or AudioSystem::SESSION_OUTPUT_STAGE,
|
||||
// always overwrites output buffer: input buffer == output buffer
|
||||
// - in other sessions:
|
||||
// last effect in the chain accumulates in output buffer: input buffer != output buffer
|
||||
// other effect: overwrites output buffer: input buffer == output buffer
|
||||
@@ -5231,6 +5404,9 @@ status_t AudioFlinger::EffectModule::configure()
|
||||
mConfig.inputCfg.buffer.frameCount = thread->frameCount();
|
||||
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
|
||||
|
||||
LOGV("configure() %p thread %p buffer %p framecount %d",
|
||||
this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
|
||||
|
||||
status_t cmdStatus;
|
||||
int size = sizeof(int);
|
||||
status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus);
|
||||
@@ -5753,7 +5929,7 @@ AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
|
||||
mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0),
|
||||
mNewLeftVolume(0), mNewRightVolume(0)
|
||||
{
|
||||
|
||||
mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC);
|
||||
}
|
||||
|
||||
AudioFlinger::EffectChain::~EffectChain()
|
||||
@@ -5786,7 +5962,8 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int
|
||||
size_t size = mEffects.size();
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (mEffects[i]->id() == id) {
|
||||
// by convention, return first effect if id provided is 0 (0 is never a valid id)
|
||||
if (id == 0 || mEffects[i]->id() == id) {
|
||||
effect = mEffects[i];
|
||||
break;
|
||||
}
|
||||
@@ -5816,21 +5993,24 @@ void AudioFlinger::EffectChain::process_l()
|
||||
}
|
||||
|
||||
// addEffect_l() must be called with PlaybackThread::mLock held
|
||||
status_t AudioFlinger::EffectChain::addEffect_l(sp<EffectModule>& effect)
|
||||
status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
|
||||
{
|
||||
effect_descriptor_t desc = effect->desc();
|
||||
uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
|
||||
|
||||
Mutex::Autolock _l(mLock);
|
||||
effect->setChain(this);
|
||||
sp<ThreadBase> thread = mThread.promote();
|
||||
if (thread == 0) {
|
||||
return NO_INIT;
|
||||
}
|
||||
effect->setThread(thread);
|
||||
|
||||
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
||||
// Auxiliary effects are inserted at the beginning of mEffects vector as
|
||||
// they are processed first and accumulated in chain input buffer
|
||||
mEffects.insertAt(effect, 0);
|
||||
sp<ThreadBase> thread = mThread.promote();
|
||||
if (thread == 0) {
|
||||
return NO_INIT;
|
||||
}
|
||||
|
||||
// the input buffer for auxiliary effect contains mono samples in
|
||||
// 32 bit format. This is to avoid saturation in AudoMixer
|
||||
// accumulation stage. Saturation is done in EffectModule::process() before
|
||||
|
||||
@@ -168,8 +168,7 @@ public:
|
||||
int *id,
|
||||
int *enabled);
|
||||
|
||||
status_t registerEffectResource_l(effect_descriptor_t *desc);
|
||||
void unregisterEffectResource_l(effect_descriptor_t *desc);
|
||||
virtual status_t moveEffects(int session, int srcOutput, int dstOutput);
|
||||
|
||||
enum hardware_call_state {
|
||||
AUDIO_HW_IDLE = 0,
|
||||
@@ -619,15 +618,22 @@ private:
|
||||
sp<EffectChain> getEffectChain_l(int sessionId);
|
||||
status_t addEffectChain_l(const sp<EffectChain>& chain);
|
||||
size_t removeEffectChain_l(const sp<EffectChain>& chain);
|
||||
void lockEffectChains_l();
|
||||
void unlockEffectChains();
|
||||
void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains);
|
||||
void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
|
||||
|
||||
sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
|
||||
void detachAuxEffect_l(int effectId);
|
||||
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
|
||||
status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
|
||||
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
|
||||
int EffectId);
|
||||
status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track,
|
||||
int EffectId);
|
||||
void setMode(uint32_t mode);
|
||||
|
||||
status_t addEffect_l(const sp< EffectModule>& effect);
|
||||
void removeEffect_l(const sp< EffectModule>& effect);
|
||||
|
||||
uint32_t getStrategyForSession_l(int sessionId);
|
||||
|
||||
struct stream_type_t {
|
||||
stream_type_t()
|
||||
: volume(1.0f),
|
||||
@@ -690,7 +696,10 @@ private:
|
||||
|
||||
class MixerThread : public PlaybackThread {
|
||||
public:
|
||||
MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
|
||||
MixerThread (const sp<AudioFlinger>& audioFlinger,
|
||||
AudioStreamOut* output,
|
||||
int id,
|
||||
uint32_t device);
|
||||
virtual ~MixerThread();
|
||||
|
||||
// Thread virtuals
|
||||
@@ -701,7 +710,8 @@ private:
|
||||
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
|
||||
|
||||
protected:
|
||||
uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
|
||||
uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
|
||||
Vector< sp<Track> > *tracksToRemove);
|
||||
virtual int getTrackName_l();
|
||||
virtual void deleteTrackName_l(int name);
|
||||
virtual uint32_t activeSleepTimeUs();
|
||||
@@ -764,6 +774,9 @@ private:
|
||||
void audioConfigChanged_l(int event, int ioHandle, void *param2);
|
||||
|
||||
int nextUniqueId();
|
||||
status_t moveEffectChain_l(int session,
|
||||
AudioFlinger::PlaybackThread *srcThread,
|
||||
AudioFlinger::PlaybackThread *dstThread);
|
||||
|
||||
friend class AudioBuffer;
|
||||
|
||||
@@ -931,6 +944,9 @@ private:
|
||||
uint32_t status() {
|
||||
return mStatus;
|
||||
}
|
||||
int sessionId() {
|
||||
return mSessionId;
|
||||
}
|
||||
status_t setEnabled(bool enabled);
|
||||
bool isEnabled();
|
||||
|
||||
@@ -938,6 +954,8 @@ private:
|
||||
int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; }
|
||||
void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
|
||||
int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; }
|
||||
void setChain(const wp<EffectChain>& chain) { mChain = chain; }
|
||||
void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
|
||||
|
||||
status_t addHandle(sp<EffectHandle>& handle);
|
||||
void disconnect(const wp<EffectHandle>& handle);
|
||||
@@ -1061,19 +1079,19 @@ private:
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
status_t addEffect_l(sp<EffectModule>& handle);
|
||||
status_t addEffect_l(const sp<EffectModule>& handle);
|
||||
size_t removeEffect_l(const sp<EffectModule>& handle);
|
||||
|
||||
int sessionId() {
|
||||
return mSessionId;
|
||||
}
|
||||
|
||||
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
|
||||
sp<EffectModule> getEffectFromId_l(int id);
|
||||
bool setVolume_l(uint32_t *left, uint32_t *right);
|
||||
void setDevice_l(uint32_t device);
|
||||
void setMode_l(uint32_t mode);
|
||||
|
||||
|
||||
void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
|
||||
mInBuffer = buffer;
|
||||
mOwnInBuffer = ownsBuffer;
|
||||
@@ -1092,6 +1110,10 @@ private:
|
||||
void stopTrack() {mActiveTrackCnt--;}
|
||||
int activeTracks() { return mActiveTrackCnt;}
|
||||
|
||||
uint32_t strategy() { return mStrategy; }
|
||||
void setStrategy(uint32_t strategy)
|
||||
{ mStrategy = strategy; }
|
||||
|
||||
status_t dump(int fd, const Vector<String16>& args);
|
||||
|
||||
protected:
|
||||
@@ -1112,7 +1134,7 @@ private:
|
||||
uint32_t mRightVolume; // previous volume on right channel
|
||||
uint32_t mNewLeftVolume; // new volume on left channel
|
||||
uint32_t mNewRightVolume; // new volume on right channel
|
||||
|
||||
uint32_t mStrategy; // strategy for this effect chain
|
||||
};
|
||||
|
||||
friend class RecordThread;
|
||||
@@ -1142,12 +1164,6 @@ private:
|
||||
#endif
|
||||
uint32_t mMode;
|
||||
|
||||
// Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
|
||||
static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
|
||||
// Maximum memory allocated to audio effects in KB
|
||||
static const uint32_t MAX_EFFECTS_MEMORY = 512;
|
||||
uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
|
||||
uint32_t mTotalEffectsMemory; // current memory used by effects
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -538,9 +538,11 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
|
||||
return output;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
LOGV("startOutput() output %d, stream %d", output, stream);
|
||||
LOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("startOutput() unknow output %d", output);
|
||||
@@ -574,9 +576,11 @@ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSyst
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
LOGV("stopOutput() output %d, stream %d", output, stream);
|
||||
LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("stopOutput() unknow output %d", output);
|
||||
@@ -602,8 +606,12 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSyste
|
||||
setOutputDevice(output, getNewDevice(output));
|
||||
|
||||
#ifdef WITH_A2DP
|
||||
if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) {
|
||||
setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
|
||||
if (mA2dpOutput != 0 && !a2dpUsedForSonification() &&
|
||||
strategy == STRATEGY_SONIFICATION) {
|
||||
setStrategyMute(STRATEGY_MEDIA,
|
||||
false,
|
||||
mA2dpOutput,
|
||||
mOutputs.valueFor(mHardwareOutput)->mLatency*2);
|
||||
}
|
||||
#endif
|
||||
if (output != mHardwareOutput) {
|
||||
@@ -826,6 +834,85 @@ status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type s
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc)
|
||||
{
|
||||
LOGV("getOutputForEffect()");
|
||||
// apply simple rule where global effects are attached to the same output as MUSIC streams
|
||||
return getOutput(AudioSystem::MUSIC);
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id)
|
||||
{
|
||||
ssize_t index = mOutputs.indexOfKey(output);
|
||||
if (index < 0) {
|
||||
LOGW("registerEffect() unknown output %d", output);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) {
|
||||
LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS",
|
||||
desc->name, (float)desc->cpuLoad/10);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
|
||||
LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
|
||||
desc->name, desc->memoryUsage);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
mTotalEffectsCpuLoad += desc->cpuLoad;
|
||||
mTotalEffectsMemory += desc->memoryUsage;
|
||||
LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d",
|
||||
desc->name, output, strategy, session, id);
|
||||
|
||||
LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage);
|
||||
LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
|
||||
|
||||
EffectDescriptor *pDesc = new EffectDescriptor();
|
||||
memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
|
||||
pDesc->mOutput = output;
|
||||
pDesc->mStrategy = (routing_strategy)strategy;
|
||||
pDesc->mSession = session;
|
||||
mEffects.add(id, pDesc);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerBase::unregisterEffect(int id)
|
||||
{
|
||||
ssize_t index = mEffects.indexOfKey(id);
|
||||
if (index < 0) {
|
||||
LOGW("unregisterEffect() unknown effect ID %d", id);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
EffectDescriptor *pDesc = mEffects.valueAt(index);
|
||||
|
||||
if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
|
||||
LOGW("unregisterEffect() CPU load %d too high for total %d",
|
||||
pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
|
||||
pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
|
||||
}
|
||||
mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
|
||||
if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
|
||||
LOGW("unregisterEffect() memory %d too big for total %d",
|
||||
pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
|
||||
pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
|
||||
}
|
||||
mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
|
||||
LOGV("unregisterEffect() effect %s, ID %d, CPU %d, memory %d",
|
||||
pDesc->mDesc.name, id, pDesc->mDesc.cpuLoad, pDesc->mDesc.memoryUsage);
|
||||
LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory);
|
||||
|
||||
mEffects.removeItem(id);
|
||||
delete pDesc;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyManagerBase::dump(int fd)
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
@@ -890,6 +977,19 @@ status_t AudioPolicyManagerBase::dump(int fd)
|
||||
write(fd, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
|
||||
(float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
|
||||
write(fd, buffer, strlen(buffer));
|
||||
|
||||
snprintf(buffer, SIZE, "Registered effects:\n");
|
||||
write(fd, buffer, strlen(buffer));
|
||||
for (size_t i = 0; i < mEffects.size(); i++) {
|
||||
snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
|
||||
write(fd, buffer, strlen(buffer));
|
||||
mEffects.valueAt(i)->dump(fd);
|
||||
}
|
||||
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -902,7 +1002,8 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
|
||||
#ifdef AUDIO_POLICY_TEST
|
||||
Thread(false),
|
||||
#endif //AUDIO_POLICY_TEST
|
||||
mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false)
|
||||
mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0),
|
||||
mLimitRingtoneVolume(false), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
|
||||
{
|
||||
mpClientInterface = clientInterface;
|
||||
|
||||
@@ -938,6 +1039,7 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
|
||||
} else {
|
||||
addOutput(mHardwareOutput, outputDesc);
|
||||
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);
|
||||
//TODO: configure audio effect output stage here
|
||||
}
|
||||
|
||||
updateDeviceForStrategy();
|
||||
@@ -1152,6 +1254,9 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices
|
||||
if (mA2dpOutput) {
|
||||
// add A2DP output descriptor
|
||||
addOutput(mA2dpOutput, outputDesc);
|
||||
|
||||
//TODO: configure audio effect output stage here
|
||||
|
||||
// set initial stream volume for A2DP device
|
||||
applyStreamVolumes(mA2dpOutput, device);
|
||||
if (a2dpUsedForSonification()) {
|
||||
@@ -1269,6 +1374,7 @@ void AudioPolicyManagerBase::closeA2dpOutputs()
|
||||
AudioParameter param;
|
||||
param.add(String8("closing"), String8("true"));
|
||||
mpClientInterface->setParameters(mA2dpOutput, param.toString());
|
||||
|
||||
mpClientInterface->closeOutput(mA2dpOutput);
|
||||
delete mOutputs.valueFor(mA2dpOutput);
|
||||
mOutputs.removeItem(mA2dpOutput);
|
||||
@@ -1282,48 +1388,54 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u
|
||||
uint32_t curDevice = getDeviceForStrategy(strategy, false);
|
||||
bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
|
||||
bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER));
|
||||
AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
|
||||
AudioOutputDescriptor *a2dpOutputDesc;
|
||||
audio_io_handle_t srcOutput = 0;
|
||||
audio_io_handle_t dstOutput = 0;
|
||||
|
||||
if (a2dpWasUsed && !a2dpIsUsed) {
|
||||
bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2);
|
||||
|
||||
dstOutput = mHardwareOutput;
|
||||
if (dupUsed) {
|
||||
LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy);
|
||||
a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
|
||||
LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy);
|
||||
srcOutput = mDuplicatedOutput;
|
||||
} else {
|
||||
LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy);
|
||||
a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
|
||||
LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy);
|
||||
srcOutput = mA2dpOutput;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
if (getStrategy((AudioSystem::stream_type)i) == strategy) {
|
||||
mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput);
|
||||
}
|
||||
}
|
||||
// do not change newDevice if it was already set before this call by a previous call to
|
||||
// getNewDevice() or checkOutputForStrategy() for a strategy with higher priority
|
||||
if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) {
|
||||
if (newDevice == 0 && mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(strategy)) {
|
||||
newDevice = getDeviceForStrategy(strategy, false);
|
||||
}
|
||||
}
|
||||
if (a2dpIsUsed && !a2dpWasUsed) {
|
||||
bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2);
|
||||
audio_io_handle_t a2dpOutput;
|
||||
|
||||
srcOutput = mHardwareOutput;
|
||||
if (dupUsed) {
|
||||
LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy);
|
||||
a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput);
|
||||
a2dpOutput = mDuplicatedOutput;
|
||||
LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy);
|
||||
dstOutput = mDuplicatedOutput;
|
||||
} else {
|
||||
LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy);
|
||||
a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput);
|
||||
a2dpOutput = mA2dpOutput;
|
||||
LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy);
|
||||
dstOutput = mA2dpOutput;
|
||||
}
|
||||
}
|
||||
|
||||
if (srcOutput != 0 && dstOutput != 0) {
|
||||
// Move effects associated to this strategy from previous output to new output
|
||||
for (size_t i = 0; i < mEffects.size(); i++) {
|
||||
EffectDescriptor *desc = mEffects.valueAt(i);
|
||||
if (desc->mSession != AudioSystem::SESSION_OUTPUT_STAGE &&
|
||||
desc->mStrategy == strategy &&
|
||||
desc->mOutput == srcOutput) {
|
||||
LOGV("checkOutputForStrategy() moving effect %d to output %d", mEffects.keyAt(i), dstOutput);
|
||||
mpClientInterface->moveEffects(desc->mSession, srcOutput, dstOutput);
|
||||
desc->mOutput = dstOutput;
|
||||
}
|
||||
}
|
||||
// Move tracks associated to this strategy from previous output to new output
|
||||
for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
|
||||
if (getStrategy((AudioSystem::stream_type)i) == strategy) {
|
||||
mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput);
|
||||
mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1371,8 +1483,12 @@ uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fro
|
||||
return device;
|
||||
}
|
||||
|
||||
AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream)
|
||||
{
|
||||
uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) {
|
||||
return (uint32_t)getStrategy(stream);
|
||||
}
|
||||
|
||||
AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(
|
||||
AudioSystem::stream_type stream) {
|
||||
// stream to strategy mapping
|
||||
switch (stream) {
|
||||
case AudioSystem::VOICE_CALL:
|
||||
@@ -1836,6 +1952,16 @@ bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream,
|
||||
(format !=0 && !AudioSystem::isLinearPCM(format)));
|
||||
}
|
||||
|
||||
uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
|
||||
{
|
||||
return MAX_EFFECTS_CPU_LOAD;
|
||||
}
|
||||
|
||||
uint32_t AudioPolicyManagerBase::getMaxEffectsMemory()
|
||||
{
|
||||
return MAX_EFFECTS_MEMORY;
|
||||
}
|
||||
|
||||
// --- AudioOutputDescriptor class implementation
|
||||
|
||||
AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()
|
||||
@@ -1969,5 +2095,27 @@ void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size)
|
||||
mCanBeMuted);
|
||||
}
|
||||
|
||||
// --- EffectDescriptor class implementation
|
||||
|
||||
status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd)
|
||||
{
|
||||
const size_t SIZE = 256;
|
||||
char buffer[SIZE];
|
||||
String8 result;
|
||||
|
||||
snprintf(buffer, SIZE, " Output: %d\n", mOutput);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Session: %d\n", mSession);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, SIZE, " Name: %s\n", mDesc.name);
|
||||
result.append(buffer);
|
||||
write(fd, result.string(), result.size());
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}; // namespace android
|
||||
|
||||
@@ -119,7 +119,8 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices
|
||||
if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
|
||||
if (state != AudioSystem::DEVICE_STATE_AVAILABLE &&
|
||||
state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
@@ -128,8 +129,9 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices
|
||||
return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
|
||||
}
|
||||
|
||||
AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device,
|
||||
const char *device_address)
|
||||
AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(
|
||||
AudioSystem::audio_devices device,
|
||||
const char *device_address)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return AudioSystem::DEVICE_STATE_UNAVAILABLE;
|
||||
@@ -175,7 +177,8 @@ status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask)
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
|
||||
status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage,
|
||||
AudioSystem::forced_config config)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
@@ -223,24 +226,28 @@ audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream,
|
||||
return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioPolicyService::startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
}
|
||||
LOGV("startOutput() tid %d", gettid());
|
||||
Mutex::Autolock _l(mLock);
|
||||
return mpPolicyManager->startOutput(output, stream);
|
||||
return mpPolicyManager->startOutput(output, stream, session);
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
|
||||
status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
}
|
||||
LOGV("stopOutput() tid %d", gettid());
|
||||
Mutex::Autolock _l(mLock);
|
||||
return mpPolicyManager->stopOutput(output, stream);
|
||||
return mpPolicyManager->stopOutput(output, stream, session);
|
||||
}
|
||||
|
||||
void AudioPolicyService::releaseOutput(audio_io_handle_t output)
|
||||
@@ -339,8 +346,46 @@ status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type strea
|
||||
return mpPolicyManager->getStreamVolumeIndex(stream, index);
|
||||
}
|
||||
|
||||
uint32_t AudioPolicyService::getStrategyForStream(AudioSystem::stream_type stream)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return mpPolicyManager->getStrategyForStream(stream);
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
}
|
||||
Mutex::Autolock _l(mLock);
|
||||
return mpPolicyManager->getOutputForEffect(desc);
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
}
|
||||
return mpPolicyManager->registerEffect(desc, output, strategy, session, id);
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::unregisterEffect(int id)
|
||||
{
|
||||
if (mpPolicyManager == NULL) {
|
||||
return NO_INIT;
|
||||
}
|
||||
return mpPolicyManager->unregisterEffect(id);
|
||||
}
|
||||
|
||||
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
|
||||
LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
|
||||
LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
|
||||
IPCThreadState::self()->getCallingPid());
|
||||
}
|
||||
|
||||
static bool tryLock(Mutex& mutex)
|
||||
@@ -447,10 +492,16 @@ audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
|
||||
return af->openOutput(pDevices,
|
||||
pSamplingRate,
|
||||
(uint32_t *)pFormat,
|
||||
pChannels,
|
||||
pLatencyMs,
|
||||
flags);
|
||||
}
|
||||
|
||||
audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2)
|
||||
audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1,
|
||||
audio_io_handle_t output2)
|
||||
{
|
||||
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
|
||||
if (af == 0) {
|
||||
@@ -514,12 +565,16 @@ 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, int delayMs)
|
||||
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, 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)
|
||||
{
|
||||
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
|
||||
if (af == 0) return PERMISSION_DENIED;
|
||||
@@ -527,8 +582,18 @@ status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, au
|
||||
return af->setStreamOutput(stream, output);
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::moveEffects(int session, audio_io_handle_t srcOutput,
|
||||
audio_io_handle_t dstOutput)
|
||||
{
|
||||
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
|
||||
if (af == 0) return PERMISSION_DENIED;
|
||||
|
||||
void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs)
|
||||
return af->moveEffects(session, (int)srcOutput, (int)dstOutput);
|
||||
}
|
||||
|
||||
void AudioPolicyService::setParameters(audio_io_handle_t ioHandle,
|
||||
const String8& keyValuePairs,
|
||||
int delayMs)
|
||||
{
|
||||
mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs);
|
||||
}
|
||||
@@ -539,7 +604,8 @@ String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const Stri
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
|
||||
status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone,
|
||||
AudioSystem::stream_type stream)
|
||||
{
|
||||
mTonePlaybackThread->startToneCommand(tone, stream);
|
||||
return NO_ERROR;
|
||||
@@ -623,8 +689,11 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
|
||||
}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);
|
||||
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);
|
||||
@@ -633,7 +702,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
|
||||
}break;
|
||||
case SET_PARAMETERS: {
|
||||
ParametersData *data = (ParametersData *)command->mParam;
|
||||
LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
|
||||
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();
|
||||
@@ -643,7 +713,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop()
|
||||
}break;
|
||||
case SET_VOICE_VOLUME: {
|
||||
VoiceVolumeData *data = (VoiceVolumeData *)command->mParam;
|
||||
LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume);
|
||||
LOGV("AudioCommandThread() processing set voice volume volume %f",
|
||||
data->mVolume);
|
||||
command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
|
||||
if (command->mWaitStatus) {
|
||||
command->mCond.signal();
|
||||
@@ -734,7 +805,10 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand()
|
||||
mWaitWorkCV.signal();
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs)
|
||||
status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream,
|
||||
float volume,
|
||||
int output,
|
||||
int delayMs)
|
||||
{
|
||||
status_t status = NO_ERROR;
|
||||
|
||||
@@ -752,7 +826,8 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float
|
||||
}
|
||||
Mutex::Autolock _l(mLock);
|
||||
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();
|
||||
if (command->mWaitStatus) {
|
||||
command->mCond.wait(mLock);
|
||||
@@ -762,7 +837,9 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs)
|
||||
status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
|
||||
const String8& keyValuePairs,
|
||||
int delayMs)
|
||||
{
|
||||
status_t status = NO_ERROR;
|
||||
|
||||
@@ -779,7 +856,8 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
|
||||
}
|
||||
Mutex::Autolock _l(mLock);
|
||||
insertCommand_l(command, delayMs);
|
||||
LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, 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);
|
||||
@@ -840,7 +918,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
|
||||
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());
|
||||
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++) {
|
||||
@@ -872,7 +951,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma
|
||||
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);
|
||||
LOGV("Filtering out volume command on output %d for stream %d",
|
||||
data->mIO, data->mStream);
|
||||
removedCommands.add(command2);
|
||||
} break;
|
||||
case START_TONE:
|
||||
@@ -896,7 +976,8 @@ 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 %d, num commands %d", command->mCommand, (int)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);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ class String8;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient
|
||||
class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface,
|
||||
public IBinder::DeathRecipient
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -43,8 +44,9 @@ public:
|
||||
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 AudioSystem::device_connection_state getDeviceConnectionState(
|
||||
AudioSystem::audio_devices device,
|
||||
const char *device_address);
|
||||
virtual status_t setPhoneState(int state);
|
||||
virtual status_t setRingerMode(uint32_t mode, uint32_t mask);
|
||||
virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
|
||||
@@ -53,15 +55,21 @@ public:
|
||||
uint32_t samplingRate = 0,
|
||||
uint32_t format = AudioSystem::FORMAT_DEFAULT,
|
||||
uint32_t channels = 0,
|
||||
AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT);
|
||||
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);
|
||||
AudioSystem::output_flags flags =
|
||||
AudioSystem::OUTPUT_FLAG_INDIRECT);
|
||||
virtual status_t startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
virtual status_t stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
virtual void releaseOutput(audio_io_handle_t output);
|
||||
virtual audio_io_handle_t getInput(int inputSource,
|
||||
uint32_t samplingRate = 0,
|
||||
uint32_t format = AudioSystem::FORMAT_DEFAULT,
|
||||
uint32_t channels = 0,
|
||||
AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0);
|
||||
AudioSystem::audio_in_acoustics acoustics =
|
||||
(AudioSystem::audio_in_acoustics)0);
|
||||
virtual status_t startInput(audio_io_handle_t input);
|
||||
virtual status_t stopInput(audio_io_handle_t input);
|
||||
virtual void releaseInput(audio_io_handle_t input);
|
||||
@@ -71,6 +79,16 @@ public:
|
||||
virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
|
||||
virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
|
||||
|
||||
virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
|
||||
|
||||
virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
|
||||
virtual status_t registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id);
|
||||
virtual status_t unregisterEffect(int id);
|
||||
|
||||
virtual status_t onTransact(
|
||||
uint32_t code,
|
||||
const Parcel& data,
|
||||
@@ -89,7 +107,8 @@ public:
|
||||
uint32_t *pChannels,
|
||||
uint32_t *pLatencyMs,
|
||||
AudioSystem::output_flags flags);
|
||||
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2);
|
||||
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
|
||||
audio_io_handle_t output2);
|
||||
virtual status_t closeOutput(audio_io_handle_t output);
|
||||
virtual status_t suspendOutput(audio_io_handle_t output);
|
||||
virtual status_t restoreOutput(audio_io_handle_t output);
|
||||
@@ -99,13 +118,21 @@ 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, int delayMs = 0);
|
||||
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, int delayMs = 0);
|
||||
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();
|
||||
virtual status_t setVoiceVolume(float volume, int delayMs = 0);
|
||||
virtual status_t moveEffects(int session,
|
||||
audio_io_handle_t srcOutput,
|
||||
audio_io_handle_t dstOutput);
|
||||
|
||||
private:
|
||||
AudioPolicyService();
|
||||
|
||||
Reference in New Issue
Block a user