AudioPolicy: callback for recording configuration change
Each AudioSession tracks start / end of recording, and sends
a callback to AudioSystem.
AudioSystem tracks a single recording callback tracking
input source and audio session number.
Change-Id: Ic065751d9ba013e03f2a6ad8dde02542e5465ec0
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index feed402..ff07b08 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -91,6 +91,12 @@
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
};
+
+// definitions for audio recording configuration updates
+// which update type is reported
+#define RECORD_CONFIG_EVENT_START 1
+#define RECORD_CONFIG_EVENT_STOP 0
+
}; // namespace android
#endif // ANDROID_AUDIO_POLICY_H
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26a0bb2..114e194 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -31,6 +31,7 @@
typedef void (*audio_error_callback)(status_t err);
typedef void (*dynamic_policy_callback)(int event, String8 regId, int val);
+typedef void (*record_config_callback)(int event, int session, int source);
class IAudioFlinger;
class IAudioPolicyService;
@@ -92,6 +93,7 @@
static void setErrorCallback(audio_error_callback cb);
static void setDynPolicyCallback(dynamic_policy_callback cb);
+ static void setRecordConfigCallback(record_config_callback);
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
@@ -419,6 +421,8 @@
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
private:
Mutex mLock;
@@ -438,6 +442,7 @@
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
static dynamic_policy_callback gDynPolicyCallback;
+ static record_config_callback gRecordConfigCallback;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
index a7f2cc3..e8fd39f 100644
--- a/include/media/IAudioPolicyServiceClient.h
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -37,6 +37,9 @@
virtual void onAudioPatchListUpdate() = 0;
// Notifies a change in the mixing state of a specific mix in a dynamic audio policy
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+ // Notifies a change of audio recording configuration
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) = 0;
};
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9d645f0..46622ea 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -37,6 +37,7 @@
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
+record_config_callback AudioSystem::gRecordConfigCallback = NULL;
// establish binder interface to AudioFlinger service
@@ -652,6 +653,12 @@
gDynPolicyCallback = cb;
}
+/*static*/ void AudioSystem::setRecordConfigCallback(record_config_callback cb)
+{
+ Mutex::Autolock _l(gLock);
+ gRecordConfigCallback = cb;
+}
+
// client singleton for AudioPolicyService binder interface
// protected by gLockAPS
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -1223,6 +1230,19 @@
}
}
+void AudioSystem::AudioPolicyServiceClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source) {
+ record_config_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ cb = gRecordConfigCallback;
+ }
+
+ if (cb != NULL) {
+ cb(event, session, source);
+ }
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
{
{
diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp
index 65cc7d6..fe5df28 100644
--- a/media/libmedia/IAudioPolicyServiceClient.cpp
+++ b/media/libmedia/IAudioPolicyServiceClient.cpp
@@ -30,7 +30,8 @@
enum {
PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
PATCH_LIST_UPDATE,
- MIX_STATE_UPDATE
+ MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
@@ -63,6 +64,16 @@
data.writeInt32(state);
remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+ data.writeInt32(event);
+ data.writeInt32(session);
+ data.writeInt32(source);
+ remote()->transact(RECORDING_CONFIGURATION_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient");
@@ -89,7 +100,15 @@
int32_t state = data.readInt32();
onDynamicPolicyMixStateUpdate(regId, state);
return NO_ERROR;
- }
+ } break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+ CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
+ int event = (int) data.readInt32();
+ audio_session_t session = (audio_session_t) data.readInt32();
+ audio_source_t source = (audio_source_t) data.readInt32();
+ onRecordingConfigurationUpdate(event, session, source);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 7cf44dc..42fb9e5 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -332,6 +332,9 @@
virtual audio_unique_id_t newAudioUniqueId() = 0;
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) = 0;
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 7e5ef5d..77c0d07 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -69,7 +69,7 @@
audio_port_handle_t mId;
// audio sessions attached to this input
AudioSessionCollection mSessions;
- // Because a preemtible capture session can preempt another one, we end up in an endless loop
+ // Because a preemptible capture session can preempt another one, we end up in an endless loop
// situation were each session is allowed to restart after being preempted,
// thus preempting the other one which restarts and so on.
// To avoid this situation, we store which audio session was preempted when
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 6feef80..576822c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -21,9 +21,12 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
+#include <media/AudioPolicy.h>
namespace android {
+class AudioPolicyClientInterface;
+
class AudioSession : public RefBase
{
public:
@@ -34,7 +37,9 @@
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
uid_t uid,
- bool isSoundTrigger);
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface);
status_t dump(int fd, int spaces, int index) const;
@@ -64,6 +69,8 @@
bool mIsSoundTrigger;
uint32_t mOpenCount;
uint32_t mActiveCount;
+ AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
+ AudioPolicyClientInterface* mClientInterface;
};
class AudioSessionCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 2cec951..597c029 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "APM::AudioSession"
//#define LOG_NDEBUG 0
+#include <AudioPolicyInterface.h>
#include "AudioSession.h"
#include "AudioGain.h"
#include "TypeConverter.h"
@@ -32,11 +33,13 @@
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
uid_t uid,
- bool isSoundTrigger) :
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface) :
mSession(session), mInputSource(inputSource),
mFormat(format), mSampleRate(sampleRate), mChannelMask(channelMask),
mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
- mOpenCount(1), mActiveCount(0)
+ mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface)
{
}
@@ -54,6 +57,7 @@
uint32_t AudioSession::changeActiveCount(int delta)
{
+ const uint32_t oldActiveCount = mActiveCount;
if ((delta + (int)mActiveCount) < 0) {
ALOGW("%s invalid delta %d, active count %d",
__FUNCTION__, delta, mActiveCount);
@@ -61,6 +65,27 @@
}
mActiveCount += delta;
ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
+
+ if ((oldActiveCount == 0) && (mActiveCount > 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_MIXING);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
+ mSession, mInputSource);
+ } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_IDLE);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_STOP,
+ mSession, mInputSource);
+ }
+
return mActiveCount;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 11dabae..af8a2b9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1462,7 +1462,8 @@
channelMask,
flags,
uid,
- isSoundTrigger);
+ isSoundTrigger,
+ policyMix, mpClientInterface);
// TODO enable input reuse
#if 0
@@ -1692,6 +1693,7 @@
void AudioPolicyManager::releaseInput(audio_io_handle_t input,
audio_session_t session)
{
+
ALOGV("releaseInput() %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
@@ -3078,7 +3080,8 @@
if ((profileType & inputDeviceTypes) == 0) {
continue;
}
- sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+ sp<AudioInputDescriptor> inputDesc =
+ new AudioInputDescriptor(inProfile);
inputDesc->mDevice = profileType;
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 489a9be..3d51f48 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -219,6 +219,12 @@
mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state);
}
+void AudioPolicyService::AudioPolicyClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ mAudioPolicyService->onRecordingConfigurationUpdate(event, session, source);
+}
+
audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId()
{
return AudioSystem::newAudioUniqueId();
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index cdde605..0c5d275 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -215,19 +215,6 @@
mOutputCommandThread->updateAudioPatchListCommand();
}
-status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- int delayMs)
-{
- return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
-}
-
-status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
- int delayMs)
-{
- return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
-}
-
void AudioPolicyService::doOnAudioPatchListUpdate()
{
Mutex::Autolock _l(mNotificationClientsLock);
@@ -251,6 +238,34 @@
}
}
+void AudioPolicyService::onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ mOutputCommandThread->recordingConfigurationUpdateCommand(event, session, source);
+}
+
+void AudioPolicyService::doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ Mutex::Autolock _l(mNotificationClientsLock);
+ for (size_t i = 0; i < mNotificationClients.size(); i++) {
+ mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, session, source);
+ }
+}
+
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
int delayMs)
{
@@ -296,7 +311,15 @@
String8 regId, int32_t state)
{
if (mAudioPolicyServiceClient != 0) {
- mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ }
+}
+
+void AudioPolicyService::NotificationClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ if (mAudioPolicyServiceClient != 0) {
+ mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, session, source);
}
}
@@ -558,7 +581,6 @@
case DYN_POLICY_MIX_STATE_UPDATE: {
DynPolicyMixStateUpdateData *data =
(DynPolicyMixStateUpdateData *)command->mParam.get();
- //###ALOGV("AudioCommandThread() processing dyn policy mix state update");
ALOGV("AudioCommandThread() processing dyn policy mix state update %s %d",
data->mRegId.string(), data->mState);
svc = mService.promote();
@@ -569,6 +591,19 @@
svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
mLock.lock();
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+ RecordingConfigurationUpdateData *data =
+ (RecordingConfigurationUpdateData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing recording configuration update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnRecordingConfigurationUpdate(data->mEvent, data->mSession,
+ data->mSource);
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -825,6 +860,21 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::recordingConfigurationUpdateCommand(
+ int event, audio_session_t session, audio_source_t source)
+{
+ sp<AudioCommand>command = new AudioCommand();
+ command->mCommand = RECORDING_CONFIGURATION_UPDATE;
+ RecordingConfigurationUpdateData *data = new RecordingConfigurationUpdateData();
+ data->mEvent = event;
+ data->mSession = session;
+ data->mSource = source;
+ command->mParam = data;
+ ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d",
+ event, source);
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -971,6 +1021,10 @@
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+
+ } break;
+
case START_TONE:
case STOP_TONE:
default:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a0d5aa2..4c11d93 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -225,6 +225,10 @@
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
+ void doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
private:
AudioPolicyService() ANDROID_API;
@@ -256,7 +260,8 @@
UPDATE_AUDIOPORT_LIST,
UPDATE_AUDIOPATCH_LIST,
SET_AUDIOPORT_CONFIG,
- DYN_POLICY_MIX_STATE_UPDATE
+ DYN_POLICY_MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -295,6 +300,9 @@
status_t setAudioPortConfigCommand(const struct audio_port_config *config,
int delayMs);
void dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
+ void recordingConfigurationUpdateCommand(
+ int event, audio_session_t session,
+ audio_source_t source);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
@@ -385,6 +393,13 @@
int32_t mState;
};
+ class RecordingConfigurationUpdateData : public AudioCommandData {
+ public:
+ int mEvent;
+ audio_session_t mSession;
+ audio_source_t mSource;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -491,6 +506,8 @@
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ virtual void onRecordingConfigurationUpdate(int event,
+ audio_session_t session, audio_source_t source);
virtual audio_unique_id_t newAudioUniqueId();
@@ -509,6 +526,9 @@
void onAudioPortListUpdate();
void onAudioPatchListUpdate();
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(
+ int event, audio_session_t session,
+ audio_source_t source);
void setAudioPortCallbacksEnabled(bool enabled);
// IBinder::DeathRecipient