Merge "Merge commit 'a8f3cafa4f81e3c38c4d0882031a246a36be1299' into merge"
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 63c82cc..51a775b 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -302,6 +302,15 @@
status_t res = data.readInt32();
return res;
}
+
+ virtual void notifySystemEvent(int eventId, int arg0) {
+ Parcel data, reply;
+ data.writeInt32(eventId);
+ data.writeInt32(arg0);
+ remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+
};
IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
@@ -470,6 +479,13 @@
reply->writeInt32(status);
return NO_ERROR;
} break;
+ case NOTIFY_SYSTEM_EVENT: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ int eventId = data.readInt32();
+ int arg0 = data.readInt32();
+ notifySystemEvent(eventId, arg0);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index c8d3d19..cad275e 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -51,6 +51,7 @@
SUPPORTS_CAMERA_API,
CONNECT_LEGACY,
SET_TORCH_MODE,
+ NOTIFY_SYSTEM_EVENT,
};
enum {
@@ -64,7 +65,18 @@
enum {
CAMERA_HAL_API_VERSION_UNSPECIFIED = -1
- };
+ };
+
+ /**
+ * Keep up-to-date with declarations in
+ * frameworks/base/services/core/java/com/android/server/camera/CameraService.java
+ *
+ * These event codes are intended to be used with the notifySystemEvent call.
+ */
+ enum {
+ NO_EVENT = 0,
+ USER_SWITCHED,
+ };
public:
DECLARE_META_INTERFACE(CameraService);
@@ -148,6 +160,11 @@
*/
virtual status_t setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) = 0;
+
+ /**
+ * Notify the camera service of a system event. Should only be called from system_server.
+ */
+ virtual void notifySystemEvent(int eventId, int arg0) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index ad5d6ed..f5db1bb 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -346,7 +346,8 @@
};
- static void setAudioPortCallback(sp<AudioPortCallback> callBack);
+ static status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
+ static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
private:
@@ -373,12 +374,19 @@
AudioPolicyServiceClient() {
}
+ status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
+ status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
+
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
// IAudioPolicyServiceClient
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
+
+ private:
+ Mutex mLock;
+ Vector <sp <AudioPortCallback> > mAudioPortCallbacks;
};
static sp<AudioFlingerClient> gAudioFlingerClient;
@@ -390,7 +398,6 @@
static Mutex gLockCache; // protects gOutputs, gPrevInSamplingRate, gPrevInFormat,
// gPrevInChannelMask and gInBuffSize
static Mutex gLockAPS; // protects gAudioPolicyService and gAudioPolicyServiceClient
- static Mutex gLockAPC; // protects gAudioPortCallback
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
@@ -405,8 +412,6 @@
// list of output descriptors containing cached parameters
// (sampling rate, framecount, channel count...)
static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
-
- static sp<AudioPortCallback> gAudioPortCallback;
};
}; // namespace android
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index c6b34a7..9150a94 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -34,7 +34,6 @@
Mutex AudioSystem::gLock;
Mutex AudioSystem::gLockCache;
Mutex AudioSystem::gLockAPS;
-Mutex AudioSystem::gLockAPC;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
@@ -48,8 +47,6 @@
audio_channel_mask_t AudioSystem::gPrevInChannelMask;
size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid
-sp<AudioSystem::AudioPortCallback> AudioSystem::gAudioPortCallback;
-
// establish binder interface to AudioFlinger service
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
@@ -873,7 +870,6 @@
Mutex::Autolock _l(gLockAPS);
gAudioPolicyService.clear();
}
- // Do not clear gAudioPortCallback
}
bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
@@ -933,12 +929,31 @@
return aps->setAudioPortConfig(config);
}
-void AudioSystem::setAudioPortCallback(sp<AudioPortCallback> callBack)
+status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack)
{
- Mutex::Autolock _l(gLockAPC);
- gAudioPortCallback = callBack;
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ Mutex::Autolock _l(gLockAPS);
+ if (gAudioPolicyServiceClient == 0) {
+ return NO_INIT;
+ }
+ return gAudioPolicyServiceClient->addAudioPortCallback(callBack);
}
+status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callBack)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ Mutex::Autolock _l(gLockAPS);
+ if (gAudioPolicyServiceClient == 0) {
+ return NO_INIT;
+ }
+ return gAudioPolicyServiceClient->removeAudioPortCallback(callBack);
+}
+
+
status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
audio_devices_t *device)
@@ -971,12 +986,58 @@
// ---------------------------------------------------------------------------
+status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
+ const sp<AudioPortCallback>& callBack)
+{
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
+ if (mAudioPortCallbacks[i] == callBack) {
+ return INVALID_OPERATION;
+ }
+ }
+ mAudioPortCallbacks.add(callBack);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
+ const sp<AudioPortCallback>& callBack)
+{
+ Mutex::Autolock _l(mLock);
+ size_t i;
+ for (i = 0; i < mAudioPortCallbacks.size(); i++) {
+ if (mAudioPortCallbacks[i] == callBack) {
+ break;
+ }
+ }
+ if (i == mAudioPortCallbacks.size()) {
+ return INVALID_OPERATION;
+ }
+ mAudioPortCallbacks.removeAt(i);
+ return NO_ERROR;
+}
+
+void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate()
+{
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
+ mAudioPortCallbacks[i]->onAudioPortListUpdate();
+ }
+}
+
+void AudioSystem::AudioPolicyServiceClient::onAudioPatchListUpdate()
+{
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
+ mAudioPortCallbacks[i]->onAudioPatchListUpdate();
+ }
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
{
{
- Mutex::Autolock _l(gLockAPC);
- if (gAudioPortCallback != 0) {
- gAudioPortCallback->onServiceDied();
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
+ mAudioPortCallbacks[i]->onServiceDied();
}
}
{
@@ -987,20 +1048,4 @@
ALOGW("AudioPolicyService server died!");
}
-void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate()
-{
- Mutex::Autolock _l(gLockAPC);
- if (gAudioPortCallback != 0) {
- gAudioPortCallback->onAudioPortListUpdate();
- }
-}
-
-void AudioSystem::AudioPolicyServiceClient::onAudioPatchListUpdate()
-{
- Mutex::Autolock _l(gLockAPC);
- if (gAudioPortCallback != 0) {
- gAudioPortCallback->onAudioPatchListUpdate();
- }
-}
-
} // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 98f64fe..ce30c62 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -667,14 +667,18 @@
status_t AudioTrack::setSampleRate(uint32_t rate)
{
- if (mIsTimed || isOffloadedOrDirect()) {
+ AutoMutex lock(mLock);
+ if (rate == mSampleRate) {
+ return NO_ERROR;
+ }
+ if (mIsTimed || isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
return INVALID_OPERATION;
}
-
- AutoMutex lock(mLock);
if (mOutput == AUDIO_IO_HANDLE_NONE) {
return NO_INIT;
}
+ // NOTE: it is theoretically possible, but highly unlikely, that a device change
+ // could mean a previously allowed sampling rate is no longer allowed.
uint32_t afSamplingRate;
if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) {
return NO_INIT;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index a040343..5a31b74 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -265,6 +265,12 @@
}
}
+ mBitrate = totalBitrate;
+
+ return OK;
+}
+
+status_t NuPlayer::GenericSource::startSources() {
// Start the selected A/V tracks now before we start buffering.
// Widevine sources might re-initialize crypto when starting, if we delay
// this to start(), all data buffered during prepare would be wasted.
@@ -279,8 +285,6 @@
return UNKNOWN_ERROR;
}
- mBitrate = totalBitrate;
-
return OK;
}
@@ -415,6 +419,32 @@
| FLAG_CAN_SEEK_FORWARD
| FLAG_CAN_SEEK);
+ if (mIsSecure) {
+ // secure decoders must be instantiated before starting widevine source
+ sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
+ notifyInstantiateSecureDecoders(reply);
+ } else {
+ finishPrepareAsync();
+ }
+}
+
+void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
+ if (err != OK) {
+ ALOGE("Failed to instantiate secure decoders!");
+ notifyPreparedAndCleanup(err);
+ return;
+ }
+ finishPrepareAsync();
+}
+
+void NuPlayer::GenericSource::finishPrepareAsync() {
+ status_t err = startSources();
+ if (err != OK) {
+ ALOGE("Failed to init start data source!");
+ notifyPreparedAndCleanup(err);
+ return;
+ }
+
if (mIsStreaming) {
mPrepareBuffering = true;
@@ -430,6 +460,7 @@
mDataSource.clear();
mCachedSource.clear();
mHttpSource.clear();
+ mBitrate = -1;
cancelPollBuffering();
}
@@ -805,6 +836,14 @@
break;
}
+ case kWhatSecureDecodersInstantiated:
+ {
+ int32_t err;
+ CHECK(msg->findInt32("err", &err));
+ onSecureDecodersInstantiated(err);
+ break;
+ }
+
case kWhatStopWidevine:
{
// mStopRead is only used for Widevine to prevent the video source
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 5fc41ec..862ee5f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -96,6 +96,7 @@
kWhatStopWidevine,
kWhatStart,
kWhatResume,
+ kWhatSecureDecodersInstantiated,
};
struct Track {
@@ -158,6 +159,9 @@
void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
void notifyPreparedAndCleanup(status_t err);
+ void onSecureDecodersInstantiated(status_t err);
+ void finishPrepareAsync();
+ status_t startSources();
void onGetFormatMeta(sp<AMessage> msg) const;
sp<MetaData> doGetFormatMeta(bool audio) const;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index f4d3794..cfa5258 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1021,23 +1021,41 @@
}
}
+status_t NuPlayer::onInstantiateSecureDecoders() {
+ status_t err;
+ if (!(mSourceFlags & Source::FLAG_SECURE)) {
+ return BAD_TYPE;
+ }
+
+ if (mRenderer != NULL) {
+ ALOGE("renderer should not be set when instantiating secure decoders");
+ return UNKNOWN_ERROR;
+ }
+
+ // TRICKY: We rely on mRenderer being null, so that decoder does not start requesting
+ // data on instantiation.
+ if (mNativeWindow != NULL) {
+ err = instantiateDecoder(false, &mVideoDecoder);
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ if (mAudioSink != NULL) {
+ err = instantiateDecoder(true, &mAudioDecoder);
+ if (err != OK) {
+ return err;
+ }
+ }
+ return OK;
+}
+
void NuPlayer::onStart() {
mOffloadAudio = false;
mAudioEOS = false;
mVideoEOS = false;
mStarted = true;
- /* instantiate decoders now for secure playback */
- if (mSourceFlags & Source::FLAG_SECURE) {
- if (mNativeWindow != NULL) {
- instantiateDecoder(false, &mVideoDecoder);
- }
-
- if (mAudioSink != NULL) {
- instantiateDecoder(true, &mAudioDecoder);
- }
- }
-
mSource->start();
uint32_t flags = 0;
@@ -1390,7 +1408,7 @@
FlushStatus newStatus =
needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
- mFlushComplete[audio][false /* isDecoder */] = false;
+ mFlushComplete[audio][false /* isDecoder */] = (mRenderer == NULL);
mFlushComplete[audio][true /* isDecoder */] = false;
if (audio) {
ALOGE_IF(mFlushingAudio != NONE,
@@ -1675,6 +1693,23 @@
CHECK(msg->findInt32("what", &what));
switch (what) {
+ case Source::kWhatInstantiateSecureDecoders:
+ {
+ if (mSource == NULL) {
+ // This is a stale notification from a source that was
+ // asynchronously preparing when the client called reset().
+ // We handled the reset, the source is gone.
+ break;
+ }
+
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
+ status_t err = onInstantiateSecureDecoders();
+ reply->setInt32("err", err);
+ reply->post();
+ break;
+ }
+
case Source::kWhatPrepared:
{
if (mSource == NULL) {
@@ -1687,6 +1722,14 @@
int32_t err;
CHECK(msg->findInt32("err", &err));
+ if (err != OK) {
+ // shut down potential secure codecs in case client never calls reset
+ mDeferredActions.push_back(
+ new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
+ FLUSH_CMD_SHUTDOWN /* video */));
+ processDeferredActions();
+ }
+
sp<NuPlayerDriver> driver = mDriver.promote();
if (driver != NULL) {
// notify duration first, so that it's definitely set when
@@ -1971,6 +2014,13 @@
notify->post();
}
+void NuPlayer::Source::notifyInstantiateSecureDecoders(const sp<AMessage> &reply) {
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", kWhatInstantiateSecureDecoders);
+ notify->setMessage("reply", reply);
+ notify->post();
+}
+
void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
TRESPASS();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index a2cb53e..2bc20d7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -204,6 +204,8 @@
status_t instantiateDecoder(bool audio, sp<DecoderBase> *decoder);
+ status_t onInstantiateSecureDecoders();
+
void updateVideoSize(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat = NULL);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 5a8beb1..d9f14a2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -55,6 +55,7 @@
kWhatTimedTextData,
kWhatQueueDecoderShutdown,
kWhatDrmNoLicense,
+ kWhatInstantiateSecureDecoders,
};
// The provides message is used to notify the player about various
@@ -125,6 +126,7 @@
void notifyFlagsChanged(uint32_t flags);
void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
+ void notifyInstantiateSecureDecoders(const sp<AMessage> &reply);
void notifyPrepared(status_t err = OK);
private:
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 4ac2fb2..118c174 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -50,6 +50,17 @@
namespace android {
+// static
+// Bandwidth Switch Mark Defaults
+const int64_t LiveSession::kUpSwitchMarkUs = 25000000ll;
+const int64_t LiveSession::kDownSwitchMarkUs = 18000000ll;
+const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
+
+// Buffer Prepare/Ready/Underflow Marks
+const int64_t LiveSession::kReadyMarkUs = 5000000ll;
+const int64_t LiveSession::kPrepareMarkUs = 1500000ll;
+const int64_t LiveSession::kUnderflowMarkUs = 1000000ll;
+
struct LiveSession::BandwidthEstimator : public RefBase {
BandwidthEstimator();
@@ -153,9 +164,9 @@
mRealTimeBaseUs(0ll),
mReconfigurationInProgress(false),
mSwitchInProgress(false),
- mUpSwitchMark(kUpSwitchMark),
- mDownSwitchMark(kDownSwitchMark),
- mUpSwitchMargin(kUpSwitchMargin),
+ mUpSwitchMark(kUpSwitchMarkUs),
+ mDownSwitchMark(kDownSwitchMarkUs),
+ mUpSwitchMargin(kUpSwitchMarginUs),
mFirstTimeUsValid(false),
mFirstTimeUs(0),
mLastSeekTimeUs(0) {
@@ -563,9 +574,9 @@
{
int64_t targetDurationUs;
CHECK(msg->findInt64("targetDurationUs", &targetDurationUs));
- mUpSwitchMark = min(kUpSwitchMark, targetDurationUs * 3);
- mDownSwitchMark = min(kDownSwitchMark, targetDurationUs * 9 / 4);
- mUpSwitchMargin = min(kUpSwitchMargin, targetDurationUs);
+ mUpSwitchMark = min(kUpSwitchMarkUs, targetDurationUs * 3);
+ mDownSwitchMark = min(kDownSwitchMarkUs, targetDurationUs * 9 / 4);
+ mUpSwitchMargin = min(kUpSwitchMarginUs, targetDurationUs);
break;
}
@@ -656,7 +667,7 @@
// If switching up, require a cushion bigger than kUnderflowMark
// to avoid buffering immediately after the switch.
// (If we don't have that cushion we'd rather cancel and try again.)
- int64_t delayUs = switchUp ? (kUnderflowMark + 1000000ll) : 0;
+ int64_t delayUs = switchUp ? (kUnderflowMarkUs + 1000000ll) : 0;
bool needResumeUntil = false;
sp<AMessage> stopParams = msg;
if (checkSwitchProgress(stopParams, delayUs, &needResumeUntil)) {
@@ -2068,13 +2079,13 @@
}
++activeCount;
- int64_t readyMark = mInPreparationPhase ? kPrepareMark : kReadyMark;
+ int64_t readyMark = mInPreparationPhase ? kPrepareMarkUs : kReadyMarkUs;
if (bufferedDurationUs > readyMark
|| mPacketSources[i]->isFinished(0)) {
++readyCount;
}
if (!mPacketSources[i]->isFinished(0)) {
- if (bufferedDurationUs < kUnderflowMark) {
+ if (bufferedDurationUs < kUnderflowMarkUs) {
++underflowCount;
}
if (bufferedDurationUs > mUpSwitchMark) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index d11675b..3d62cab 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -122,14 +122,14 @@
};
// Bandwidth Switch Mark Defaults
- static const int64_t kUpSwitchMark = 25000000ll;
- static const int64_t kDownSwitchMark = 18000000ll;
- static const int64_t kUpSwitchMargin = 5000000ll;
+ static const int64_t kUpSwitchMarkUs;
+ static const int64_t kDownSwitchMarkUs;
+ static const int64_t kUpSwitchMarginUs;
// Buffer Prepare/Ready/Underflow Marks
- static const int64_t kReadyMark = 5000000ll;
- static const int64_t kPrepareMark = 1500000ll;
- static const int64_t kUnderflowMark = 1000000ll;
+ static const int64_t kReadyMarkUs;
+ static const int64_t kPrepareMarkUs;
+ static const int64_t kUnderflowMarkUs;
struct BandwidthEstimator;
struct BandwidthItem {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 6786506..01c3dd6 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -166,10 +166,12 @@
PSISection();
status_t append(const void *data, size_t size);
+ void setSkipBytes(uint8_t skip);
void clear();
bool isComplete() const;
bool isEmpty() const;
+ bool isCRCOkay() const;
const uint8_t *data() const;
size_t size() const;
@@ -179,6 +181,8 @@
private:
sp<ABuffer> mBuffer;
+ uint8_t mSkipBytes;
+ static uint32_t CRC_TABLE[];
DISALLOW_EVIL_CONSTRUCTORS(PSISection);
};
@@ -1171,6 +1175,7 @@
}
unsigned skip = br->getBits(8);
+ section->setSkipBytes(skip + 1); // skip filler bytes + pointer field itself
br->skipBits(skip * 8);
}
@@ -1185,6 +1190,9 @@
return OK;
}
+ if (!section->isCRCOkay()) {
+ return BAD_VALUE;
+ }
ABitReader sectionBits(section->data(), section->size());
if (PID == 0) {
@@ -1407,7 +1415,79 @@
////////////////////////////////////////////////////////////////////////////////
-ATSParser::PSISection::PSISection() {
+
+// CRC32 used for PSI section. The table was generated by following command:
+// $ python pycrc.py --model crc-32-mpeg --algorithm table-driven --generate c
+// Visit http://www.tty1.net/pycrc/index_en.html for more details.
+uint32_t ATSParser::PSISection::CRC_TABLE[] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+ 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+ 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+ 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+ 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+ 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+ 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+ 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+ 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+ 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+ 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+ 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+ 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+ 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+ };
+
+ATSParser::PSISection::PSISection() :
+ mSkipBytes(0) {
}
ATSParser::PSISection::~PSISection() {
@@ -1438,10 +1518,15 @@
return OK;
}
+void ATSParser::PSISection::setSkipBytes(uint8_t skip) {
+ mSkipBytes = skip;
+}
+
void ATSParser::PSISection::clear() {
if (mBuffer != NULL) {
mBuffer->setRange(0, 0);
}
+ mSkipBytes = 0;
}
bool ATSParser::PSISection::isComplete() const {
@@ -1465,4 +1550,30 @@
return mBuffer == NULL ? 0 : mBuffer->size();
}
+bool ATSParser::PSISection::isCRCOkay() const {
+ if (!isComplete()) {
+ return false;
+ }
+ uint8_t* data = mBuffer->data();
+
+ // Return true if section_syntax_indicator says no section follows the field section_length.
+ if ((data[1] & 0x80) == 0) {
+ return true;
+ }
+
+ unsigned sectionLength = U16_AT(data + 1) & 0xfff;
+ ALOGV("sectionLength %u, skip %u", sectionLength, mSkipBytes);
+
+ // Skip the preceding field present when payload start indicator is on.
+ sectionLength -= mSkipBytes;
+
+ uint32_t crc = 0xffffffff;
+ for(unsigned i = 0; i < sectionLength + 4 /* crc */; i++) {
+ uint8_t b = data[i];
+ int index = ((crc >> 24) ^ (b & 0xff)) & 0xff;
+ crc = CRC_TABLE[index] ^ (crc << 8);
+ }
+ ALOGV("crc: %08x\n", crc);
+ return (crc == 0);
+}
} // namespace android
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index baf65f6..0e2e48c 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -31,13 +31,16 @@
libradioservice
LOCAL_STATIC_LIBRARIES := \
- libregistermsext
+ libregistermsext
LOCAL_C_INCLUDES := \
frameworks/av/media/libmediaplayerservice \
frameworks/av/services/medialog \
frameworks/av/services/audioflinger \
frameworks/av/services/audiopolicy \
+ frameworks/av/services/audiopolicy/common/managerdefinitions/include \
+ frameworks/av/services/audiopolicy/common/include \
+ frameworks/av/services/audiopolicy/engine/interface \
frameworks/av/services/camera/libcameraservice \
frameworks/av/services/mediaresourcemanager \
$(call include-path-for, audio-utils) \
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 5988d2c..4efb3d7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4316,6 +4316,10 @@
}
if (track->isStopping_1()) {
track->mState = TrackBase::STOPPING_2;
+ if (last && mHwPaused) {
+ doHwResume = true;
+ mHwPaused = false;
+ }
}
if ((track->sharedBuffer() != 0) || track->isStopped() ||
track->isStopping_2() || track->isPaused()) {
@@ -4455,14 +4459,17 @@
bool AudioFlinger::DirectOutputThread::shouldStandby_l()
{
bool trackPaused = false;
+ bool trackStopped = false;
// do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
// after a timeout and we will enter standby then.
if (mTracks.size() > 0) {
trackPaused = mTracks[mTracks.size() - 1]->isPaused();
+ trackStopped = mTracks[mTracks.size() - 1]->isStopped() ||
+ mTracks[mTracks.size() - 1]->mState == TrackBase::IDLE;
}
- return !mStandby && !(trackPaused || (usesHwAvSync() && mHwPaused));
+ return !mStandby && !(trackPaused || (usesHwAvSync() && mHwPaused && !trackStopped));
}
// getTrackName_l() must be called with ThreadBase::mLock held
@@ -4565,7 +4572,10 @@
// use shorter standby delay as on normal output to release
// hardware resources as soon as possible
- if (audio_is_linear_pcm(mFormat)) {
+ // no delay on outputs with HW A/V sync
+ if (usesHwAvSync()) {
+ standbyDelay = 0;
+ } else if (audio_is_linear_pcm(mFormat)) {
standbyDelay = microseconds(activeSleepTime*2);
} else {
standbyDelay = kOffloadStandbyDelayNs;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 7692315..dc9f249 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -745,6 +745,7 @@
// move to STOPPING_2 when drain completes and then STOPPED
mState = STOPPING_1;
}
+ playbackThread->broadcast_l();
ALOGV("not stopping/stopped => stopping/stopped (%d) on thread %p", mName,
playbackThread);
}
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 351ed79..d4ce86a 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -21,7 +21,9 @@
LOCAL_C_INCLUDES := \
$(TOPDIR)frameworks/av/services/audioflinger \
$(call include-path-for, audio-effects) \
- $(call include-path-for, audio-utils)
+ $(call include-path-for, audio-utils) \
+ $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
+ $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -39,7 +41,8 @@
endif
LOCAL_STATIC_LIBRARIES := \
- libmedia_helper
+ libmedia_helper \
+ libaudiopolicycomponents
LOCAL_MODULE:= libaudiopolicyservice
@@ -54,14 +57,6 @@
LOCAL_SRC_FILES:= \
managerdefault/AudioPolicyManager.cpp \
- managerdefault/ConfigParsingUtils.cpp \
- managerdefault/Devices.cpp \
- managerdefault/Gains.cpp \
- managerdefault/HwModule.cpp \
- managerdefault/IOProfile.cpp \
- managerdefault/Ports.cpp \
- managerdefault/AudioInputDescriptor.cpp \
- managerdefault/AudioOutputDescriptor.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -69,8 +64,15 @@
liblog \
libsoundtrigger
+LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
+
+LOCAL_C_INCLUDES += \
+ $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
+ $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+
LOCAL_STATIC_LIBRARIES := \
- libmedia_helper
+ libmedia_helper \
+ libaudiopolicycomponents
LOCAL_MODULE:= libaudiopolicymanagerdefault
@@ -86,9 +88,21 @@
LOCAL_SHARED_LIBRARIES := \
libaudiopolicymanagerdefault
+LOCAL_STATIC_LIBRARIES := \
+ libaudiopolicycomponents
+
+LOCAL_C_INCLUDES += \
+ $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
+ $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+
LOCAL_MODULE:= libaudiopolicymanager
include $(BUILD_SHARED_LIBRARY)
endif
endif
+
+#######################################################################
+# Recursive call sub-folder Android.mk
+#
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audiopolicy/common/Android.mk b/services/audiopolicy/common/Android.mk
new file mode 100644
index 0000000..dcce8e3
--- /dev/null
+++ b/services/audiopolicy/common/Android.mk
@@ -0,0 +1,9 @@
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+#######################################################################
+# Recursive call sub-folder Android.mk
+#
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/services/audiopolicy/managerdefault/ApmImplDefinitions.h b/services/audiopolicy/common/include/RoutingStrategy.h
similarity index 79%
rename from services/audiopolicy/managerdefault/ApmImplDefinitions.h
rename to services/audiopolicy/common/include/RoutingStrategy.h
index 620979b..d38967e 100644
--- a/services/audiopolicy/managerdefault/ApmImplDefinitions.h
+++ b/services/audiopolicy/common/include/RoutingStrategy.h
@@ -14,8 +14,14 @@
* limitations under the License.
*/
+#pragma once
+
namespace android {
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+
enum routing_strategy {
STRATEGY_MEDIA,
STRATEGY_PHONE,
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
new file mode 100755
index 0000000..a4cc759
--- /dev/null
+++ b/services/audiopolicy/common/include/Volume.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Log.h>
+
+class VolumeCurvePoint
+{
+public:
+ int mIndex;
+ float mDBAttenuation;
+};
+
+class Volume
+{
+public:
+ /**
+ * 4 points to define the volume attenuation curve, each characterized by the volume
+ * index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+ * we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+ *
+ * @todo shall become configurable
+ */
+ enum {
+ VOLMIN = 0,
+ VOLKNEE1 = 1,
+ VOLKNEE2 = 2,
+ VOLMAX = 3,
+
+ VOLCNT = 4
+ };
+
+ /**
+ * device categories used for volume curve management.
+ */
+ enum device_category {
+ DEVICE_CATEGORY_HEADSET,
+ DEVICE_CATEGORY_SPEAKER,
+ DEVICE_CATEGORY_EARPIECE,
+ DEVICE_CATEGORY_EXT_MEDIA,
+ DEVICE_CATEGORY_CNT
+ };
+
+ /**
+ * extract one device relevant for volume control from multiple device selection
+ *
+ * @param[in] device for which the volume category is associated
+ *
+ * @return subset of device required to limit the number of volume category per device
+ */
+ static audio_devices_t getDeviceForVolume(audio_devices_t device)
+ {
+ if (device == AUDIO_DEVICE_NONE) {
+ // this happens when forcing a route update and no track is active on an output.
+ // In this case the returned category is not important.
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (popcount(device) > 1) {
+ // Multiple device selection is either:
+ // - speaker + one other device: give priority to speaker in this case.
+ // - one A2DP device + another device: happens with duplicated output. In this case
+ // retain the device on the A2DP output as the other must not correspond to an active
+ // selection if not the speaker.
+ // - HDMI-CEC system audio mode only output: give priority to available item in order.
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
+ device = AUDIO_DEVICE_OUT_HDMI_ARC;
+ } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
+ device = AUDIO_DEVICE_OUT_AUX_LINE;
+ } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
+ device = AUDIO_DEVICE_OUT_SPDIF;
+ } else {
+ device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+ }
+ }
+
+ /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
+ if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+
+ ALOGW_IF(popcount(device) != 1,
+ "getDeviceForVolume() invalid device combination: %08x",
+ device);
+
+ return device;
+ }
+
+ /**
+ * returns the category the device belongs to with regard to volume curve management
+ *
+ * @param[in] device to check upon the category to whom it belongs to.
+ *
+ * @return device category.
+ */
+ static device_category getDeviceCategory(audio_devices_t device)
+ {
+ switch(getDeviceForVolume(device)) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ return DEVICE_CATEGORY_EARPIECE;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ return DEVICE_CATEGORY_HEADSET;
+ case AUDIO_DEVICE_OUT_LINE:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ /*USB? Remote submix?*/
+ return DEVICE_CATEGORY_EXT_MEDIA;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+ default:
+ return DEVICE_CATEGORY_SPEAKER;
+ }
+ }
+
+};
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
new file mode 100755
index 0000000..a2327ee
--- /dev/null
+++ b/services/audiopolicy/common/include/policy.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+
+// For mixed output and inputs, the policy will use max mixer sampling rates.
+// Do not limit sampling rate otherwise
+#define MAX_MIXER_SAMPLING_RATE 48000
+
+// For mixed output and inputs, the policy will use max mixer channel count.
+// Do not limit channel count otherwise
+#define MAX_MIXER_CHANNEL_COUNT 8
+
+/**
+ * A device mask for all audio input devices that are considered "virtual" when evaluating
+ * active inputs in getActiveInput()
+ */
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER)
+
+
+/**
+ * A device mask for all audio input and output devices where matching inputs/outputs on device
+ * type alone is not enough: the address must match too
+ */
+#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+
+/**
+ * Check if the state given correspond to an in call state.
+ * @TODO find a better name for widely call state
+ *
+ * @param[in] state to consider
+ *
+ * @return true if given state represents a device in a telephony or VoIP call
+ */
+static inline bool is_state_in_call(int state)
+{
+ return (state == AUDIO_MODE_IN_CALL) || (state == AUDIO_MODE_IN_COMMUNICATION);
+}
+
+/**
+ * Check if the input device given is considered as a virtual device.
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device is a virtual one, false otherwise.
+ */
+static bool is_virtual_input_device(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check whether the device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static bool device_distinguishes_on_address(audio_devices_t device)
+{
+ return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
+}
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
new file mode 100644
index 0000000..71ba1cb
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ src/DeviceDescriptor.cpp \
+ src/AudioGain.cpp \
+ src/StreamDescriptor.cpp \
+ src/HwModule.cpp \
+ src/IOProfile.cpp \
+ src/AudioPort.cpp \
+ src/AudioPolicyMix.cpp \
+ src/AudioPatch.cpp \
+ src/AudioInputDescriptor.cpp \
+ src/AudioOutputDescriptor.cpp \
+ src/EffectDescriptor.cpp \
+ src/ConfigParsingUtils.cpp \
+ src/SoundTriggerSession.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ liblog \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/include \
+ $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/include
+
+LOCAL_MODULE := libaudiopolicycomponents
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
new file mode 100644
index 0000000..21fbf9b
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <system/audio.h>
+
+namespace android {
+
+class AudioGain: public RefBase
+{
+public:
+ AudioGain(int index, bool useInChannelMask);
+ virtual ~AudioGain() {}
+
+ void dump(int fd, int spaces, int index) const;
+
+ void getDefaultConfig(struct audio_gain_config *config);
+ status_t checkConfig(const struct audio_gain_config *config);
+ int mIndex;
+ struct audio_gain mGain;
+ bool mUseInChannelMask;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
similarity index 68%
rename from services/audiopolicy/managerdefault/AudioInputDescriptor.h
rename to services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 02579e6..7536a37 100644
--- a/services/audiopolicy/managerdefault/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -14,14 +14,28 @@
* limitations under the License.
*/
+#pragma once
+
+#include "AudioPort.h"
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+
namespace android {
+class IOProfile;
+class AudioMix;
+
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
// and keep track of the usage of this input.
class AudioInputDescriptor: public AudioPortConfig
{
public:
AudioInputDescriptor(const sp<IOProfile>& profile);
+ void setIoHandle(audio_io_handle_t ioHandle);
+
+ audio_module_handle_t getModuleHandle() const;
status_t dump(int fd);
@@ -45,4 +59,27 @@
void toAudioPort(struct audio_port *port) const;
};
+class AudioInputCollection :
+ public DefaultKeyedVector< audio_io_handle_t, sp<AudioInputDescriptor> >
+{
+public:
+ bool isSourceActive(audio_source_t source) const;
+
+ sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
+
+ uint32_t activeInputsCount() const;
+
+ /**
+ * return io handle of active input or 0 if no input is active
+ * Only considers inputs from physical devices (e.g. main mic, headset mic) when
+ * ignoreVirtualInputs is true.
+ */
+ audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+ audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+
+ status_t dump(int fd) const;
+};
+
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
similarity index 65%
rename from services/audiopolicy/managerdefault/AudioOutputDescriptor.h
rename to services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 32f46e4..43ee691 100644
--- a/services/audiopolicy/managerdefault/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -14,10 +14,20 @@
* limitations under the License.
*/
-#include "ApmImplDefinitions.h"
+#pragma once
+
+#include "AudioPort.h"
+#include <RoutingStrategy.h>
+#include <utils/Errors.h>
+#include <utils/Timers.h>
+#include <utils/KeyedVector.h>
+#include <system/audio.h>
namespace android {
+class IOProfile;
+class AudioMix;
+
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
class AudioOutputDescriptor: public AudioPortConfig
@@ -30,6 +40,7 @@
audio_devices_t device() const;
void changeRefCount(audio_stream_type_t stream, int delta);
+ void setIoHandle(audio_io_handle_t ioHandle);
bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
audio_devices_t supportedDevices();
uint32_t latency();
@@ -38,15 +49,14 @@
bool isStreamActive(audio_stream_type_t stream,
uint32_t inPastMs = 0,
nsecs_t sysTime = 0) const;
- bool isStrategyActive(routing_strategy strategy,
- uint32_t inPastMs = 0,
- nsecs_t sysTime = 0) const;
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
virtual sp<AudioPort> getAudioPort() const { return mProfile; }
void toAudioPort(struct audio_port *port) const;
+ audio_module_handle_t getModuleHandle() const;
+
audio_port_handle_t mId;
audio_io_handle_t mIoHandle; // output handle
uint32_t mLatency; //
@@ -66,4 +76,38 @@
uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
};
+class AudioOutputCollection :
+ public DefaultKeyedVector< audio_io_handle_t, sp<AudioOutputDescriptor> >
+{
+public:
+ bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+ /**
+ * return whether a stream is playing remotely, override to change the definition of
+ * local/remote playback, used for instance by notification manager to not make
+ * media players lose audio focus when not playing locally
+ * For the base implementation, "remotely" means playing during screen mirroring which
+ * uses an output for playback with a non-empty, non "0" address.
+ */
+ bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+ /**
+ * returns the A2DP output handle if it is open or 0 otherwise
+ */
+ audio_io_handle_t getA2dpOutput() const;
+
+ sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
+
+ sp<AudioOutputDescriptor> getPrimaryOutput() const;
+
+ /**
+ * return true if any output is playing anything besides the stream to ignore
+ */
+ bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+
+ audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+
+ status_t dump(int fd) const;
+};
+
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
new file mode 100644
index 0000000..385f257
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class AudioPatch : public RefBase
+{
+public:
+ AudioPatch(const struct audio_patch *patch, uid_t uid);
+
+ status_t dump(int fd, int spaces, int index) const;
+
+ audio_patch_handle_t mHandle;
+ struct audio_patch mPatch;
+ uid_t mUid;
+ audio_patch_handle_t mAfPatchHandle;
+
+private:
+ static volatile int32_t mNextUniqueId;
+};
+
+class AudioPatchCollection : public DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> >
+{
+public:
+ status_t addAudioPatch(audio_patch_handle_t handle, const sp<AudioPatch>& patch);
+
+ status_t removeAudioPatch(audio_patch_handle_t handle);
+
+ status_t listAudioPatches(unsigned int *num_patches, struct audio_patch *patches) const;
+
+ status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
new file mode 100644
index 0000000..988aed6
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/RefBase.h>
+#include <media/AudioPolicy.h>
+#include <utils/KeyedVector.h>
+#include <hardware/audio.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class AudioOutputDescriptor;
+
+/**
+ * custom mix entry in mPolicyMixes
+ */
+class AudioPolicyMix : public RefBase {
+public:
+ AudioPolicyMix() {}
+
+ const sp<AudioOutputDescriptor> &getOutput() const;
+
+ void setOutput(sp<AudioOutputDescriptor> &output);
+
+ void clearOutput();
+
+ android::AudioMix &getMix();
+
+ void setMix(AudioMix &mix);
+
+private:
+ AudioMix mMix; // Audio policy mix descriptor
+ sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
+};
+
+
+class AudioPolicyMixCollection : public DefaultKeyedVector<String8, sp<AudioPolicyMix> >
+{
+public:
+ status_t getAudioPolicyMix(String8 address, sp<AudioPolicyMix> &policyMix) const;
+
+ status_t registerMix(String8 address, AudioMix mix);
+
+ status_t unregisterMix(String8 address);
+
+ void closeOutput(sp<AudioOutputDescriptor> &desc);
+
+ /**
+ * Try to find an output descriptor for the given attributes.
+ *
+ * @param[in] attributes to consider for the research of output descriptor.
+ * @param[out] desc to return if an output could be found.
+ *
+ * @return NO_ERROR if an output was found for the given attribute (in this case, the
+ * descriptor output param is initialized), error code otherwise.
+ */
+ status_t getOutputForAttr(audio_attributes_t attributes, sp<AudioOutputDescriptor> &desc);
+
+ audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
+ audio_devices_t availableDeviceTypes,
+ AudioMix **policyMix);
+
+ status_t getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix);
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Ports.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
similarity index 88%
rename from services/audiopolicy/managerdefault/Ports.h
rename to services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index f6e0e93..4f7f2bc 100644
--- a/services/audiopolicy/managerdefault/Ports.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -14,15 +14,25 @@
* limitations under the License.
*/
+#pragma once
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
namespace android {
class HwModule;
+class AudioGain;
-class AudioPort: public virtual RefBase
+class AudioPort : public virtual RefBase
{
public:
AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role, const sp<HwModule>& module);
+ audio_port_role_t role, const sp<HwModule>& module);
virtual ~AudioPort() {}
audio_port_handle_t getHandle() { return mId; }
@@ -30,6 +40,8 @@
void attach(const sp<HwModule>& module);
bool isAttached() { return mId != 0; }
+ static audio_port_handle_t getNextUniqueId();
+
virtual void toAudioPort(struct audio_port *port) const;
void importAudioPort(const sp<AudioPort> port);
@@ -63,6 +75,8 @@
static const audio_format_t sPcmFormatCompareTable[];
static int compareFormats(audio_format_t format1, audio_format_t format2);
+ audio_module_handle_t getModuleHandle() const;
+
void dump(int fd, int spaces) const;
String8 mName;
@@ -86,9 +100,12 @@
// and a unique ID for identifying a port to the (upcoming) selection API,
// and its relationship to the mId in AudioOutputDescriptor and AudioInputDescriptor.
audio_port_handle_t mId;
+
+private:
+ static volatile int32_t mNextUniqueId;
};
-class AudioPortConfig: public virtual RefBase
+class AudioPortConfig : public virtual RefBase
{
public:
AudioPortConfig();
@@ -105,18 +122,4 @@
struct audio_gain_config mGain;
};
-
-class AudioPatch: public RefBase
-{
-public:
- AudioPatch(audio_patch_handle_t handle, const struct audio_patch *patch, uid_t uid);
-
- status_t dump(int fd, int spaces, int index) const;
-
- audio_patch_handle_t mHandle;
- struct audio_patch mPatch;
- uid_t mUid;
- audio_patch_handle_t mAfPatchHandle;
-};
-
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
similarity index 77%
rename from services/audiopolicy/managerdefault/ConfigParsingUtils.h
rename to services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index b2d9763..53cb4a3 100644
--- a/services/audiopolicy/managerdefault/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -14,6 +14,19 @@
* limitations under the License.
*/
+#pragma once
+
+#include "DeviceDescriptor.h"
+#include "HwModule.h"
+#include "audio_policy_conf.h"
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <cutils/config_utils.h>
+#include <utils/RefBase.h>
+#include <system/audio_policy.h>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -156,6 +169,32 @@
static uint32_t parseOutputFlagNames(char *name);
static uint32_t parseInputFlagNames(char *name);
static audio_devices_t parseDeviceNames(char *name);
+
+ static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled);
+
+ static void loadGlobalConfig(cnode *root, const sp<HwModule>& module,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled);
+
+ static status_t loadAudioPolicyConfig(const char *path,
+ HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled);
+
+private:
+ static void loadHwModule(cnode *root, HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled);
};
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Devices.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
similarity index 71%
rename from services/audiopolicy/managerdefault/Devices.h
rename to services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index af2fbda..d15f6b4 100644
--- a/services/audiopolicy/managerdefault/Devices.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -14,12 +14,19 @@
* limitations under the License.
*/
+#pragma once
+
+#include "AudioPort.h"
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <cutils/config_utils.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
namespace android {
-class AudioPort;
-class AudioPortConfig;
-
-class DeviceDescriptor: public AudioPort, public AudioPortConfig
+class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
public:
DeviceDescriptor(const String8& name, audio_devices_t type);
@@ -37,12 +44,18 @@
virtual void loadGains(cnode *root);
virtual void toAudioPort(struct audio_port *port) const;
+ audio_devices_t type() const { return mDeviceType; }
status_t dump(int fd, int spaces, int index) const;
- audio_devices_t mDeviceType;
String8 mAddress;
+ audio_port_handle_t mId;
static String8 emptyNameStr;
+
+private:
+ audio_devices_t mDeviceType;
+
+friend class DeviceVector;
};
class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
@@ -50,9 +63,9 @@
public:
DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
- ssize_t add(const sp<DeviceDescriptor>& item);
- ssize_t remove(const sp<DeviceDescriptor>& item);
- ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
+ ssize_t add(const sp<DeviceDescriptor>& item);
+ ssize_t remove(const sp<DeviceDescriptor>& item);
+ ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
audio_devices_t types() const { return mDeviceTypes; }
@@ -63,8 +76,13 @@
DeviceVector getDevicesFromType(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromName(const String8& name) const;
- DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address)
- const;
+ DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
+
+ audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+
+ audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
+
+ status_t dump(int fd, const String8 &direction) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
new file mode 100644
index 0000000..c9783a1
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <RoutingStrategy.h>
+#include <hardware/audio_effect.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+
+class EffectDescriptor : public RefBase
+{
+public:
+ status_t dump(int fd);
+
+ int mIo; // io the effect is attached to
+ routing_strategy mStrategy; // routing strategy the effect is associated to
+ int mSession; // audio session the effect is on
+ effect_descriptor_t mDesc; // effect descriptor
+ bool mEnabled; // enabled state: CPU load being used or not
+};
+
+class EffectDescriptorCollection : public KeyedVector<int, sp<EffectDescriptor> >
+{
+public:
+ EffectDescriptorCollection();
+
+ status_t registerEffect(const effect_descriptor_t *desc, audio_io_handle_t io,
+ uint32_t strategy, int session, int id);
+ status_t unregisterEffect(int id);
+ status_t setEffectEnabled(int id, bool enabled);
+ uint32_t getMaxEffectsCpuLoad() const;
+ uint32_t getMaxEffectsMemory() const;
+ bool isNonOffloadableEffectEnabled();
+
+ status_t dump(int fd);
+
+private:
+ status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
+
+ uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+ uint32_t mTotalEffectsMemory; // current memory used by effects
+
+ /**
+ * 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;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
similarity index 69%
rename from services/audiopolicy/managerdefault/HwModule.h
rename to services/audiopolicy/common/managerdefinitions/include/HwModule.h
index f814dd9..92c3ea2 100644
--- a/services/audiopolicy/managerdefault/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -14,8 +14,20 @@
* limitations under the License.
*/
+#pragma once
+
+#include "DeviceDescriptor.h"
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
namespace android {
+class IOProfile;
+
class HwModule : public RefBase
{
public:
@@ -33,6 +45,8 @@
audio_devices_t device, String8 address);
status_t removeInputProfile(String8 name);
+ audio_module_handle_t getHandle() const { return mHandle; }
+
void dump(int fd);
const char *const mName; // base name of the audio HW module (primary, a2dp ...)
@@ -43,4 +57,18 @@
DeviceVector mDeclaredDevices; // devices declared in audio_policy.conf
};
+class HwModuleCollection : public Vector< sp<HwModule> >
+{
+public:
+ sp<HwModule> getModuleFromName(const char *name) const;
+
+ sp <HwModule> getModuleForDevice(audio_devices_t device) const;
+
+ sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name) const;
+
+ status_t dump(int fd) const;
+};
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
similarity index 94%
rename from services/audiopolicy/managerdefault/IOProfile.h
rename to services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 3317969..095e759 100644
--- a/services/audiopolicy/managerdefault/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -14,6 +14,13 @@
* limitations under the License.
*/
+#pragma once
+
+#include "AudioPort.h"
+#include "DeviceDescriptor.h"
+#include <utils/String8.h>
+#include <system/audio.h>
+
namespace android {
class HwModule;
diff --git a/services/audiopolicy/managerdefault/ApmImplDefinitions.h b/services/audiopolicy/common/managerdefinitions/include/SoundTriggerSession.h
similarity index 63%
copy from services/audiopolicy/managerdefault/ApmImplDefinitions.h
copy to services/audiopolicy/common/managerdefinitions/include/SoundTriggerSession.h
index 620979b..420e6d7 100644
--- a/services/audiopolicy/managerdefault/ApmImplDefinitions.h
+++ b/services/audiopolicy/common/managerdefinitions/include/SoundTriggerSession.h
@@ -14,19 +14,20 @@
* limitations under the License.
*/
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+
namespace android {
-enum routing_strategy {
- STRATEGY_MEDIA,
- STRATEGY_PHONE,
- STRATEGY_SONIFICATION,
- STRATEGY_SONIFICATION_RESPECTFUL,
- STRATEGY_DTMF,
- STRATEGY_ENFORCED_AUDIBLE,
- STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
- STRATEGY_ACCESSIBILITY,
- STRATEGY_REROUTING,
- NUM_STRATEGIES
+class SoundTriggerSessionCollection : public DefaultKeyedVector<audio_session_t, audio_io_handle_t>
+{
+public:
+ status_t releaseSession(audio_session_t session);
+
+ status_t acquireSession(audio_session_t session, audio_io_handle_t ioHandle);
};
-}; //namespace android
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
new file mode 100644
index 0000000..84db5ab
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <Volume.h>
+#include <utils/KeyedVector.h>
+#include <utils/StrongPointer.h>
+#include <utils/SortedVector.h>
+#include <hardware/audio.h>
+
+namespace android {
+
+// stream descriptor used for volume control
+class StreamDescriptor
+{
+public:
+ StreamDescriptor();
+
+ int getVolumeIndex(audio_devices_t device) const;
+ bool canBeMuted() const { return mCanBeMuted; }
+ void clearCurrentVolumeIndex();
+ void addCurrentVolumeIndex(audio_devices_t device, int index);
+ int getVolumeIndexMin() const { return mIndexMin; }
+ int getVolumeIndexMax() const { return mIndexMax; }
+ void setVolumeIndexMin(int volIndexMin);
+ void setVolumeIndexMax(int volIndexMax);
+
+ void dump(int fd) const;
+
+ void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point);
+ const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const
+ {
+ return mVolumeCurve[deviceCategory];
+ }
+
+private:
+ const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT];
+ KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
+ int mIndexMin; /**< min volume index. */
+ int mIndexMax; /**< max volume index. */
+ bool mCanBeMuted; /**< true is the stream can be muted. */
+};
+
+/**
+ * stream descriptors collection for volume control
+ */
+class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor>
+{
+public:
+ StreamDescriptorCollection();
+
+ void clearCurrentVolumeIndex(audio_stream_type_t stream);
+ void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index);
+
+ bool canBeMuted(audio_stream_type_t stream);
+
+ status_t dump(int fd) const;
+
+ void setVolumeCurvePoint(audio_stream_type_t stream,
+ Volume::device_category deviceCategory,
+ const VolumeCurvePoint *point);
+
+ const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream,
+ Volume::device_category deviceCategory) const;
+
+ void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin);
+ void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax);
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
similarity index 91%
rename from services/audiopolicy/managerdefault/audio_policy_conf.h
rename to services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index 2535a67..a393e3b 100644
--- a/services/audiopolicy/managerdefault/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-
-#ifndef ANDROID_AUDIO_POLICY_CONF_H
-#define ANDROID_AUDIO_POLICY_CONF_H
+#pragma once
/////////////////////////////////////////////////
@@ -53,9 +51,9 @@
// "formats" in outputs descriptors indicating that supported
// values should be queried after opening the output.
-#define DEVICES_TAG "devices"
-#define DEVICE_TYPE "type"
-#define DEVICE_ADDRESS "address"
+#define APM_DEVICES_TAG "devices"
+#define APM_DEVICE_TYPE "type"
+#define APM_DEVICE_ADDRESS "address"
#define MIXERS_TAG "mixers"
#define MIXER_TYPE "type"
@@ -71,7 +69,3 @@
#define GAIN_STEP_VALUE "step_value_mB"
#define GAIN_MIN_RAMP_MS "min_ramp_ms"
#define GAIN_MAX_RAMP_MS "max_ramp_ms"
-
-
-
-#endif // ANDROID_AUDIO_POLICY_CONF_H
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
new file mode 100644
index 0000000..fc7b0cc
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioGain"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "AudioGain.h"
+#include "StreamDescriptor.h"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <math.h>
+
+namespace android {
+
+AudioGain::AudioGain(int index, bool useInChannelMask)
+{
+ mIndex = index;
+ mUseInChannelMask = useInChannelMask;
+ memset(&mGain, 0, sizeof(struct audio_gain));
+}
+
+void AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+ config->index = mIndex;
+ config->mode = mGain.mode;
+ config->channel_mask = mGain.channel_mask;
+ if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ config->values[0] = mGain.default_value;
+ } else {
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ config->values[i] = mGain.default_value;
+ }
+ }
+ if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ config->ramp_duration_ms = mGain.min_ramp_ms;
+ }
+}
+
+status_t AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+ if ((config->mode & ~mGain.mode) != 0) {
+ return BAD_VALUE;
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+ if ((config->values[0] < mGain.min_value) ||
+ (config->values[0] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ } else {
+ if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+ return BAD_VALUE;
+ }
+ uint32_t numValues;
+ if (mUseInChannelMask) {
+ numValues = audio_channel_count_from_in_mask(config->channel_mask);
+ } else {
+ numValues = audio_channel_count_from_out_mask(config->channel_mask);
+ }
+ for (size_t i = 0; i < numValues; i++) {
+ if ((config->values[i] < mGain.min_value) ||
+ (config->values[i] > mGain.max_value)) {
+ return BAD_VALUE;
+ }
+ }
+ }
+ if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+ if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+ (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+ return BAD_VALUE;
+ }
+ }
+ return NO_ERROR;
+}
+
+void AudioGain::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
new file mode 100644
index 0000000..fa66728
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioInputDescriptor"
+//#define LOG_NDEBUG 0
+
+#include "AudioInputDescriptor.h"
+#include "IOProfile.h"
+#include "AudioGain.h"
+#include "HwModule.h"
+#include <media/AudioPolicy.h>
+#include <policy.h>
+
+namespace android {
+
+AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
+ : mId(0), mIoHandle(0),
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
+ mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
+{
+ if (profile != NULL) {
+ mSamplingRate = profile->pickSamplingRate();
+ mFormat = profile->pickFormat();
+ mChannelMask = profile->pickChannelMask();
+ if (profile->mGains.size() > 0) {
+ profile->mGains[0]->getDefaultConfig(&mGain);
+ }
+ }
+}
+
+void AudioInputDescriptor::setIoHandle(audio_io_handle_t ioHandle)
+{
+ mId = AudioPort::getNextUniqueId();
+ mIoHandle = ioHandle;
+}
+
+audio_module_handle_t AudioInputDescriptor::getModuleHandle() const
+{
+ return mProfile->getModuleHandle();
+}
+
+void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ ALOG_ASSERT(mProfile != 0,
+ "toAudioPortConfig() called on input with null profile %d", mIoHandle);
+ dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
+ AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
+ if (srcConfig != NULL) {
+ dstConfig->config_mask |= srcConfig->config_mask;
+ }
+
+ AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+ dstConfig->id = mId;
+ dstConfig->role = AUDIO_PORT_ROLE_SINK;
+ dstConfig->type = AUDIO_PORT_TYPE_MIX;
+ dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
+ dstConfig->ext.mix.handle = mIoHandle;
+ dstConfig->ext.mix.usecase.source = mInputSource;
+}
+
+void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
+{
+ ALOG_ASSERT(mProfile != 0, "toAudioPort() called on input with null profile %d", mIoHandle);
+
+ mProfile->toAudioPort(port);
+ port->id = mId;
+ toAudioPortConfig(&port->active_config);
+ port->ext.mix.hw_module = mProfile->mModule->mHandle;
+ port->ext.mix.handle = mIoHandle;
+ port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
+}
+
+status_t AudioInputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " ID: %d\n", mId);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+bool AudioInputCollection::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if (inputDescriptor->mRefCount == 0) {
+ continue;
+ }
+ if (inputDescriptor->mInputSource == (int)source) {
+ return true;
+ }
+ }
+ return false;
+}
+
+sp<AudioInputDescriptor> AudioInputCollection::getInputFromId(audio_port_handle_t id) const
+{
+ sp<AudioInputDescriptor> inputDesc = NULL;
+ for (size_t i = 0; i < size(); i++) {
+ inputDesc = valueAt(i);
+ if (inputDesc->mId == id) {
+ break;
+ }
+ }
+ return inputDesc;
+}
+
+uint32_t AudioInputCollection::activeInputsCount() const
+{
+ uint32_t count = 0;
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioInputDescriptor> desc = valueAt(i);
+ if (desc->mRefCount > 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioInputDescriptor> input_descriptor = valueAt(i);
+ if ((input_descriptor->mRefCount > 0)
+ && (!ignoreVirtualInputs || !is_virtual_input_device(input_descriptor->mDevice))) {
+ return keyAt(i);
+ }
+ }
+ return 0;
+}
+
+audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
+{
+ sp<AudioInputDescriptor> inputDesc = valueFor(handle);
+ audio_devices_t devices = inputDesc->mProfile->mSupportedDevices.types();
+ return devices;
+}
+
+status_t AudioInputCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nInputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Input %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
similarity index 61%
rename from services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp
rename to services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 4b85972..cdb5b51 100644
--- a/services/audiopolicy/managerdefault/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -17,12 +17,19 @@
#define LOG_TAG "APM::AudioOutputDescriptor"
//#define LOG_NDEBUG 0
-#include "AudioPolicyManager.h"
+#include "AudioOutputDescriptor.h"
+#include "IOProfile.h"
+#include "AudioGain.h"
+#include "HwModule.h"
+#include <media/AudioPolicy.h>
+
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
namespace android {
-AudioOutputDescriptor::AudioOutputDescriptor(
- const sp<IOProfile>& profile)
+AudioOutputDescriptor::AudioOutputDescriptor(const sp<IOProfile>& profile)
: mId(0), mIoHandle(0), mLatency(0),
mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
mPatchHandle(0),
@@ -49,6 +56,11 @@
}
}
+audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
+{
+ return mProfile->getModuleHandle();
+}
+
audio_devices_t AudioOutputDescriptor::device() const
{
if (isDuplicated()) {
@@ -58,6 +70,12 @@
}
}
+void AudioOutputDescriptor::setIoHandle(audio_io_handle_t ioHandle)
+{
+ mId = AudioPort::getNextUniqueId();
+ mIoHandle = ioHandle;
+}
+
uint32_t AudioOutputDescriptor::latency()
{
if (isDuplicated()) {
@@ -108,23 +126,15 @@
bool AudioOutputDescriptor::isActive(uint32_t inPastMs) const
{
- return isStrategyActive(NUM_STRATEGIES, inPastMs);
-}
-
-bool AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
- uint32_t inPastMs,
- nsecs_t sysTime) const
-{
- if ((sysTime == 0) && (inPastMs != 0)) {
+ nsecs_t sysTime = 0;
+ if (inPastMs != 0) {
sysTime = systemTime();
}
for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
if (i == AUDIO_STREAM_PATCH) {
continue;
}
- if (((AudioPolicyManager::getStrategy((audio_stream_type_t)i) == strategy) ||
- (NUM_STRATEGIES == strategy)) &&
- isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
+ if (isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
return true;
}
}
@@ -132,8 +142,8 @@
}
bool AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
- uint32_t inPastMs,
- nsecs_t sysTime) const
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
{
if (mRefCount[stream] != 0) {
return true;
@@ -216,6 +226,108 @@
return NO_ERROR;
}
+bool AudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < this->size(); i++) {
+ const sp<AudioOutputDescriptor> outputDesc = this->valueAt(i);
+ if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+bool AudioOutputCollection::isStreamActiveRemotely(audio_stream_type_t stream,
+ uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+ if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+ outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ // do not consider re routing (when the output is going to a dynamic policy)
+ // as "remote playback"
+ if (outputDesc->mPolicyMix == NULL) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+audio_io_handle_t AudioOutputCollection::getA2dpOutput() const
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+ if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ return this->keyAt(i);
+ }
+ }
+ return 0;
+}
+
+sp<AudioOutputDescriptor> AudioOutputCollection::getPrimaryOutput() const
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ return outputDesc;
+ }
+ }
+ return NULL;
+}
+
+sp<AudioOutputDescriptor> AudioOutputCollection::getOutputFromId(audio_port_handle_t id) const
+{
+ sp<AudioOutputDescriptor> outputDesc = NULL;
+ for (size_t i = 0; i < size(); i++) {
+ outputDesc = valueAt(i);
+ if (outputDesc->mId == id) {
+ break;
+ }
+ }
+ return outputDesc;
+}
+
+bool AudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
+{
+ for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+ if (s == (size_t) streamToIgnore) {
+ continue;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->mRefCount[s] != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+audio_devices_t AudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
+{
+ sp<AudioOutputDescriptor> outputDesc = valueFor(handle);
+ audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types();
+ return devices;
+}
+
+
+status_t AudioOutputCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
new file mode 100644
index 0000000..3a317fa
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPatch"
+//#define LOG_NDEBUG 0
+
+#include "AudioPatch.h"
+#include "AudioGain.h"
+#include "ConfigParsingUtils.h"
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+int32_t volatile AudioPatch::mNextUniqueId = 1;
+
+AudioPatch::AudioPatch(const struct audio_patch *patch, uid_t uid) :
+ mHandle(static_cast<audio_patch_handle_t>(android_atomic_inc(&mNextUniqueId))),
+ mPatch(*patch),
+ mUid(uid),
+ mAfPatchHandle(0)
+{
+}
+
+status_t AudioPatch::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
+ result.append(buffer);
+ for (size_t i = 0; i < mPatch.num_sources; i++) {
+ if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
+ mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ mPatch.sources[i].ext.device.type));
+ } else {
+ snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
+ mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
+ }
+ result.append(buffer);
+ }
+ snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
+ result.append(buffer);
+ for (size_t i = 0; i < mPatch.num_sinks; i++) {
+ if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
+ mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ mPatch.sinks[i].ext.device.type));
+ } else {
+ snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
+ mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
+ }
+ result.append(buffer);
+ }
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioPatchCollection::addAudioPatch(audio_patch_handle_t handle,
+ const sp<AudioPatch>& patch)
+{
+ ssize_t index = indexOfKey(handle);
+
+ if (index >= 0) {
+ ALOGW("addAudioPatch() patch %d already in", handle);
+ return ALREADY_EXISTS;
+ }
+ add(handle, patch);
+ ALOGV("addAudioPatch() handle %d af handle %d num_sources %d num_sinks %d source handle %d"
+ "sink handle %d",
+ handle, patch->mAfPatchHandle, patch->mPatch.num_sources, patch->mPatch.num_sinks,
+ patch->mPatch.sources[0].id, patch->mPatch.sinks[0].id);
+ return NO_ERROR;
+}
+
+status_t AudioPatchCollection::removeAudioPatch(audio_patch_handle_t handle)
+{
+ ssize_t index = indexOfKey(handle);
+
+ if (index < 0) {
+ ALOGW("removeAudioPatch() patch %d not in", handle);
+ return ALREADY_EXISTS;
+ }
+ ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->mAfPatchHandle);
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+status_t AudioPatchCollection::listAudioPatches(unsigned int *num_patches,
+ struct audio_patch *patches) const
+{
+ if (num_patches == NULL || (*num_patches != 0 && patches == NULL)) {
+ return BAD_VALUE;
+ }
+ ALOGV("listAudioPatches() num_patches %d patches %p available patches %zu",
+ *num_patches, patches, size());
+ if (patches == NULL) {
+ *num_patches = 0;
+ }
+
+ size_t patchesWritten = 0;
+ size_t patchesMax = *num_patches;
+ for (size_t i = 0; i < size() && patchesWritten < patchesMax; i++) {
+ const sp<AudioPatch> patch = valueAt(i);
+ patches[patchesWritten] = patch->mPatch;
+ patches[patchesWritten++].id = patch->mHandle;
+ ALOGV("listAudioPatches() patch %zu num_sources %d num_sinks %d",
+ i, patch->mPatch.num_sources, patch->mPatch.num_sinks);
+ }
+ *num_patches = size();
+
+ ALOGV("listAudioPatches() got %zu patches needed %d", patchesWritten, *num_patches);
+ return NO_ERROR;
+}
+
+status_t AudioPatchCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "\nAudio Patches:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, 2, i);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
new file mode 100644
index 0000000..84a53ebd
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyMix"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyMix.h"
+#include "HwModule.h"
+#include "AudioPort.h"
+#include "IOProfile.h"
+#include "AudioGain.h"
+#include <AudioOutputDescriptor.h>
+
+namespace android {
+
+void AudioPolicyMix::setOutput(sp<AudioOutputDescriptor> &output)
+{
+ mOutput = output;
+}
+
+const sp<AudioOutputDescriptor> &AudioPolicyMix::getOutput() const
+{
+ return mOutput;
+}
+
+void AudioPolicyMix::clearOutput()
+{
+ mOutput.clear();
+}
+
+void AudioPolicyMix::setMix(AudioMix &mix)
+{
+ mMix = mix;
+}
+
+android::AudioMix &AudioPolicyMix::getMix()
+{
+ return mMix;
+}
+
+status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix)
+{
+ ssize_t index = indexOfKey(address);
+ if (index >= 0) {
+ ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
+ return BAD_VALUE;
+ }
+ sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
+ policyMix->setMix(mix);
+ add(address, policyMix);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::unregisterMix(String8 address)
+{
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+ return BAD_VALUE;
+ }
+
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address,
+ sp<AudioPolicyMix> &policyMix) const
+{
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+ return BAD_VALUE;
+ }
+ policyMix = valueAt(index);
+ return NO_ERROR;
+}
+
+void AudioPolicyMixCollection::closeOutput(sp<AudioOutputDescriptor> &desc)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioPolicyMix> policyMix = valueAt(i);
+ if (policyMix->getOutput() == desc) {
+ policyMix->clearOutput();
+ }
+ }
+}
+
+status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
+ sp<AudioOutputDescriptor> &desc)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioPolicyMix> policyMix = valueAt(i);
+ AudioMix mix = policyMix->getMix();
+
+ if (mix.mMixType == MIX_TYPE_PLAYERS) {
+ for (size_t j = 0; j < mix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
+ (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
+ desc = policyMix->getOutput();
+ break;
+ }
+ if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = policyMix->getOutput();
+ break;
+ }
+ }
+ } else if (mix.mMixType == MIX_TYPE_RECORDERS) {
+ if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
+ strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = policyMix->getOutput();
+ }
+ }
+ if (desc != 0) {
+ desc->mPolicyMix = &mix;
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
+ audio_devices_t availDevices,
+ AudioMix **policyMix)
+{
+ for (size_t i = 0; i < size(); i++) {
+ AudioMix mix = valueAt(i)->getMix();
+
+ if (mix.mMixType != MIX_TYPE_RECORDERS) {
+ continue;
+ }
+ for (size_t j = 0; j < mix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mSource == inputSource) ||
+ (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mSource != inputSource)) {
+ if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ if (policyMix != NULL) {
+ *policyMix = &mix;
+ }
+ return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ }
+ }
+ }
+ return AUDIO_DEVICE_NONE;
+}
+
+status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix)
+{
+ if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
+ return BAD_VALUE;
+ }
+ String8 address(attr.tags + strlen("addr="));
+
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGW("getInputForAttr() no policy for address %s", address.string());
+ return BAD_VALUE;
+ }
+ sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
+ AudioMix mix = audioPolicyMix->getMix();
+
+ if (mix.mMixType != MIX_TYPE_PLAYERS) {
+ ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
+ return BAD_VALUE;
+ }
+ policyMix = &mix;
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/Ports.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
similarity index 90%
rename from services/audiopolicy/managerdefault/Ports.cpp
rename to services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 3e55cee..46a119e 100644
--- a/services/audiopolicy/managerdefault/Ports.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -14,30 +14,46 @@
* limitations under the License.
*/
-#define LOG_TAG "APM::Ports"
+#define LOG_TAG "APM::AudioPort"
//#define LOG_NDEBUG 0
-#include "AudioPolicyManager.h"
-
+#include "AudioPort.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include "ConfigParsingUtils.h"
#include "audio_policy_conf.h"
+#include <policy.h>
namespace android {
+int32_t volatile AudioPort::mNextUniqueId = 1;
+
// --- AudioPort class implementation
AudioPort::AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role, const sp<HwModule>& module) :
+ audio_port_role_t role, const sp<HwModule>& module) :
mName(name), mType(type), mRole(role), mModule(module), mFlags(0), mId(0)
{
mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
}
-void AudioPort::attach(const sp<HwModule>& module) {
- mId = AudioPolicyManager::nextUniqueId();
+void AudioPort::attach(const sp<HwModule>& module)
+{
+ mId = getNextUniqueId();
mModule = module;
}
+audio_port_handle_t AudioPort::getNextUniqueId()
+{
+ return static_cast<audio_port_handle_t>(android_atomic_inc(&mNextUniqueId));
+}
+
+audio_module_handle_t AudioPort::getModuleHandle() const
+{
+ return mModule->mHandle;
+}
+
void AudioPort::toAudioPort(struct audio_port *port) const
{
port->role = mRole;
@@ -785,60 +801,4 @@
}
}
-
-// --- AudioPatch class implementation
-
-AudioPatch::AudioPatch(audio_patch_handle_t handle,
- const struct audio_patch *patch, uid_t uid) :
- mHandle(handle), mPatch(*patch), mUid(uid), mAfPatchHandle(0)
-{}
-
-status_t AudioPatch::dump(int fd, int spaces, int index) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sAudio patch %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- handle: %2d\n", spaces, "", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- audio flinger handle: %2d\n", spaces, "", mAfPatchHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- %d sources:\n", spaces, "", mPatch.num_sources);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sources; i++) {
- if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- mPatch.sources[i].ext.device.type));
- } else {
- snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
- mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
- }
- result.append(buffer);
- }
- snprintf(buffer, SIZE, "%*s- %d sinks:\n", spaces, "", mPatch.num_sinks);
- result.append(buffer);
- for (size_t i = 0; i < mPatch.num_sinks; i++) {
- if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
- snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- mPatch.sinks[i].ext.device.type));
- } else {
- snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
- mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
- }
- result.append(buffer);
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
new file mode 100644
index 0000000..fe5bc5f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::ConfigParsingUtils"
+//#define LOG_NDEBUG 0
+
+#include "ConfigParsingUtils.h"
+#include "AudioGain.h"
+#include <hardware/audio.h>
+#include <utils/Log.h>
+#include <cutils/misc.h>
+
+namespace android {
+
+//static
+uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
+ size_t size,
+ const char *name)
+{
+ for (size_t i = 0; i < size; i++) {
+ if (strcmp(table[i].name, name) == 0) {
+ ALOGV("stringToEnum() found %s", table[i].name);
+ return table[i].value;
+ }
+ }
+ return 0;
+}
+
+//static
+const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
+ size_t size,
+ uint32_t value)
+{
+ for (size_t i = 0; i < size; i++) {
+ if (table[i].value == value) {
+ return table[i].name;
+ }
+ }
+ return "";
+}
+
+//static
+bool ConfigParsingUtils::stringToBool(const char *value)
+{
+ return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
+
+// --- audio_policy.conf file parsing
+//static
+uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
+{
+ uint32_t flag = 0;
+
+ // it is OK to cast name to non const here as we are not going to use it after
+ // strtok() modifies it
+ char *flagName = strtok(name, "|");
+ while (flagName != NULL) {
+ if (strlen(flagName) != 0) {
+ flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
+ ARRAY_SIZE(sOutputFlagNameToEnumTable),
+ flagName);
+ }
+ flagName = strtok(NULL, "|");
+ }
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+
+ return flag;
+}
+
+//static
+uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
+{
+ uint32_t flag = 0;
+
+ // it is OK to cast name to non const here as we are not going to use it after
+ // strtok() modifies it
+ char *flagName = strtok(name, "|");
+ while (flagName != NULL) {
+ if (strlen(flagName) != 0) {
+ flag |= stringToEnum(sInputFlagNameToEnumTable,
+ ARRAY_SIZE(sInputFlagNameToEnumTable),
+ flagName);
+ }
+ flagName = strtok(NULL, "|");
+ }
+ return flag;
+}
+
+//static
+audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
+{
+ uint32_t device = 0;
+
+ char *devName = strtok(name, "|");
+ while (devName != NULL) {
+ if (strlen(devName) != 0) {
+ device |= stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ devName);
+ }
+ devName = strtok(NULL, "|");
+ }
+ return device;
+}
+
+//static
+void ConfigParsingUtils::loadHwModule(cnode *root, HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnable)
+{
+ status_t status = NAME_NOT_FOUND;
+ cnode *node;
+ sp<HwModule> module = new HwModule(root->name);
+
+ node = config_find(root, DEVICES_TAG);
+ if (node != NULL) {
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading device %s", node->name);
+ status_t tmpStatus = module->loadDevice(node);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ node = config_find(root, OUTPUTS_TAG);
+ if (node != NULL) {
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading output %s", node->name);
+ status_t tmpStatus = module->loadOutput(node);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ node = config_find(root, INPUTS_TAG);
+ if (node != NULL) {
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading input %s", node->name);
+ status_t tmpStatus = module->loadInput(node);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ loadGlobalConfig(root, module, availableInputDevices, availableOutputDevices,
+ defaultOutputDevices, isSpeakerDrcEnable);
+
+ if (status == NO_ERROR) {
+ hwModules.add(module);
+ }
+}
+
+//static
+void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled)
+{
+ cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
+ if (node == NULL) {
+ return;
+ }
+
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModules() loading module %s", node->name);
+ loadHwModule(node, hwModules, availableInputDevices, availableOutputDevices,
+ defaultOutputDevices, isSpeakerDrcEnabled);
+ node = node->next;
+ }
+}
+
+//static
+void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& module,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevice,
+ bool &speakerDrcEnabled)
+{
+ cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+
+ if (node == NULL) {
+ return;
+ }
+ DeviceVector declaredDevices;
+ if (module != NULL) {
+ declaredDevices = module->mDeclaredDevices;
+ }
+
+ node = node->first_child;
+ while (node) {
+ if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
+ availableOutputDevices.loadDevicesFromName((char *)node->value,
+ declaredDevices);
+ ALOGV("loadGlobalConfig() Attached Output Devices %08x",
+ availableOutputDevices.types());
+ } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
+ audio_devices_t device = (audio_devices_t)stringToEnum(
+ sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ (char *)node->value);
+ if (device != AUDIO_DEVICE_NONE) {
+ defaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
+ } else {
+ ALOGW("loadGlobalConfig() default device not specified");
+ }
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
+ } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
+ availableInputDevices.loadDevicesFromName((char *)node->value,
+ declaredDevices);
+ ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
+ } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ speakerDrcEnabled = stringToBool((char *)node->value);
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+ } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
+ uint32_t major, minor;
+ sscanf((char *)node->value, "%u.%u", &major, &minor);
+ module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
+ ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
+ module->mHalVersion, major, minor);
+ }
+ node = node->next;
+ }
+}
+
+//static
+status_t ConfigParsingUtils::loadAudioPolicyConfig(const char *path,
+ HwModuleCollection &hwModules,
+ DeviceVector &availableInputDevices,
+ DeviceVector &availableOutputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled)
+{
+ cnode *root;
+ char *data;
+
+ data = (char *)load_file(path, NULL);
+ if (data == NULL) {
+ return -ENODEV;
+ }
+ root = config_node("", "");
+ config_load(root, data);
+
+ loadHwModules(root, hwModules,
+ availableInputDevices, availableOutputDevices,
+ defaultOutputDevices, isSpeakerDrcEnabled);
+ // legacy audio_policy.conf files have one global_configuration section
+ loadGlobalConfig(root, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY),
+ availableInputDevices, availableOutputDevices,
+ defaultOutputDevices, isSpeakerDrcEnabled);
+ config_free(root);
+ free(root);
+ free(data);
+
+ ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Devices.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
similarity index 83%
rename from services/audiopolicy/managerdefault/Devices.cpp
rename to services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 42e198c..7df7d75 100644
--- a/services/audiopolicy/managerdefault/Devices.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -17,18 +17,21 @@
#define LOG_TAG "APM::Devices"
//#define LOG_NDEBUG 0
-#include "AudioPolicyManager.h"
+#include "DeviceDescriptor.h"
+#include "AudioGain.h"
+#include "HwModule.h"
+#include "ConfigParsingUtils.h"
namespace android {
String8 DeviceDescriptor::emptyNameStr = String8("");
DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
- AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
- audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
- AUDIO_PORT_ROLE_SOURCE,
- NULL),
- mDeviceType(type), mAddress("")
+ AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE,
+ NULL),
+ mAddress(""), mDeviceType(type)
{
}
@@ -57,7 +60,7 @@
{
mDeviceTypes = AUDIO_DEVICE_NONE;
for(size_t i = 0; i < size(); i++) {
- mDeviceTypes |= itemAt(i)->mDeviceType;
+ mDeviceTypes |= itemAt(i)->type();
}
ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
}
@@ -82,7 +85,7 @@
refreshTypes();
}
} else {
- ALOGW("DeviceVector::add device %08x already in", item->mDeviceType);
+ ALOGW("DeviceVector::add device %08x already in", item->type());
ret = -1;
}
return ret;
@@ -94,7 +97,7 @@
ssize_t ret = indexOf(item);
if (ret < 0) {
- ALOGW("DeviceVector::remove device %08x not in", item->mDeviceType);
+ ALOGW("DeviceVector::remove device %08x not in", item->type());
} else {
ret = SortedVector::removeAt(ret);
if (ret >= 0) {
@@ -104,6 +107,17 @@
return ret;
}
+audio_devices_t DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
+{
+ audio_devices_t devices = AUDIO_DEVICE_NONE;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getModuleHandle() == moduleHandle) {
+ devices |= itemAt(i)->type();
+ }
+ }
+ return devices;
+}
+
void DeviceVector::loadDevicesFromType(audio_devices_t types)
{
DeviceVector deviceList;
@@ -151,7 +165,7 @@
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mDeviceType == type) {
+ if (itemAt(i)->type() == type) {
if (address == "" || itemAt(i)->mAddress == address) {
device = itemAt(i);
if (itemAt(i)->mAddress == address) {
@@ -189,7 +203,7 @@
devices.add(itemAt(i));
type &= ~curType;
ALOGV("DeviceVector::getDevicesFromType() for type %x found %p",
- itemAt(i)->mDeviceType, itemAt(i).get());
+ itemAt(i)->type(), itemAt(i).get());
}
}
return devices;
@@ -200,7 +214,7 @@
{
DeviceVector devices;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mDeviceType == type) {
+ if (itemAt(i)->type() == type) {
if (itemAt(i)->mAddress == address) {
devices.add(itemAt(i));
}
@@ -221,6 +235,26 @@
return device;
}
+
+status_t DeviceVector::dump(int fd, const String8 &direction) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ itemAt(i)->dump(fd, 2, i);
+ }
+ return NO_ERROR;
+}
+
+audio_policy_dev_state_t DeviceVector::getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const
+{
+ ssize_t index = indexOf(devDesc);
+ return index >= 0 ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE : AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
+}
+
void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
@@ -241,7 +275,7 @@
// without the test?
// This has been demonstrated to NOT be true (at start up)
// ALOG_ASSERT(mModule != NULL);
- dstConfig->ext.device.hw_module = mModule != NULL ? mModule->mHandle : NULL;
+ dstConfig->ext.device.hw_module = mModule != 0 ? mModule->mHandle : AUDIO_IO_HANDLE_NONE;
strncpy(dstConfig->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
new file mode 100644
index 0000000..33d838d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::EffectDescriptor"
+//#define LOG_NDEBUG 0
+
+#include "EffectDescriptor.h"
+#include <utils/String8.h>
+
+namespace android {
+
+status_t EffectDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " I/O: %d\n", mIo);
+ 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);
+ snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+EffectDescriptorCollection::EffectDescriptorCollection() :
+ mTotalEffectsCpuLoad(0),
+ mTotalEffectsMemory(0)
+{
+
+}
+
+status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+ ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+ desc->name, desc->memoryUsage);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsMemory += desc->memoryUsage;
+ ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
+ desc->name, io, strategy, session, id);
+ ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
+
+ sp<EffectDescriptor> effectDesc = new EffectDescriptor();
+ memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t));
+ effectDesc->mIo = io;
+ effectDesc->mStrategy = static_cast<routing_strategy>(strategy);
+ effectDesc->mSession = session;
+ effectDesc->mEnabled = false;
+
+ add(id, effectDesc);
+
+ return NO_ERROR;
+}
+
+status_t EffectDescriptorCollection::unregisterEffect(int id)
+{
+ ssize_t index = indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ sp<EffectDescriptor> effectDesc = valueAt(index);
+
+ setEffectEnabled(effectDesc, false);
+
+ if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
+ ALOGW("unregisterEffect() memory %d too big for total %d",
+ effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+ effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+ }
+ mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
+ ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
+ effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+
+ removeItem(id);
+
+ return NO_ERROR;
+}
+
+status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled)
+{
+ ssize_t index = indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ return setEffectEnabled(valueAt(index), enabled);
+}
+
+
+status_t EffectDescriptorCollection::setEffectEnabled(const sp<EffectDescriptor> &effectDesc,
+ bool enabled)
+{
+ if (enabled == effectDesc->mEnabled) {
+ ALOGV("setEffectEnabled(%s) effect already %s",
+ enabled?"true":"false", enabled?"enabled":"disabled");
+ return INVALID_OPERATION;
+ }
+
+ if (enabled) {
+ if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+ ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+ effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
+ } else {
+ if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
+ ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
+ effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+ effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+ }
+ mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
+ }
+ effectDesc->mEnabled = enabled;
+ return NO_ERROR;
+}
+
+bool EffectDescriptorCollection::isNonOffloadableEffectEnabled()
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<EffectDescriptor> effectDesc = valueAt(i);
+ if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) &&
+ ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+ ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
+ effectDesc->mDesc.name, effectDesc->mSession);
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t EffectDescriptorCollection::getMaxEffectsCpuLoad() const
+{
+ return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const
+{
+ return MAX_EFFECTS_MEMORY;
+}
+
+status_t EffectDescriptorCollection::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ 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 < size(); i++) {
+ snprintf(buffer, SIZE, "- Effect %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
similarity index 75%
rename from services/audiopolicy/managerdefault/HwModule.cpp
rename to services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index a04bdc8..0097d69 100644
--- a/services/audiopolicy/managerdefault/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -17,9 +17,13 @@
#define LOG_TAG "APM::HwModule"
//#define LOG_NDEBUG 0
-#include "AudioPolicyManager.h"
+#include "HwModule.h"
+#include "IOProfile.h"
+#include "AudioGain.h"
+#include "ConfigParsingUtils.h"
#include "audio_policy_conf.h"
#include <hardware/audio.h>
+#include <policy.h>
namespace android {
@@ -138,7 +142,7 @@
audio_devices_t type = AUDIO_DEVICE_NONE;
while (node) {
- if (strcmp(node->name, DEVICE_TYPE) == 0) {
+ if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
type = ConfigParsingUtils::parseDeviceNames((char *)node->value);
break;
}
@@ -154,7 +158,7 @@
node = root->first_child;
while (node) {
- if (strcmp(node->name, DEVICE_ADDRESS) == 0) {
+ if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
deviceDesc->mAddress = String8((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
if (audio_is_input_device(type)) {
@@ -276,4 +280,92 @@
}
}
+sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
+{
+ sp <HwModule> module;
+
+ for (size_t i = 0; i < size(); i++)
+ {
+ if (strcmp(itemAt(i)->mName, name) == 0) {
+ return itemAt(i);
+ }
+ }
+ return module;
+}
+
+
+sp <HwModule> HwModuleCollection::getModuleForDevice(audio_devices_t device) const
+{
+ sp <HwModule> module;
+
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->mHandle == 0) {
+ continue;
+ }
+ if (audio_is_output_device(device)) {
+ for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
+ {
+ if (itemAt(i)->mOutputProfiles[j]->mSupportedDevices.types() & device) {
+ return itemAt(i);
+ }
+ }
+ } else {
+ for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
+ if (itemAt(i)->mInputProfiles[j]->mSupportedDevices.types() &
+ device & ~AUDIO_DEVICE_BIT_IN) {
+ return itemAt(i);
+ }
+ }
+ }
+ }
+ return module;
+}
+
+sp<DeviceDescriptor> HwModuleCollection::getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name) const
+{
+ String8 address = (device_address == NULL) ? String8("") : String8(device_address);
+ // handle legacy remote submix case where the address was not always specified
+ if (device_distinguishes_on_address(device) && (address.length() == 0)) {
+ address = String8("0");
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ const sp<HwModule> hwModule = itemAt(i);
+ if (hwModule->mHandle == 0) {
+ continue;
+ }
+ DeviceVector deviceList =
+ hwModule->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
+ if (!deviceList.isEmpty()) {
+ return deviceList.itemAt(0);
+ }
+ deviceList = hwModule->mDeclaredDevices.getDevicesFromType(device);
+ if (!deviceList.isEmpty()) {
+ return deviceList.itemAt(0);
+ }
+ }
+
+ sp<DeviceDescriptor> devDesc =
+ new DeviceDescriptor(String8(device_name != NULL ? device_name : ""), device);
+ devDesc->mAddress = address;
+ return devDesc;
+}
+
+status_t HwModuleCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nHW Modules dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd);
+ }
+ return NO_ERROR;
+}
+
} //namespace android
diff --git a/services/audiopolicy/managerdefault/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
similarity index 82%
rename from services/audiopolicy/managerdefault/IOProfile.cpp
rename to services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 538ac1a..376dd22 100644
--- a/services/audiopolicy/managerdefault/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -17,7 +17,9 @@
#define LOG_TAG "APM::IOProfile"
//#define LOG_NDEBUG 0
-#include "AudioPolicyManager.h"
+#include "IOProfile.h"
+#include "HwModule.h"
+#include "AudioGain.h"
namespace android {
@@ -35,19 +37,27 @@
// Sampling rate, format and channel mask must be specified in order to
// get a valid a match
bool IOProfile::isCompatibleProfile(audio_devices_t device,
- String8 address,
- uint32_t samplingRate,
- uint32_t *updatedSamplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- uint32_t flags) const
+ String8 address,
+ uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ uint32_t flags) const
{
const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
ALOG_ASSERT(isPlaybackThread != isRecordThread);
- if (device != AUDIO_DEVICE_NONE && mSupportedDevices.getDevice(device, address) == 0) {
- return false;
+
+ if (device != AUDIO_DEVICE_NONE) {
+ // just check types if multiple devices are selected
+ if (popcount(device & ~AUDIO_DEVICE_BIT_IN) > 1) {
+ if ((mSupportedDevices.types() & device) != device) {
+ return false;
+ }
+ } else if (mSupportedDevices.getDevice(device, address) == 0) {
+ return false;
+ }
}
if (samplingRate == 0) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
new file mode 100644
index 0000000..8ca3ae0
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/SoundTriggerSession.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::SoundTriggerSession"
+//#define LOG_NDEBUG 0
+
+#include "SoundTriggerSession.h"
+
+
+namespace android {
+
+status_t SoundTriggerSessionCollection::acquireSession(audio_session_t session,
+ audio_io_handle_t ioHandle)
+{
+ add(session, ioHandle);
+
+ return NO_ERROR;
+}
+
+status_t SoundTriggerSessionCollection::releaseSession(audio_session_t session)
+{
+ ssize_t index = indexOfKey(session);
+ if (index < 0) {
+ ALOGW("acquireSoundTriggerSession() session %d not registered", session);
+ return BAD_VALUE;
+ }
+
+ removeItem(session);
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
new file mode 100644
index 0000000..b682e2c
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::Volumes"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "StreamDescriptor.h"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// --- StreamDescriptor class implementation
+
+StreamDescriptor::StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int StreamDescriptor::getVolumeIndex(audio_devices_t device) const
+{
+ device = Volume::getDeviceForVolume(device);
+ // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+ if (mIndexCur.indexOfKey(device) < 0) {
+ device = AUDIO_DEVICE_OUT_DEFAULT;
+ }
+ return mIndexCur.valueFor(device);
+}
+
+void StreamDescriptor::clearCurrentVolumeIndex()
+{
+ mIndexCur.clear();
+}
+
+void StreamDescriptor::addCurrentVolumeIndex(audio_devices_t device, int index)
+{
+ mIndexCur.add(device, index);
+}
+
+void StreamDescriptor::setVolumeIndexMin(int volIndexMin)
+{
+ mIndexMin = volIndexMin;
+}
+
+void StreamDescriptor::setVolumeIndexMax(int volIndexMax)
+{
+ mIndexMax = volIndexMax;
+}
+
+void StreamDescriptor::setVolumeCurvePoint(Volume::device_category deviceCategory,
+ const VolumeCurvePoint *point)
+{
+ mVolumeCurve[deviceCategory] = point;
+}
+
+void StreamDescriptor::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s %02d %02d ",
+ mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+ result.append(buffer);
+ for (size_t i = 0; i < mIndexCur.size(); i++) {
+ snprintf(buffer, SIZE, "%04x : %02d, ",
+ mIndexCur.keyAt(i),
+ mIndexCur.valueAt(i));
+ result.append(buffer);
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+StreamDescriptorCollection::StreamDescriptorCollection()
+{
+ for (size_t stream = 0 ; stream < AUDIO_STREAM_CNT; stream++) {
+ add(static_cast<audio_stream_type_t>(stream), StreamDescriptor());
+ }
+}
+
+bool StreamDescriptorCollection::canBeMuted(audio_stream_type_t stream)
+{
+ return valueAt(stream).canBeMuted();
+}
+
+void StreamDescriptorCollection::clearCurrentVolumeIndex(audio_stream_type_t stream)
+{
+ editValueAt(stream).clearCurrentVolumeIndex();
+}
+
+void StreamDescriptorCollection::addCurrentVolumeIndex(audio_stream_type_t stream,
+ audio_devices_t device, int index)
+{
+ editValueAt(stream).addCurrentVolumeIndex(device, index);
+}
+
+void StreamDescriptorCollection::setVolumeCurvePoint(audio_stream_type_t stream,
+ Volume::device_category deviceCategory,
+ const VolumeCurvePoint *point)
+{
+ editValueAt(stream).setVolumeCurvePoint(deviceCategory, point);
+}
+
+const VolumeCurvePoint *StreamDescriptorCollection::getVolumeCurvePoint(audio_stream_type_t stream,
+ Volume::device_category deviceCategory) const
+{
+ return valueAt(stream).getVolumeCurvePoint(deviceCategory);
+}
+
+void StreamDescriptorCollection::setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin)
+{
+ return editValueAt(stream).setVolumeIndexMin(volIndexMin);
+}
+
+void StreamDescriptorCollection::setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax)
+{
+ return editValueAt(stream).setVolumeIndexMax(volIndexMax);
+}
+
+status_t StreamDescriptorCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nStreams dump:\n");
+ write(fd, buffer, strlen(buffer));
+ snprintf(buffer, SIZE,
+ " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, " %02zu ", i);
+ write(fd, buffer, strlen(buffer));
+ valueAt(i).dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
new file mode 100755
index 0000000..eadaa77
--- /dev/null
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AudioPolicyManagerObserver.h>
+#include <RoutingStrategy.h>
+#include <Volume.h>
+#include <HwModule.h>
+#include <DeviceDescriptor.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+/**
+ * This interface is dedicated to the policy manager that a Policy Engine shall implement.
+ */
+class AudioPolicyManagerInterface
+{
+public:
+ /**
+ * Checks if the engine was correctly initialized.
+ *
+ * @return NO_ERROR if initialization has been done correctly, error code otherwise..
+ */
+ virtual status_t initCheck() = 0;
+
+ /**
+ * Sets the Manager observer that allows the engine to retrieve information on collection
+ * of devices, streams, HwModules, ...
+ *
+ * @param[in] observer handle on the manager.
+ */
+ virtual void setObserver(AudioPolicyManagerObserver *observer) = 0;
+
+ /**
+ * Get the input device selected for a given input source.
+ *
+ * @param[in] inputSource to get the selected input device associated to
+ *
+ * @return selected input device for the given input source, may be none if error.
+ */
+ virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const = 0;
+
+ /**
+ * Get the output device associated to a given strategy.
+ *
+ * @param[in] stream type for which the selected ouput device is requested.
+ *
+ * @return selected ouput device for the given strategy, may be none if error.
+ */
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy stategy) const = 0;
+
+ /**
+ * Get the strategy selected for a given stream type.
+ *
+ * @param[in] stream: for which the selected strategy followed by is requested.
+ *
+ * @return strategy to be followed.
+ */
+ virtual routing_strategy getStrategyForStream(audio_stream_type_t stream) = 0;
+
+ /**
+ * Get the strategy selected for a given usage.
+ *
+ * @param[in] usage to get the selected strategy followed by.
+ *
+ * @return strategy to be followed.
+ */
+ virtual routing_strategy getStrategyForUsage(audio_usage_t usage) = 0;
+
+ /**
+ * Set the Telephony Mode.
+ *
+ * @param[in] mode: Android Phone state (normal, ringtone, csv, in communication)
+ *
+ * @return NO_ERROR if Telephony Mode set correctly, error code otherwise.
+ */
+ virtual status_t setPhoneState(audio_mode_t mode) = 0;
+
+ /**
+ * Get the telephony Mode
+ *
+ * @return the current telephony mode
+ */
+ virtual audio_mode_t getPhoneState() const = 0;
+
+ /**
+ * Set Force Use config for a given usage.
+ *
+ * @param[in] usage for which a configuration shall be forced.
+ * @param[in] config wished to be forced for the given usage.
+ *
+ * @return NO_ERROR if the Force Use config was set correctly, error code otherwise (e.g. config not
+ * allowed a given usage...)
+ */
+ virtual status_t setForceUse(audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config) = 0;
+
+ /**
+ * Get Force Use config for a given usage.
+ *
+ * @param[in] usage for which a configuration shall be forced.
+ *
+ * @return config wished to be forced for the given usage.
+ */
+ virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const = 0;
+
+ /**
+ * Set the connection state of device(s).
+ *
+ * @param[in] devDesc for which the state has changed.
+ * @param[in] state of availability of this(these) device(s).
+ *
+ * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+ */
+ virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state) = 0;
+
+ /**
+ * Translate a volume index given by the UI to an amplification value for a stream type
+ * and a device category.
+ *
+ * @param[in] deviceCategory for which the conversion is requested.
+ * @param[in] stream type for which the conversion is requested.
+ * @param[in] indexInUi index received from the UI to be translated.
+ *
+ * @return amplification value matching the UI index for this given device and stream.
+ */
+ virtual float volIndexToAmpl(Volume::device_category deviceCategory, audio_stream_type_t stream,
+ int indexInUi) = 0;
+
+ /**
+ * Initialize the min / max index of volume applicable for a given stream type. These indexes
+ * will be used upon conversion of UI index to volume amplification.
+ *
+ * @param[in] stream type for which the indexes need to be set
+ * @param[in] indexMin Minimum index allowed for this stream.
+ * @param[in] indexMax Maximum index allowed for this stream.
+ */
+ virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0;
+
+ /**
+ * Initialize volume curves for each strategy and device category
+ *
+ * @param[in] isSpeakerDrcEnabled true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER
+ path to boost soft sounds, used to adjust volume curves accordingly
+ */
+ virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled) = 0;
+
+protected:
+ virtual ~AudioPolicyManagerInterface() {}
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
new file mode 100755
index 0000000..4f5427e
--- /dev/null
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AudioGain.h>
+#include <AudioPort.h>
+#include <AudioPatch.h>
+#include <IOProfile.h>
+#include <DeviceDescriptor.h>
+#include <AudioInputDescriptor.h>
+#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
+#include <SoundTriggerSession.h>
+#include <StreamDescriptor.h>
+
+namespace android {
+
+/**
+ * This interface is an observer that the manager shall implement to allows e.g. the engine
+ * to access to policy pillars elements (like output / input descritors collections,
+ * HwModule collections, AudioMix, ...
+ */
+class AudioPolicyManagerObserver
+{
+public:
+ virtual const AudioPatchCollection &getAudioPatches() const = 0;
+
+ virtual const SoundTriggerSessionCollection &getSoundTriggerSessionCollection() const = 0;
+
+ virtual const AudioPolicyMixCollection &getAudioPolicyMixCollection() const = 0;
+
+ virtual const AudioOutputCollection &getOutputs() const = 0;
+
+ virtual const AudioInputCollection &getInputs() const = 0;
+
+ virtual const DeviceVector &getAvailableOutputDevices() const = 0;
+
+ virtual const DeviceVector &getAvailableInputDevices() const = 0;
+
+ virtual StreamDescriptorCollection &getStreamDescriptors() = 0;
+
+ virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const = 0;
+
+protected:
+ virtual ~AudioPolicyManagerObserver() {}
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
new file mode 100755
index 0000000..b0ae835
--- /dev/null
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -0,0 +1,48 @@
+LOCAL_PATH := $(call my-dir)
+
+# Component build
+#######################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/Engine.cpp \
+ src/EngineInstance.cpp \
+ src/Gains.cpp \
+
+
+audio_policy_engine_includes_common := \
+ $(LOCAL_PATH)/include \
+ $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Werror \
+ -Wextra \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(audio_policy_engine_includes_common)
+
+LOCAL_C_INCLUDES := \
+ $(audio_policy_engine_includes_common) \
+ $(TARGET_OUT_HEADERS)/hw \
+ $(call include-path-for, frameworks-av) \
+ $(call include-path-for, audio-utils) \
+ $(call include-path-for, bionic) \
+ $(TOPDIR)frameworks/av/services/audiopolicy/common/include
+
+
+LOCAL_MODULE := libaudiopolicyenginedefault
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper \
+ libaudiopolicycomponents
+
+LOCAL_SHARED_LIBRARIES += \
+ libcutils \
+ libutils \
+ libaudioutils \
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h b/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h
new file mode 100755
index 0000000..1e329f0
--- /dev/null
+++ b/services/audiopolicy/enginedefault/include/AudioPolicyEngineInstance.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+class AudioPolicyManagerInterface;
+
+namespace android
+{
+namespace audio_policy
+{
+
+class Engine;
+
+class EngineInstance
+{
+protected:
+ EngineInstance();
+
+public:
+ virtual ~EngineInstance();
+
+ /**
+ * Get Audio Policy Engine instance.
+ *
+ * @return pointer to Route Manager Instance object.
+ */
+ static EngineInstance *getInstance();
+
+ /**
+ * Interface query.
+ * The first client of an interface of the policy engine will start the singleton.
+ *
+ * @tparam RequestedInterface: interface that the client is wishing to retrieve.
+ *
+ * @return interface handle.
+ */
+ template <class RequestedInterface>
+ RequestedInterface *queryInterface() const;
+
+protected:
+ /**
+ * Get Audio Policy Engine instance.
+ *
+ * @return Audio Policy Engine singleton.
+ */
+ Engine *getEngine() const;
+
+private:
+ /* Copy facilities are put private to disable copy. */
+ EngineInstance(const EngineInstance &object);
+ EngineInstance &operator=(const EngineInstance &object);
+};
+
+/**
+ * Limit template instantation to supported type interfaces.
+ * Compile time error will claim if invalid interface is requested.
+ */
+template <>
+AudioPolicyManagerInterface *EngineInstance::queryInterface() const;
+
+} // namespace audio_policy
+} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
new file mode 100755
index 0000000..b4d7246
--- /dev/null
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyEngine"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "Engine.h"
+#include "Gains.h"
+#include <AudioPolicyManagerObserver.h>
+#include <AudioPort.h>
+#include <IOProfile.h>
+#include <policy.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+
+namespace android
+{
+namespace audio_policy
+{
+
+Engine::Engine()
+ : mManagerInterface(this),
+ mPhoneState(AUDIO_MODE_NORMAL),
+ mApmObserver(NULL)
+{
+ for (int i = 0; i < AUDIO_POLICY_FORCE_USE_CNT; i++) {
+ mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
+ }
+}
+
+Engine::~Engine()
+{
+}
+
+void Engine::setObserver(AudioPolicyManagerObserver *observer)
+{
+ ALOG_ASSERT(observer != NULL, "Invalid Audio Policy Manager observer");
+ mApmObserver = observer;
+}
+
+status_t Engine::initCheck()
+{
+ return (mApmObserver != NULL) ? NO_ERROR : NO_INIT;
+}
+
+float Engine::volIndexToAmpl(Volume::device_category category, audio_stream_type_t streamType,
+ int indexInUi)
+{
+ const StreamDescriptor &streamDesc = mApmObserver->getStreamDescriptors().valueAt(streamType);
+ return Gains::volIndexToAmpl(category, streamDesc, indexInUi);
+}
+
+status_t Engine::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
+{
+ ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ if (indexMin < 0 || indexMin >= indexMax) {
+ ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d",
+ stream , indexMin, indexMax);
+ return BAD_VALUE;
+ }
+ mApmObserver->getStreamDescriptors().setVolumeIndexMin(stream, indexMin);
+ mApmObserver->getStreamDescriptors().setVolumeIndexMax(stream, indexMax);
+ return NO_ERROR;
+}
+
+void Engine::initializeVolumeCurves(bool isSpeakerDrcEnabled)
+{
+ StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
+
+ for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+ for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
+ streams.setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
+ static_cast<Volume::device_category>(j),
+ Gains::sVolumeProfiles[i][j]);
+ }
+ }
+
+ // Check availability of DRC on speaker path: if available, override some of the speaker curves
+ if (isSpeakerDrcEnabled) {
+ streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sDefaultSystemVolumeCurveDrc);
+ streams.setVolumeCurvePoint(AUDIO_STREAM_RING, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerSonificationVolumeCurveDrc);
+ streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerMediaVolumeCurveDrc);
+ streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, Volume::DEVICE_CATEGORY_SPEAKER,
+ Gains::sSpeakerMediaVolumeCurveDrc);
+ }
+}
+
+
+status_t Engine::setPhoneState(audio_mode_t state)
+{
+ ALOGV("setPhoneState() state %d", state);
+
+ if (state < 0 || state >= AUDIO_MODE_CNT) {
+ ALOGW("setPhoneState() invalid state %d", state);
+ return BAD_VALUE;
+ }
+
+ if (state == mPhoneState ) {
+ ALOGW("setPhoneState() setting same state %d", state);
+ return BAD_VALUE;
+ }
+
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+ StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
+ // are we entering or starting a call
+ if (!is_state_in_call(oldState) && is_state_in_call(state)) {
+ ALOGV(" Entering call in setPhoneState()");
+ for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
+ streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
+ Gains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]);
+ }
+ } else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
+ ALOGV(" Exiting call in setPhoneState()");
+ for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
+ streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
+ Gains::sVolumeProfiles[AUDIO_STREAM_DTMF][j]);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config)
+{
+ switch(usage) {
+ case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+ if (config != AUDIO_POLICY_FORCE_SPEAKER && config != AUDIO_POLICY_FORCE_BT_SCO &&
+ config != AUDIO_POLICY_FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return BAD_VALUE;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AUDIO_POLICY_FORCE_FOR_MEDIA:
+ if (config != AUDIO_POLICY_FORCE_HEADPHONES && config != AUDIO_POLICY_FORCE_BT_A2DP &&
+ config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+ config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
+ config != AUDIO_POLICY_FORCE_DIGITAL_DOCK && config != AUDIO_POLICY_FORCE_NONE &&
+ config != AUDIO_POLICY_FORCE_NO_BT_A2DP && config != AUDIO_POLICY_FORCE_SPEAKER ) {
+ ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return BAD_VALUE;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AUDIO_POLICY_FORCE_FOR_RECORD:
+ if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+ config != AUDIO_POLICY_FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return BAD_VALUE;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AUDIO_POLICY_FORCE_FOR_DOCK:
+ if (config != AUDIO_POLICY_FORCE_NONE && config != AUDIO_POLICY_FORCE_BT_CAR_DOCK &&
+ config != AUDIO_POLICY_FORCE_BT_DESK_DOCK &&
+ config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+ config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
+ config != AUDIO_POLICY_FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ mForceUse[usage] = config;
+ break;
+ case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+ if (config != AUDIO_POLICY_FORCE_NONE &&
+ config != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ mForceUse[usage] = config;
+ break;
+ case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
+ if (config != AUDIO_POLICY_FORCE_NONE &&
+ config != AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d forHDMI_SYSTEM_AUDIO", config);
+ }
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+ return NO_ERROR;
+}
+
+routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream)
+{
+ // stream to strategy mapping
+ switch (stream) {
+ case AUDIO_STREAM_VOICE_CALL:
+ case AUDIO_STREAM_BLUETOOTH_SCO:
+ return STRATEGY_PHONE;
+ case AUDIO_STREAM_RING:
+ case AUDIO_STREAM_ALARM:
+ return STRATEGY_SONIFICATION;
+ case AUDIO_STREAM_NOTIFICATION:
+ return STRATEGY_SONIFICATION_RESPECTFUL;
+ case AUDIO_STREAM_DTMF:
+ return STRATEGY_DTMF;
+ default:
+ ALOGE("unknown stream type %d", stream);
+ case AUDIO_STREAM_SYSTEM:
+ // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+ // while key clicks are played produces a poor result
+ case AUDIO_STREAM_MUSIC:
+ return STRATEGY_MEDIA;
+ case AUDIO_STREAM_ENFORCED_AUDIBLE:
+ return STRATEGY_ENFORCED_AUDIBLE;
+ case AUDIO_STREAM_TTS:
+ return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ case AUDIO_STREAM_ACCESSIBILITY:
+ return STRATEGY_ACCESSIBILITY;
+ case AUDIO_STREAM_REROUTING:
+ return STRATEGY_REROUTING;
+ }
+}
+
+routing_strategy Engine::getStrategyForUsage(audio_usage_t usage)
+{
+ const AudioOutputCollection &outputs = mApmObserver->getOutputs();
+
+ // usage to strategy mapping
+ switch (usage) {
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ if (outputs.isStreamActive(AUDIO_STREAM_RING) ||
+ outputs.isStreamActive(AUDIO_STREAM_ALARM)) {
+ return STRATEGY_SONIFICATION;
+ }
+ if (isInCall()) {
+ return STRATEGY_PHONE;
+ }
+ return STRATEGY_ACCESSIBILITY;
+
+ case AUDIO_USAGE_MEDIA:
+ case AUDIO_USAGE_GAME:
+ case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+ return STRATEGY_MEDIA;
+
+ case AUDIO_USAGE_VOICE_COMMUNICATION:
+ return STRATEGY_PHONE;
+
+ case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ return STRATEGY_DTMF;
+
+ case AUDIO_USAGE_ALARM:
+ case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+ return STRATEGY_SONIFICATION;
+
+ case AUDIO_USAGE_NOTIFICATION:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ case AUDIO_USAGE_NOTIFICATION_EVENT:
+ return STRATEGY_SONIFICATION_RESPECTFUL;
+
+ case AUDIO_USAGE_UNKNOWN:
+ default:
+ return STRATEGY_MEDIA;
+ }
+}
+
+audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
+{
+ const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices();
+ const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices();
+
+ const AudioOutputCollection &outputs = mApmObserver->getOutputs();
+
+ uint32_t device = AUDIO_DEVICE_NONE;
+ uint32_t availableOutputDevicesType = availableOutputDevices.types();
+
+ switch (strategy) {
+
+ case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ if (!device) {
+ ALOGE("getDeviceForStrategy() no device found for "\
+ "STRATEGY_TRANSMITTED_THROUGH_SPEAKER");
+ }
+ break;
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+ } else if (outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing on a remote device, use the the sonification behavior.
+ // Note that we test this usecase before testing if media is playing because
+ // the isStreamActive() method only informs about the activity of a stream, not
+ // if it's for local playback. Note also that we use the same delay between both tests
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+ //user "safe" speaker if available instead of normal speaker to avoid triggering
+ //other acoustic safety mechanisms for notification
+ if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+ device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ } else if (outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing (or has recently played), use the same device
+ device = getDeviceForStrategy(STRATEGY_MEDIA);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION);
+ //user "safe" speaker if available instead of normal speaker to avoid triggering
+ //other acoustic safety mechanisms for notification
+ if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
+ device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ }
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // Force use of only devices on primary output if:
+ // - in call AND
+ // - cannot route from voice call RX OR
+ // - audio HAL version is < 3.0 and TX device is on the primary HW module
+ if (getPhoneState() == AUDIO_MODE_IN_CALL) {
+ audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+ sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
+ audio_devices_t availPrimaryInputDevices =
+ availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+ audio_devices_t availPrimaryOutputDevices =
+ primaryOutput->supportedDevices() & availableOutputDevices.types();
+
+ if (((availableInputDevices.types() &
+ AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
+ (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+ (primaryOutput->getAudioPort()->mModule->mHalVersion <
+ AUDIO_DEVICE_API_VERSION_3_0))) {
+ availableOutputDevicesType = availPrimaryOutputDevices;
+ }
+ }
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
+ case AUDIO_POLICY_FORCE_BT_SCO:
+ if (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (!isInCall() &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (outputs.getA2dpOutput() != 0)) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ if (!isInCall()) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mApmObserver->getDefaultOutputDevice()->type();
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AUDIO_POLICY_FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (!isInCall() &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (outputs.getA2dpOutput() != 0)) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ if (!isInCall()) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
+ if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mApmObserver->getDefaultOutputDevice()->type();
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now
+ case STRATEGY_ACCESSIBILITY:
+ if (strategy == STRATEGY_ACCESSIBILITY) {
+ // do not route accessibility prompts to a digital output currently configured with a
+ // compressed format as they would likely not be mixed and dropped.
+ for (size_t i = 0; i < outputs.size(); i++) {
+ sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
+ audio_devices_t devices = desc->device() &
+ (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
+ if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
+ devices != AUDIO_DEVICE_NONE) {
+ availableOutputDevicesType = availableOutputDevices.types() & ~devices;
+ }
+ }
+ }
+ // FALL THROUGH
+
+ case STRATEGY_REROUTING:
+ case STRATEGY_MEDIA: {
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
+ device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+ (outputs.getA2dpOutput() != 0)) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE)) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+ int device3 = AUDIO_DEVICE_NONE;
+ if (strategy == STRATEGY_MEDIA) {
+ // ARC, SPDIF and AUX_LINE can co-exist with others.
+ device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
+ device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
+ device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
+ }
+
+ device2 |= device3;
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+ device |= device2;
+
+ // If hdmi system audio mode is on, remove speaker out of output list.
+ if ((strategy == STRATEGY_MEDIA) &&
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] ==
+ AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
+ device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+ if (device) break;
+ device = mApmObserver->getDefaultOutputDevice()->type();
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+
+audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
+{
+ const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices();
+ const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices();
+ const AudioOutputCollection &outputs = mApmObserver->getOutputs();
+ audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ switch (inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ break;
+ }
+ break;
+
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&
+ (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ // Allow only use of devices on primary input if in call and HAL does not support routing
+ // to voice call path.
+ if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
+ (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
+ sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
+ availableDeviceTypes =
+ availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle())
+ & ~AUDIO_DEVICE_BIT_IN;
+ }
+
+ switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
+ case AUDIO_POLICY_FORCE_BT_SCO:
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ break;
+ }
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+
+ case AUDIO_POLICY_FORCE_SPEAKER:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ }
+ break;
+
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_HOTWORD:
+ if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
+ availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ case AUDIO_SOURCE_FM_TUNER:
+ if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
+ device = AUDIO_DEVICE_IN_FM_TUNER;
+ }
+ break;
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+template <>
+AudioPolicyManagerInterface *Engine::queryInterface()
+{
+ return &mManagerInterface;
+}
+
+} // namespace audio_policy
+} // namespace android
+
+
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
new file mode 100755
index 0000000..f44556c
--- /dev/null
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+
+#include "AudioPolicyManagerInterface.h"
+#include "Gains.h"
+#include <AudioGain.h>
+#include <policy.h>
+
+namespace android
+{
+
+class AudioPolicyManagerObserver;
+
+namespace audio_policy
+{
+
+class Engine
+{
+public:
+ Engine();
+ virtual ~Engine();
+
+ template <class RequestedInterface>
+ RequestedInterface *queryInterface();
+
+private:
+ /// Interface members
+ class ManagerInterfaceImpl : public AudioPolicyManagerInterface
+ {
+ public:
+ ManagerInterfaceImpl(Engine *policyEngine)
+ : mPolicyEngine(policyEngine) {}
+
+ virtual void setObserver(AudioPolicyManagerObserver *observer)
+ {
+ mPolicyEngine->setObserver(observer);
+ }
+ virtual status_t initCheck()
+ {
+ return mPolicyEngine->initCheck();
+ }
+ virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const
+ {
+ return mPolicyEngine->getDeviceForInputSource(inputSource);
+ }
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy) const
+ {
+ return mPolicyEngine->getDeviceForStrategy(strategy);
+ }
+ virtual routing_strategy getStrategyForStream(audio_stream_type_t stream)
+ {
+ return mPolicyEngine->getStrategyForStream(stream);
+ }
+ virtual routing_strategy getStrategyForUsage(audio_usage_t usage)
+ {
+ return mPolicyEngine->getStrategyForUsage(usage);
+ }
+ virtual status_t setPhoneState(audio_mode_t mode)
+ {
+ return mPolicyEngine->setPhoneState(mode);
+ }
+ virtual audio_mode_t getPhoneState() const
+ {
+ return mPolicyEngine->getPhoneState();
+ }
+ virtual status_t setForceUse(audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config)
+ {
+ return mPolicyEngine->setForceUse(usage, config);
+ }
+ virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const
+ {
+ return mPolicyEngine->getForceUse(usage);
+ }
+ virtual status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
+ audio_policy_dev_state_t /*state*/)
+ {
+ return NO_ERROR;
+ }
+ virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
+ {
+ return mPolicyEngine->initStreamVolume(stream, indexMin, indexMax);
+ }
+ virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled)
+ {
+ return mPolicyEngine->initializeVolumeCurves(isSpeakerDrcEnabled);
+ }
+ virtual float volIndexToAmpl(Volume::device_category deviceCategory,
+ audio_stream_type_t stream,int indexInUi)
+ {
+ return mPolicyEngine->volIndexToAmpl(deviceCategory, stream, indexInUi);
+ }
+ private:
+ Engine *mPolicyEngine;
+ } mManagerInterface;
+
+private:
+ /* Copy facilities are put private to disable copy. */
+ Engine(const Engine &object);
+ Engine &operator=(const Engine &object);
+
+ void setObserver(AudioPolicyManagerObserver *observer);
+
+ status_t initCheck();
+
+ inline bool isInCall() const
+ {
+ return is_state_in_call(mPhoneState);
+ }
+
+ status_t setPhoneState(audio_mode_t mode);
+ audio_mode_t getPhoneState() const
+ {
+ return mPhoneState;
+ }
+ status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
+ audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const
+ {
+ return mForceUse[usage];
+ }
+ status_t setDefaultDevice(audio_devices_t device);
+
+ routing_strategy getStrategyForStream(audio_stream_type_t stream);
+ routing_strategy getStrategyForUsage(audio_usage_t usage);
+ audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
+ audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
+
+ float volIndexToAmpl(Volume::device_category category,
+ audio_stream_type_t stream, int indexInUi);
+ status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
+ void initializeVolumeCurves(bool isSpeakerDrcEnabled);
+
+ audio_mode_t mPhoneState; /**< current phone state. */
+
+ /** current forced use configuration. */
+ audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT];
+
+ AudioPolicyManagerObserver *mApmObserver;
+};
+} // namespace audio_policy
+} // namespace android
+
diff --git a/services/audiopolicy/enginedefault/src/EngineInstance.cpp b/services/audiopolicy/enginedefault/src/EngineInstance.cpp
new file mode 100755
index 0000000..17e9832
--- /dev/null
+++ b/services/audiopolicy/enginedefault/src/EngineInstance.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <AudioPolicyManagerInterface.h>
+#include "AudioPolicyEngineInstance.h"
+#include "Engine.h"
+
+namespace android
+{
+namespace audio_policy
+{
+
+EngineInstance::EngineInstance()
+{
+}
+
+EngineInstance *EngineInstance::getInstance()
+{
+ static EngineInstance instance;
+ return &instance;
+}
+
+EngineInstance::~EngineInstance()
+{
+}
+
+Engine *EngineInstance::getEngine() const
+{
+ static Engine engine;
+ return &engine;
+}
+
+template <>
+AudioPolicyManagerInterface *EngineInstance::queryInterface() const
+{
+ return getEngine()->queryInterface<AudioPolicyManagerInterface>();
+}
+
+} // namespace audio_policy
+} // namespace android
+
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp
new file mode 100644
index 0000000..a684fdd
--- /dev/null
+++ b/services/audiopolicy/enginedefault/src/Gains.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::Gains"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include "Gains.h"
+#include <Volume.h>
+#include <math.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// Enginedefault
+const VolumeCurvePoint
+Gains::sDefaultVolumeCurve[Volume::VOLCNT] = {
+ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+
+const VolumeCurvePoint
+Gains::sDefaultMediaVolumeCurve[Volume::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sExtMediaSystemVolumeCurve[Volume::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSpeakerMediaVolumeCurve[Volume::VOLCNT] = {
+ {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT] = {
+ {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSpeakerSonificationVolumeCurve[Volume::VOLCNT] = {
+ {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT] = {
+ {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
+// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
+const VolumeCurvePoint
+Gains::sDefaultSystemVolumeCurve[Volume::VOLCNT] = {
+ {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
+};
+
+const VolumeCurvePoint
+Gains::sDefaultSystemVolumeCurveDrc[Volume::VOLCNT] = {
+ {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const VolumeCurvePoint
+Gains::sHeadsetSystemVolumeCurve[Volume::VOLCNT] = {
+ {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
+};
+
+const VolumeCurvePoint
+Gains::sDefaultVoiceVolumeCurve[Volume::VOLCNT] = {
+ {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSpeakerVoiceVolumeCurve[Volume::VOLCNT] = {
+ {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sLinearVolumeCurve[Volume::VOLCNT] = {
+ {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint
+Gains::sSilentVolumeCurve[Volume::VOLCNT] = {
+ {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
+};
+
+const VolumeCurvePoint
+Gains::sFullScaleVolumeCurve[Volume::VOLCNT] = {
+ {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
+};
+
+const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT]
+ [Volume::DEVICE_CATEGORY_CNT] = {
+ { // AUDIO_STREAM_VOICE_CALL
+ Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_SYSTEM
+ Gains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_RING
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_MUSIC
+ Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ALARM
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_NOTIFICATION
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_BLUETOOTH_SCO
+ Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ENFORCED_AUDIBLE
+ Gains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_DTMF
+ Gains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_TTS
+ // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
+ Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_ACCESSIBILITY
+ Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_REROUTING
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+ { // AUDIO_STREAM_PATCH
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ Gains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ Gains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ },
+};
+
+//static
+float Gains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi)
+{
+ Volume::device_category deviceCategory = Volume::getDeviceCategory(device);
+ const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory);
+
+ // the volume index in the UI is relative to the min and max volume indices for this stream type
+ int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
+ curve[Volume::VOLMIN].mIndex;
+ int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) /
+ (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin());
+
+ // find what part of the curve this index volume belongs to, or if it's out of bounds
+ int segment = 0;
+ if (volIdx < curve[Volume::VOLMIN].mIndex) { // out of bounds
+ return 0.0f;
+ } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
+ segment = 0;
+ } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
+ segment = 1;
+ } else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
+ segment = 2;
+ } else { // out of bounds
+ return 1.0f;
+ }
+
+ // linear interpolation in the attenuation table in dB
+ float decibels = curve[segment].mDBAttenuation +
+ ((float)(volIdx - curve[segment].mIndex)) *
+ ( (curve[segment+1].mDBAttenuation -
+ curve[segment].mDBAttenuation) /
+ ((float)(curve[segment+1].mIndex -
+ curve[segment].mIndex)) );
+
+ float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+ ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+ curve[segment].mIndex, volIdx,
+ curve[segment+1].mIndex,
+ curve[segment].mDBAttenuation,
+ decibels,
+ curve[segment+1].mDBAttenuation,
+ amplification);
+
+ return amplification;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/enginedefault/src/Gains.h
new file mode 100644
index 0000000..b5601ca
--- /dev/null
+++ b/services/audiopolicy/enginedefault/src/Gains.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <StreamDescriptor.h>
+#include <utils/KeyedVector.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class StreamDescriptor;
+
+class Gains
+{
+public :
+ static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi);
+
+ // default volume curve
+ static const VolumeCurvePoint sDefaultVolumeCurve[Volume::VOLCNT];
+ // default volume curve for media strategy
+ static const VolumeCurvePoint sDefaultMediaVolumeCurve[Volume::VOLCNT];
+ // volume curve for non-media audio on ext media outputs (HDMI, Line, etc)
+ static const VolumeCurvePoint sExtMediaSystemVolumeCurve[Volume::VOLCNT];
+ // volume curve for media strategy on speakers
+ static const VolumeCurvePoint sSpeakerMediaVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[Volume::VOLCNT];
+ // volume curve for sonification strategy on speakers
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[Volume::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[Volume::VOLCNT];
+ static const VolumeCurvePoint sHeadsetSystemVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sDefaultVoiceVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sLinearVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT];
+ static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT];
+ // default volume curves per stream and device category. See initializeVolumeCurves()
+ static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT];
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp b/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp
deleted file mode 100644
index f4054c8..0000000
--- a/services/audiopolicy/managerdefault/AudioInputDescriptor.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioInputDescriptor"
-//#define LOG_NDEBUG 0
-
-#include "AudioPolicyManager.h"
-
-namespace android {
-
-AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
- : mId(0), mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
- mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
-{
- if (profile != NULL) {
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
- if (profile->mGains.size() > 0) {
- profile->mGains[0]->getDefaultConfig(&mGain);
- }
- }
-}
-
-void AudioInputDescriptor::toAudioPortConfig(
- struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig) const
-{
- ALOG_ASSERT(mProfile != 0,
- "toAudioPortConfig() called on input with null profile %d", mIoHandle);
- dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
- AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
- if (srcConfig != NULL) {
- dstConfig->config_mask |= srcConfig->config_mask;
- }
-
- AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
- dstConfig->id = mId;
- dstConfig->role = AUDIO_PORT_ROLE_SINK;
- dstConfig->type = AUDIO_PORT_TYPE_MIX;
- dstConfig->ext.mix.hw_module = mProfile->mModule->mHandle;
- dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = mInputSource;
-}
-
-void AudioInputDescriptor::toAudioPort(
- struct audio_port *port) const
-{
- ALOG_ASSERT(mProfile != 0, "toAudioPort() called on input with null profile %d", mIoHandle);
-
- mProfile->toAudioPort(port);
- port->id = mId;
- toAudioPortConfig(&port->active_config);
- port->ext.mix.hw_module = mProfile->mModule->mHandle;
- port->ext.mix.handle = mIoHandle;
- port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
-}
-
-status_t AudioInputDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " ID: %d\n", mId);
- result.append(buffer);
- snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %d\n", mFormat);
- result.append(buffer);
- snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
- result.append(buffer);
- snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
- result.append(buffer);
- snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
-}
-
-}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 53ec0f6..797a2b4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -24,20 +24,11 @@
#define ALOGVV(a...) do { } while(0)
#endif
-// A device mask for all audio input devices that are considered "virtual" when evaluating
-// active inputs in getActiveInput()
-#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER)
-// A device mask for all audio output devices that are considered "remote" when evaluating
-// active output devices in isStreamActiveRemotely()
-#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-// A device mask for all audio input and output devices where matching inputs/outputs on device
-// type alone is not enough: the address must match too
-#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
-
#include <inttypes.h>
#include <math.h>
+#include <AudioPolicyManagerInterface.h>
+#include <AudioPolicyEngineInstance.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <hardware/audio.h>
@@ -47,6 +38,8 @@
#include <soundtrigger/SoundTrigger.h>
#include "AudioPolicyManager.h"
#include "audio_policy_conf.h"
+#include <ConfigParsingUtils.h>
+#include <policy.h>
namespace android {
@@ -73,7 +66,8 @@
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
- sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address, device_name);
+ sp<DeviceDescriptor> devDesc =
+ mHwModules.getDeviceDescriptor(device, device_address, device_name);
// handle output devices
if (audio_is_output_device(device)) {
@@ -97,7 +91,7 @@
// register new device as available
index = mAvailableOutputDevices.add(devDesc);
if (index >= 0) {
- sp<HwModule> module = getModuleForDevice(device);
+ sp<HwModule> module = mHwModules.getModuleForDevice(device);
if (module == 0) {
ALOGD("setDeviceConnectionState() could not find HW module for device %08x",
device);
@@ -113,6 +107,9 @@
mAvailableOutputDevices.remove(devDesc);
return INVALID_OPERATION;
}
+ // Propagate device availability to Engine
+ mEngine->setDeviceConnectionState(devDesc, state);
+
// outputs should never be empty here
ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
"checkOutputsForDevice() returned no outputs but status OK");
@@ -143,6 +140,9 @@
mAvailableOutputDevices.remove(devDesc);
checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress);
+
+ // Propagate device availability to Engine
+ mEngine->setDeviceConnectionState(devDesc, state);
} break;
default:
@@ -171,20 +171,20 @@
}
updateDevicesAndOutputs();
- if (mPhoneState == AUDIO_MODE_IN_CALL) {
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_io_handle_t output = mOutputs.keyAt(i);
- if ((mPhoneState != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) {
+ if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) {
audio_devices_t newDevice = getNewOutputDevice(mOutputs.keyAt(i),
true /*fromCache*/);
// do not force device change on duplicated output because if device is 0, it will
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
bool force = !mOutputs.valueAt(i)->isDuplicated()
- && (!deviceDistinguishesOnAddress(device)
+ && (!device_distinguishes_on_address(device)
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
setOutputDevice(output, newDevice, force, 0);
@@ -208,7 +208,7 @@
ALOGW("setDeviceConnectionState() device already connected: %d", device);
return INVALID_OPERATION;
}
- sp<HwModule> module = getModuleForDevice(device);
+ sp<HwModule> module = mHwModules.getModuleForDevice(device);
if (module == NULL) {
ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",
device);
@@ -230,6 +230,8 @@
param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device);
mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
+ // Propagate device availability to Engine
+ mEngine->setDeviceConnectionState(devDesc, state);
} break;
// handle input device disconnection
@@ -249,6 +251,8 @@
checkInputsForDevice(device, state, inputs, devDesc->mAddress);
mAvailableInputDevices.remove(devDesc);
+ // Propagate device availability to Engine
+ mEngine->setDeviceConnectionState(devDesc, state);
} break;
default:
@@ -258,7 +262,7 @@
closeAllInputs();
- if (mPhoneState == AUDIO_MODE_IN_CALL) {
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
@@ -272,9 +276,10 @@
}
audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
- const char *device_address)
+ const char *device_address)
{
- sp<DeviceDescriptor> devDesc = getDeviceDescriptor(device, device_address, "");
+ sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(device, device_address, "");
+
DeviceVector *deviceVector;
if (audio_is_output_device(device)) {
@@ -285,44 +290,7 @@
ALOGW("getDeviceConnectionState() invalid device type %08x", device);
return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
}
-
- ssize_t index = deviceVector->indexOf(devDesc);
- if (index >= 0) {
- return AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
- } else {
- return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
- }
-}
-
-sp<DeviceDescriptor> AudioPolicyManager::getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name)
-{
- String8 address = (device_address == NULL) ? String8("") : String8(device_address);
- // handle legacy remote submix case where the address was not always specified
- if (deviceDistinguishesOnAddress(device) && (address.length() == 0)) {
- address = String8("0");
- }
-
- for (size_t i = 0; i < mHwModules.size(); i++) {
- if (mHwModules[i]->mHandle == 0) {
- continue;
- }
- DeviceVector deviceList =
- mHwModules[i]->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
- if (!deviceList.isEmpty()) {
- return deviceList.itemAt(0);
- }
- deviceList = mHwModules[i]->mDeclaredDevices.getDevicesFromType(device);
- if (!deviceList.isEmpty()) {
- return deviceList.itemAt(0);
- }
- }
-
- sp<DeviceDescriptor> devDesc =
- new DeviceDescriptor(String8(device_name != NULL ? device_name : ""), device);
- devDesc->mAddress = address;
- return devDesc;
+ return deviceVector->getDeviceConnectionState(devDesc);
}
void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs)
@@ -393,8 +361,7 @@
ALOGW_IF(status != NO_ERROR, "updateCallRouting() error %d creating RX audio patch",
status);
if (status == NO_ERROR) {
- mCallRxPatch = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
- &patch, mUidCached);
+ mCallRxPatch = new AudioPatch(&patch, mUidCached);
mCallRxPatch->mAfPatchHandle = afPatchHandle;
mCallRxPatch->mUid = mUidCached;
}
@@ -436,8 +403,7 @@
ALOGW_IF(status != NO_ERROR, "setPhoneState() error %d creating TX audio patch",
status);
if (status == NO_ERROR) {
- mCallTxPatch = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
- &patch, mUidCached);
+ mCallTxPatch = new AudioPatch(&patch, mUidCached);
mCallTxPatch->mAfPatchHandle = afPatchHandle;
mCallTxPatch->mUid = mUidCached;
}
@@ -447,16 +413,14 @@
void AudioPolicyManager::setPhoneState(audio_mode_t state)
{
ALOGV("setPhoneState() state %d", state);
- if (state < 0 || state >= AUDIO_MODE_CNT) {
- ALOGW("setPhoneState() invalid state %d", state);
+ // store previous phone state for management of sonification strategy below
+ int oldState = mEngine->getPhoneState();
+
+ if (mEngine->setPhoneState(state) != NO_ERROR) {
+ ALOGW("setPhoneState() invalid or same state %d", state);
return;
}
-
- if (state == mPhoneState ) {
- ALOGW("setPhoneState() setting same state %d", state);
- return;
- }
-
+ /// Opens: can these line be executed after the switch of volume curves???
// if leaving call state, handle special case of active streams
// pertaining to sonification strategy see handleIncallSonification()
if (isInCall()) {
@@ -472,36 +436,12 @@
mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
}
- // store previous phone state for management of sonification strategy below
- int oldState = mPhoneState;
- mPhoneState = state;
- bool force = false;
-
- // are we entering or starting a call
- if (!isStateInCall(oldState) && isStateInCall(state)) {
- ALOGV(" Entering call in setPhoneState()");
- // force routing command to audio hardware when starting a call
- // even if no device change is needed
- force = true;
- for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
- mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
- ApmGains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
- }
- } else if (isStateInCall(oldState) && !isStateInCall(state)) {
- ALOGV(" Exiting call in setPhoneState()");
- // force routing command to audio hardware when exiting a call
- // even if no device change is needed
- force = true;
- for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
- mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
- ApmGains::sVolumeProfiles[AUDIO_STREAM_DTMF][j];
- }
- } else if (isStateInCall(state) && (state != oldState)) {
- ALOGV(" Switching between telephony and VoIP in setPhoneState()");
- // force routing command to audio hardware when switching between telephony and VoIP
- // even if no device change is needed
- force = true;
- }
+ /**
+ * Switching to or from incall state or switching between telephony and VoIP lead to force
+ * routing command.
+ */
+ bool force = ((is_state_in_call(oldState) != is_state_in_call(state))
+ || (is_state_in_call(state) && (state != oldState)));
// check for device and output changes triggered by new phone state
checkA2dpSuspend();
@@ -518,12 +458,12 @@
// mute media and sonification strategies and delay device switch by the largest
// latency of any output where either strategy is active.
// This avoid sending the ring tone or music tail into the earpiece or headset.
- if ((desc->isStrategyActive(STRATEGY_MEDIA,
- SONIFICATION_HEADSET_MUSIC_DELAY,
- sysTime) ||
- desc->isStrategyActive(STRATEGY_SONIFICATION,
- SONIFICATION_HEADSET_MUSIC_DELAY,
- sysTime)) &&
+ if ((isStrategyActive(desc, STRATEGY_MEDIA,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime) ||
+ isStrategyActive(desc, STRATEGY_SONIFICATION,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime)) &&
(delayMs < (int)desc->mLatency*2)) {
delayMs = desc->mLatency*2;
}
@@ -581,84 +521,35 @@
}
}
+audio_mode_t AudioPolicyManager::getPhoneState() {
+ return mEngine->getPhoneState();
+}
+
void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config)
{
- ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+ ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mEngine->getPhoneState());
- bool forceVolumeReeval = false;
- switch(usage) {
- case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
- if (config != AUDIO_POLICY_FORCE_SPEAKER && config != AUDIO_POLICY_FORCE_BT_SCO &&
- config != AUDIO_POLICY_FORCE_NONE) {
- ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
- return;
- }
- forceVolumeReeval = true;
- mForceUse[usage] = config;
- break;
- case AUDIO_POLICY_FORCE_FOR_MEDIA:
- if (config != AUDIO_POLICY_FORCE_HEADPHONES && config != AUDIO_POLICY_FORCE_BT_A2DP &&
- config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
- config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
- config != AUDIO_POLICY_FORCE_DIGITAL_DOCK && config != AUDIO_POLICY_FORCE_NONE &&
- config != AUDIO_POLICY_FORCE_NO_BT_A2DP && config != AUDIO_POLICY_FORCE_SPEAKER ) {
- ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
- return;
- }
- mForceUse[usage] = config;
- break;
- case AUDIO_POLICY_FORCE_FOR_RECORD:
- if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
- config != AUDIO_POLICY_FORCE_NONE) {
- ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
- return;
- }
- mForceUse[usage] = config;
- break;
- case AUDIO_POLICY_FORCE_FOR_DOCK:
- if (config != AUDIO_POLICY_FORCE_NONE && config != AUDIO_POLICY_FORCE_BT_CAR_DOCK &&
- config != AUDIO_POLICY_FORCE_BT_DESK_DOCK &&
- config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
- config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
- config != AUDIO_POLICY_FORCE_DIGITAL_DOCK) {
- ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
- }
- forceVolumeReeval = true;
- mForceUse[usage] = config;
- break;
- case AUDIO_POLICY_FORCE_FOR_SYSTEM:
- if (config != AUDIO_POLICY_FORCE_NONE &&
- config != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
- ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
- }
- forceVolumeReeval = true;
- mForceUse[usage] = config;
- break;
- case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
- if (config != AUDIO_POLICY_FORCE_NONE &&
- config != AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED) {
- ALOGW("setForceUse() invalid config %d forHDMI_SYSTEM_AUDIO", config);
- }
- mForceUse[usage] = config;
- break;
- default:
- ALOGW("setForceUse() invalid usage %d", usage);
- break;
+ if (mEngine->setForceUse(usage, config) != NO_ERROR) {
+ ALOGW("setForceUse() could not set force cfg %d for usage %d", config, usage);
+ return;
}
+ bool forceVolumeReeval = (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) ||
+ (usage == AUDIO_POLICY_FORCE_FOR_DOCK) ||
+ (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM);
// check for device and output changes triggered by new force usage
checkA2dpSuspend();
checkOutputForAllStrategies();
updateDevicesAndOutputs();
- if (mPhoneState == AUDIO_MODE_IN_CALL) {
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, true /*fromCache*/);
updateCallRouting(newDevice);
}
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_io_handle_t output = mOutputs.keyAt(i);
audio_devices_t newDevice = getNewOutputDevice(output, true /*fromCache*/);
- if ((mPhoneState != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) {
+ if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (output != mPrimaryOutput)) {
setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
}
if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
@@ -666,18 +557,13 @@
}
}
- audio_io_handle_t activeInput = getActiveInput();
+ audio_io_handle_t activeInput = mInputs.getActiveInput();
if (activeInput != 0) {
setInputDevice(activeInput, getNewInputDevice(activeInput));
}
}
-audio_policy_forced_cfg_t AudioPolicyManager::getForceUse(audio_policy_force_use_t usage)
-{
- return mForceUse[usage];
-}
-
void AudioPolicyManager::setSystemProperty(const char* property, const char* value)
{
ALOGV("setSystemProperty() property %s, value %s", property, value);
@@ -711,11 +597,11 @@
}
audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
{
routing_strategy strategy = getStrategy(stream);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
@@ -753,45 +639,16 @@
}
stream_type_to_audio_attributes(*stream, &attributes);
}
-
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- sp<AudioOutputDescriptor> desc;
- if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) {
- for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
- if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
- (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
- desc = mPolicyMixes[i]->mOutput;
- break;
- }
- if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
- strncmp(attributes.tags + strlen("addr="),
- mPolicyMixes[i]->mMix.mRegistrationId.string(),
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- desc = mPolicyMixes[i]->mOutput;
- break;
- }
- }
- } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) {
- if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
- strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
- strncmp(attributes.tags + strlen("addr="),
- mPolicyMixes[i]->mMix.mRegistrationId.string(),
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- desc = mPolicyMixes[i]->mOutput;
- }
+ sp<AudioOutputDescriptor> desc;
+ if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
+ ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
+ if (!audio_is_linear_pcm(format)) {
+ return BAD_VALUE;
}
- if (desc != 0) {
- if (!audio_is_linear_pcm(format)) {
- return BAD_VALUE;
- }
- desc->mPolicyMix = &mPolicyMixes[i]->mMix;
- *stream = streamTypefromAttributesInt(&attributes);
- *output = desc->mIoHandle;
- ALOGV("getOutputForAttr() returns output %d", *output);
- return NO_ERROR;
- }
+ *stream = streamTypefromAttributesInt(&attributes);
+ *output = desc->mIoHandle;
+ ALOGV("getOutputForAttr() returns output %d", *output);
+ return NO_ERROR;
}
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
@@ -799,7 +656,7 @@
}
ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x",
- attributes.usage, attributes.content_type, attributes.tags, attributes.flags);
+ attributes.usage, attributes.content_type, attributes.tags, attributes.flags);
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
@@ -909,7 +766,7 @@
// in the background.
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
- !isNonOffloadableEffectEnabled()) {
+ !mEffects.isNonOffloadableEffectEnabled()) {
profile = getProfileForDirectOutput(device,
samplingRate,
format,
@@ -1095,7 +952,7 @@
uint32_t beaconMuteLatency = 0;
if (stream == AUDIO_STREAM_TTS) {
ALOGV("\t found BEACON stream");
- if (isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+ if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
return INVALID_OPERATION;
} else {
beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
@@ -1274,7 +1131,7 @@
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
if (outputDesc->isActive()) {
mpClientInterface->closeOutput(output);
- mOutputs.removeItem(output);
+ removeOutput(output);
mTestOutputs[testIndex] = 0;
}
return;
@@ -1332,19 +1189,13 @@
if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
+ status_t ret = mPolicyMixes.getInputMixForAttr(*attr, policyMix);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
address = String8(attr->tags + strlen("addr="));
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index < 0) {
- ALOGW("getInputForAttr() no policy for address %s", address.string());
- return BAD_VALUE;
- }
- if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) {
- ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
- return BAD_VALUE;
- }
- policyMix = &mPolicyMixes[index]->mMix;
- *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
} else {
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
if (device == AUDIO_DEVICE_NONE) {
@@ -1482,10 +1333,10 @@
}
// virtual input devices are compatible with other input devices
- if (!isVirtualInputDevice(inputDesc->mDevice)) {
+ if (!is_virtual_input_device(inputDesc->mDevice)) {
// for a non-virtual input device, check if there is another (non-virtual) active input
- audio_io_handle_t activeInput = getActiveInput();
+ audio_io_handle_t activeInput = mInputs.getActiveInput();
if (activeInput != 0 && activeInput != input) {
// If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
@@ -1503,7 +1354,7 @@
}
if (inputDesc->mRefCount == 0) {
- if (activeInputsCount() == 0) {
+ if (mInputs.activeInputsCount() == 0) {
SoundTrigger::setCaptureState(true);
}
setInputDevice(input, getNewInputDevice(input), true /* force */);
@@ -1575,7 +1426,7 @@
resetInputDevice(input);
- if (activeInputsCount() == 0) {
+ if (mInputs.activeInputsCount() == 0) {
SoundTrigger::setCaptureState(false);
}
}
@@ -1642,25 +1493,20 @@
int indexMax)
{
ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
- if (indexMin < 0 || indexMin >= indexMax) {
- ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax);
- return;
- }
- mStreams[stream].mIndexMin = indexMin;
- mStreams[stream].mIndexMax = indexMax;
+ mEngine->initStreamVolume(stream, indexMin, indexMax);
//FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
if (stream == AUDIO_STREAM_MUSIC) {
- mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMin = indexMin;
- mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexMax = indexMax;
+ mEngine->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
}
}
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
- int index,
- audio_devices_t device)
+ int index,
+ audio_devices_t device)
{
- if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ if ((index < mStreams[stream].getVolumeIndexMin()) ||
+ (index > mStreams[stream].getVolumeIndexMax())) {
return BAD_VALUE;
}
if (!audio_is_output_device(device)) {
@@ -1668,7 +1514,7 @@
}
// Force max volume if stream cannot be muted
- if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+ if (!mStreams.canBeMuted(stream)) index = mStreams[stream].getVolumeIndexMax();
ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
stream, device, index);
@@ -1676,9 +1522,9 @@
// if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
// clear all device specific values
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
- mStreams[stream].mIndexCur.clear();
+ mStreams.clearCurrentVolumeIndex(stream);
}
- mStreams[stream].mIndexCur.add(device, index);
+ mStreams.addCurrentVolumeIndex(stream, device, index);
// update volume on all outputs whose current device is also selected by the same
// strategy as the device specified by the caller
@@ -1688,7 +1534,7 @@
//FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
if (stream == AUDIO_STREAM_MUSIC) {
- mStreams[AUDIO_STREAM_ACCESSIBILITY].mIndexCur.add(device, index);
+ mStreams.addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
}
if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
@@ -1697,8 +1543,7 @@
}
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
- audio_devices_t curDevice =
- ApmGains::getDeviceForVolume(mOutputs.valueAt(i)->device());
+ audio_devices_t curDevice = Volume::getDeviceForVolume(mOutputs.valueAt(i)->device());
if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
@@ -1728,7 +1573,7 @@
if (device == AUDIO_DEVICE_OUT_DEFAULT) {
device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
}
- device = ApmGains::getDeviceForVolume(device);
+ device = Volume::getDeviceForVolume(device);
*index = mStreams[stream].getVolumeIndex(device);
ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
@@ -1805,137 +1650,7 @@
return INVALID_OPERATION;
}
}
-
- if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
- ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
- desc->name, desc->memoryUsage);
- return INVALID_OPERATION;
- }
- mTotalEffectsMemory += desc->memoryUsage;
- ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
- desc->name, io, strategy, session, id);
- ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
-
- sp<EffectDescriptor> effectDesc = new EffectDescriptor();
- memcpy (&effectDesc->mDesc, desc, sizeof(effect_descriptor_t));
- effectDesc->mIo = io;
- effectDesc->mStrategy = (routing_strategy)strategy;
- effectDesc->mSession = session;
- effectDesc->mEnabled = false;
-
- mEffects.add(id, effectDesc);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::unregisterEffect(int id)
-{
- ssize_t index = mEffects.indexOfKey(id);
- if (index < 0) {
- ALOGW("unregisterEffect() unknown effect ID %d", id);
- return INVALID_OPERATION;
- }
-
- sp<EffectDescriptor> effectDesc = mEffects.valueAt(index);
-
- setEffectEnabled(effectDesc, false);
-
- if (mTotalEffectsMemory < effectDesc->mDesc.memoryUsage) {
- ALOGW("unregisterEffect() memory %d too big for total %d",
- effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
- effectDesc->mDesc.memoryUsage = mTotalEffectsMemory;
- }
- mTotalEffectsMemory -= effectDesc->mDesc.memoryUsage;
- ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
- effectDesc->mDesc.name, id, effectDesc->mDesc.memoryUsage, mTotalEffectsMemory);
-
- mEffects.removeItem(id);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
-{
- ssize_t index = mEffects.indexOfKey(id);
- if (index < 0) {
- ALOGW("unregisterEffect() unknown effect ID %d", id);
- return INVALID_OPERATION;
- }
-
- return setEffectEnabled(mEffects.valueAt(index), enabled);
-}
-
-status_t AudioPolicyManager::setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled)
-{
- if (enabled == effectDesc->mEnabled) {
- ALOGV("setEffectEnabled(%s) effect already %s",
- enabled?"true":"false", enabled?"enabled":"disabled");
- return INVALID_OPERATION;
- }
-
- if (enabled) {
- if (mTotalEffectsCpuLoad + effectDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
- ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
- effectDesc->mDesc.name, (float)effectDesc->mDesc.cpuLoad/10);
- return INVALID_OPERATION;
- }
- mTotalEffectsCpuLoad += effectDesc->mDesc.cpuLoad;
- ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
- } else {
- if (mTotalEffectsCpuLoad < effectDesc->mDesc.cpuLoad) {
- ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
- effectDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
- effectDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
- }
- mTotalEffectsCpuLoad -= effectDesc->mDesc.cpuLoad;
- ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
- }
- effectDesc->mEnabled = enabled;
- return NO_ERROR;
-}
-
-bool AudioPolicyManager::isNonOffloadableEffectEnabled()
-{
- for (size_t i = 0; i < mEffects.size(); i++) {
- sp<EffectDescriptor> effectDesc = mEffects.valueAt(i);
- if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) &&
- ((effectDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
- ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
- effectDesc->mDesc.name, effectDesc->mSession);
- return true;
- }
- }
- return false;
-}
-
-bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
-{
- nsecs_t sysTime = systemTime();
- for (size_t i = 0; i < mOutputs.size(); i++) {
- const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
- return true;
- }
- }
- return false;
-}
-
-bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream,
- uint32_t inPastMs) const
-{
- nsecs_t sysTime = systemTime();
- for (size_t i = 0; i < mOutputs.size(); i++) {
- const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
- outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
- // do not consider re routing (when the output is going to a dynamic policy)
- // as "remote playback"
- if (outputDesc->mPolicyMix == NULL) {
- return true;
- }
- }
- }
- return false;
+ return mEffects.registerEffect(desc, io, strategy, session, id);
}
bool AudioPolicyManager::isSourceActive(audio_source_t source) const
@@ -2005,9 +1720,8 @@
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index >= 0) {
- ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
+
+ if (mPolicyMixes.registerMix(address, mixes[i]) != NO_ERROR) {
continue;
}
audio_config_t outputConfig = mixes[i].mFormat;
@@ -2020,9 +1734,7 @@
AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
module->addInputProfile(address, &inputConfig,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
- sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
- policyMix->mMix = mixes[i];
- mPolicyMixes.add(address, policyMix);
+
if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
@@ -2055,14 +1767,11 @@
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index < 0) {
- ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+
+ if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
continue;
}
- mPolicyMixes.removeItemsAt(index);
-
if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
{
@@ -2096,87 +1805,32 @@
snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput);
result.append(buffer);
- snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+ snprintf(buffer, SIZE, " Phone state: %d\n", mEngine->getPhoneState());
result.append(buffer);
snprintf(buffer, SIZE, " Force use for communications %d\n",
- mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]);
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION));
result.append(buffer);
- snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA]);
+ snprintf(buffer, SIZE, " Force use for media %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA));
result.append(buffer);
- snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD]);
+ snprintf(buffer, SIZE, " Force use for record %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD));
result.append(buffer);
- snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK]);
+ snprintf(buffer, SIZE, " Force use for dock %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK));
result.append(buffer);
- snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM]);
+ snprintf(buffer, SIZE, " Force use for system %d\n", mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM));
result.append(buffer);
snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n",
- mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO]);
- result.append(buffer);
-
- snprintf(buffer, SIZE, " Available output devices:\n");
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO));
result.append(buffer);
write(fd, result.string(), result.size());
- for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
- mAvailableOutputDevices[i]->dump(fd, 2, i);
- }
- snprintf(buffer, SIZE, "\n Available input devices:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
- mAvailableInputDevices[i]->dump(fd, 2, i);
- }
- snprintf(buffer, SIZE, "\nHW Modules dump:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < mHwModules.size(); i++) {
- snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
- write(fd, buffer, strlen(buffer));
- mHwModules[i]->dump(fd);
- }
-
- snprintf(buffer, SIZE, "\nOutputs dump:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < mOutputs.size(); i++) {
- snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
- write(fd, buffer, strlen(buffer));
- mOutputs.valueAt(i)->dump(fd);
- }
-
- snprintf(buffer, SIZE, "\nInputs dump:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < mInputs.size(); i++) {
- snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
- write(fd, buffer, strlen(buffer));
- mInputs.valueAt(i)->dump(fd);
- }
-
- snprintf(buffer, SIZE, "\nStreams dump:\n");
- write(fd, buffer, strlen(buffer));
- snprintf(buffer, SIZE,
- " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < AUDIO_STREAM_CNT; i++) {
- snprintf(buffer, SIZE, " %02zu ", i);
- write(fd, buffer, strlen(buffer));
- mStreams[i].dump(fd);
- }
-
- 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);
- }
-
- snprintf(buffer, SIZE, "\nAudio Patches:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < mAudioPatches.size(); i++) {
- mAudioPatches[i]->dump(fd, 2, i);
- }
+ mAvailableOutputDevices.dump(fd, String8("output"));
+ mAvailableInputDevices.dump(fd, String8("input"));
+ mHwModules.dump(fd);
+ mOutputs.dump(fd);
+ mInputs.dump(fd);
+ mStreams.dump(fd);
+ mEffects.dump(fd);
+ mAudioPatches.dump(fd);
return NO_ERROR;
}
@@ -2233,7 +1887,7 @@
// FIXME: We should check the audio session here but we do not have it in this context.
// This may prevent offloading in rare situations where effects are left active by apps
// in the background.
- if (isNonOffloadableEffectEnabled()) {
+ if (mEffects.isNonOffloadableEffectEnabled()) {
return false;
}
@@ -2312,93 +1966,6 @@
return NO_ERROR;
}
-sp<AudioOutputDescriptor> AudioPolicyManager::getOutputFromId(
- audio_port_handle_t id) const
-{
- sp<AudioOutputDescriptor> outputDesc = NULL;
- for (size_t i = 0; i < mOutputs.size(); i++) {
- outputDesc = mOutputs.valueAt(i);
- if (outputDesc->mId == id) {
- break;
- }
- }
- return outputDesc;
-}
-
-sp<AudioInputDescriptor> AudioPolicyManager::getInputFromId(
- audio_port_handle_t id) const
-{
- sp<AudioInputDescriptor> inputDesc = NULL;
- for (size_t i = 0; i < mInputs.size(); i++) {
- inputDesc = mInputs.valueAt(i);
- if (inputDesc->mId == id) {
- break;
- }
- }
- return inputDesc;
-}
-
-sp <HwModule> AudioPolicyManager::getModuleForDevice(
- audio_devices_t device) const
-{
- sp <HwModule> module;
-
- for (size_t i = 0; i < mHwModules.size(); i++) {
- if (mHwModules[i]->mHandle == 0) {
- continue;
- }
- if (audio_is_output_device(device)) {
- for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
- {
- if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) {
- return mHwModules[i];
- }
- }
- } else {
- for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) {
- if (mHwModules[i]->mInputProfiles[j]->mSupportedDevices.types() &
- device & ~AUDIO_DEVICE_BIT_IN) {
- return mHwModules[i];
- }
- }
- }
- }
- return module;
-}
-
-sp <HwModule> AudioPolicyManager::getModuleFromName(const char *name) const
-{
- sp <HwModule> module;
-
- for (size_t i = 0; i < mHwModules.size(); i++)
- {
- if (strcmp(mHwModules[i]->mName, name) == 0) {
- return mHwModules[i];
- }
- }
- return module;
-}
-
-audio_devices_t AudioPolicyManager::availablePrimaryOutputDevices()
-{
- sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(mPrimaryOutput);
- audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types();
- return devices & mAvailableOutputDevices.types();
-}
-
-audio_devices_t AudioPolicyManager::availablePrimaryInputDevices()
-{
- audio_module_handle_t primaryHandle =
- mOutputs.valueFor(mPrimaryOutput)->mProfile->mModule->mHandle;
- audio_devices_t devices = AUDIO_DEVICE_NONE;
- for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
- if (mAvailableInputDevices[i]->mModule->mHandle == primaryHandle) {
- devices |= mAvailableInputDevices[i]->mDeviceType;
- }
- }
- return devices;
-}
-
status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
uid_t uid)
@@ -2454,7 +2021,7 @@
}
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
- sp<AudioOutputDescriptor> outputDesc = getOutputFromId(patch->sources[0].id);
+ sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id);
return BAD_VALUE;
@@ -2483,15 +2050,14 @@
return BAD_VALUE;
}
- if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
+ if (!outputDesc->mProfile->isCompatibleProfile(devDesc->type(),
devDesc->mAddress,
patch->sources[0].sample_rate,
- NULL, // updatedSamplingRate
- patch->sources[0].format,
- patch->sources[0].channel_mask,
- AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
- ALOGV("createAudioPatch() profile not supported for device %08x",
- devDesc->mDeviceType);
+ NULL, // updatedSamplingRate
+ patch->sources[0].format,
+ patch->sources[0].channel_mask,
+ AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
+ ALOGV("createAudioPatch() profile not supported for device %08x", devDesc->type());
return INVALID_OPERATION;
}
devices.add(devDesc);
@@ -2523,7 +2089,7 @@
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
}
- sp<AudioInputDescriptor> inputDesc = getInputFromId(patch->sinks[0].id);
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
if (inputDesc == NULL) {
return BAD_VALUE;
}
@@ -2538,7 +2104,7 @@
return BAD_VALUE;
}
- if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
+ if (!inputDesc->mProfile->isCompatibleProfile(devDesc->type(),
devDesc->mAddress,
patch->sinks[0].sample_rate,
NULL, /*updatedSampleRate*/
@@ -2552,8 +2118,8 @@
}
// TODO: reconfigure output format and channels here
ALOGV("createAudioPatch() setting device %08x on output %d",
- devDesc->mDeviceType, inputDesc->mIoHandle);
- setInputDevice(inputDesc->mIoHandle, devDesc->mDeviceType, true, handle);
+ devDesc->type(), inputDesc->mIoHandle);
+ setInputDevice(inputDesc->mIoHandle, devDesc->type(), true, handle);
index = mAudioPatches.indexOfKey(*handle);
if (index >= 0) {
if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
@@ -2603,8 +2169,7 @@
return INVALID_OPERATION;
}
SortedVector<audio_io_handle_t> outputs =
- getOutputsForDevice(sinkDeviceDesc->mDeviceType,
- mOutputs);
+ getOutputsForDevice(sinkDeviceDesc->type(), mOutputs);
// if the sink device is reachable via an opened output stream, request to go via
// this output stream by adding a second source to the patch description
audio_io_handle_t output = selectOutput(outputs,
@@ -2634,8 +2199,7 @@
status, afPatchHandle);
if (status == NO_ERROR) {
if (index < 0) {
- patchDesc = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
- &newPatch, uid);
+ patchDesc = new AudioPatch(&newPatch, uid);
addAudioPatch(patchDesc->mHandle, patchDesc);
} else {
patchDesc->mPatch = newPatch;
@@ -2678,7 +2242,7 @@
struct audio_patch *patch = &patchDesc->mPatch;
patchDesc->mUid = mUidCached;
if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
- sp<AudioOutputDescriptor> outputDesc = getOutputFromId(patch->sources[0].id);
+ sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
if (outputDesc == NULL) {
ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id);
return BAD_VALUE;
@@ -2691,7 +2255,7 @@
NULL);
} else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
- sp<AudioInputDescriptor> inputDesc = getInputFromId(patch->sinks[0].id);
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
if (inputDesc == NULL) {
ALOGV("releaseAudioPatch() input not found for id %d", patch->sinks[0].id);
return BAD_VALUE;
@@ -2721,30 +2285,11 @@
struct audio_patch *patches,
unsigned int *generation)
{
- if (num_patches == NULL || (*num_patches != 0 && patches == NULL) ||
- generation == NULL) {
+ if (generation == NULL) {
return BAD_VALUE;
}
- ALOGV("listAudioPatches() num_patches %d patches %p available patches %zu",
- *num_patches, patches, mAudioPatches.size());
- if (patches == NULL) {
- *num_patches = 0;
- }
-
- size_t patchesWritten = 0;
- size_t patchesMax = *num_patches;
- for (size_t i = 0;
- i < mAudioPatches.size() && patchesWritten < patchesMax; i++) {
- patches[patchesWritten] = mAudioPatches[i]->mPatch;
- patches[patchesWritten++].id = mAudioPatches[i]->mHandle;
- ALOGV("listAudioPatches() patch %zu num_sources %d num_sinks %d",
- i, mAudioPatches[i]->mPatch.num_sources, mAudioPatches[i]->mPatch.num_sinks);
- }
- *num_patches = mAudioPatches.size();
-
*generation = curAudioPortGeneration();
- ALOGV("listAudioPatches() got %zu patches needed %d", patchesWritten, *num_patches);
- return NO_ERROR;
+ return mAudioPatches.listAudioPatches(num_patches, patches);
}
status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config *config)
@@ -2763,7 +2308,7 @@
sp<AudioPortConfig> audioPortConfig;
if (config->type == AUDIO_PORT_TYPE_MIX) {
if (config->role == AUDIO_PORT_ROLE_SOURCE) {
- sp<AudioOutputDescriptor> outputDesc = getOutputFromId(config->id);
+ sp<AudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(config->id);
if (outputDesc == NULL) {
return BAD_VALUE;
}
@@ -2772,7 +2317,7 @@
outputDesc->mIoHandle);
audioPortConfig = outputDesc;
} else if (config->role == AUDIO_PORT_ROLE_SINK) {
- sp<AudioInputDescriptor> inputDesc = getInputFromId(config->id);
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(config->id);
if (inputDesc == NULL) {
return BAD_VALUE;
}
@@ -2829,79 +2374,24 @@
*ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId();
*device = getDeviceAndMixForInputSource(AUDIO_SOURCE_HOTWORD);
- mSoundTriggerSessions.add(*session, *ioHandle);
-
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::releaseSoundTriggerSession(audio_session_t session)
-{
- ssize_t index = mSoundTriggerSessions.indexOfKey(session);
- if (index < 0) {
- ALOGW("acquireSoundTriggerSession() session %d not registered", session);
- return BAD_VALUE;
- }
-
- mSoundTriggerSessions.removeItem(session);
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::addAudioPatch(audio_patch_handle_t handle,
- const sp<AudioPatch>& patch)
-{
- ssize_t index = mAudioPatches.indexOfKey(handle);
-
- if (index >= 0) {
- ALOGW("addAudioPatch() patch %d already in", handle);
- return ALREADY_EXISTS;
- }
- mAudioPatches.add(handle, patch);
- ALOGV("addAudioPatch() handle %d af handle %d num_sources %d num_sinks %d source handle %d"
- "sink handle %d",
- handle, patch->mAfPatchHandle, patch->mPatch.num_sources, patch->mPatch.num_sinks,
- patch->mPatch.sources[0].id, patch->mPatch.sinks[0].id);
- return NO_ERROR;
-}
-
-status_t AudioPolicyManager::removeAudioPatch(audio_patch_handle_t handle)
-{
- ssize_t index = mAudioPatches.indexOfKey(handle);
-
- if (index < 0) {
- ALOGW("removeAudioPatch() patch %d not in", handle);
- return ALREADY_EXISTS;
- }
- ALOGV("removeAudioPatch() handle %d af handle %d", handle,
- mAudioPatches.valueAt(index)->mAfPatchHandle);
- mAudioPatches.removeItemsAt(index);
- return NO_ERROR;
+ return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
// ----------------------------------------------------------------------------
// AudioPolicyManager
// ----------------------------------------------------------------------------
-
-uint32_t AudioPolicyManager::nextUniqueId()
-{
- return android_atomic_inc(&mNextUniqueId);
-}
-
uint32_t AudioPolicyManager::nextAudioPortGeneration()
{
return android_atomic_inc(&mAudioPortGeneration);
}
-int32_t volatile AudioPolicyManager::mNextUniqueId = 1;
-
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
:
#ifdef AUDIO_POLICY_TEST
Thread(false),
#endif //AUDIO_POLICY_TEST
mPrimaryOutput((audio_io_handle_t)0),
- mPhoneState(AUDIO_MODE_NORMAL),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
- mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
mA2dpSuspended(false),
mSpeakerDrcEnabled(false),
mAudioPortGeneration(1),
@@ -2909,24 +2399,39 @@
mBeaconPlayingRefCount(0),
mBeaconMuted(false)
{
+ audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
+ if (!engineInstance) {
+ ALOGE("%s: Could not get an instance of policy engine", __FUNCTION__);
+ return;
+ }
+ // Retrieve the Policy Manager Interface
+ mEngine = engineInstance->queryInterface<AudioPolicyManagerInterface>();
+ if (mEngine == NULL) {
+ ALOGE("%s: Failed to get Policy Engine Interface", __FUNCTION__);
+ return;
+ }
+ mEngine->setObserver(this);
+ status_t status = mEngine->initCheck();
+ ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
+
mUidCached = getuid();
mpClientInterface = clientInterface;
- for (int i = 0; i < AUDIO_POLICY_FORCE_USE_CNT; i++) {
- mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
- }
-
mDefaultOutputDevice = new DeviceDescriptor(String8("Speaker"), AUDIO_DEVICE_OUT_SPEAKER);
- if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
- if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
+ if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
+ mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
+ mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
+ if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
+ mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
+ mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
defaultAudioPolicyConfig();
}
}
// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
- // must be done after reading the policy
- initializeVolumeCurves();
+ // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
+ mEngine->initializeVolumeCurves(mSpeakerDrcEnabled);
// open all output streams needed to access attached devices
audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
@@ -2954,13 +2459,13 @@
continue;
}
audio_devices_t profileType = outProfile->mSupportedDevices.types();
- if ((profileType & mDefaultOutputDevice->mDeviceType) != AUDIO_DEVICE_NONE) {
- profileType = mDefaultOutputDevice->mDeviceType;
+ if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
+ profileType = mDefaultOutputDevice->type();
} else {
// chose first device present in mSupportedDevices also part of
// outputDeviceTypes
for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- profileType = outProfile->mSupportedDevices[k]->mDeviceType;
+ profileType = outProfile->mSupportedDevices[k]->type();
if ((profileType & outputDeviceTypes) != 0) {
break;
}
@@ -2995,7 +2500,7 @@
outputDesc->mFormat = config.format;
for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = outProfile->mSupportedDevices[k]->mDeviceType;
+ audio_devices_t type = outProfile->mSupportedDevices[k]->type();
ssize_t index =
mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -3027,7 +2532,7 @@
// inputDeviceTypes
audio_devices_t profileType = AUDIO_DEVICE_NONE;
for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- profileType = inProfile->mSupportedDevices[k]->mDeviceType;
+ profileType = inProfile->mSupportedDevices[k]->type();
if (profileType & inputDeviceTypes) {
break;
}
@@ -3063,7 +2568,7 @@
if (status == NO_ERROR) {
for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = inProfile->mSupportedDevices[k]->mDeviceType;
+ audio_devices_t type = inProfile->mSupportedDevices[k]->type();
ssize_t index =
mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
@@ -3082,23 +2587,29 @@
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
if (!mAvailableOutputDevices[i]->isAttached()) {
- ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->mDeviceType);
+ ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->type());
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
}
+ // The device is now validated and can be appended to the available devices of the engine
+ mEngine->setDeviceConnectionState(mAvailableOutputDevices[i],
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
i++;
}
for (size_t i = 0; i < mAvailableInputDevices.size();) {
if (!mAvailableInputDevices[i]->isAttached()) {
- ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->mDeviceType);
+ ALOGW("Input device %08x unreachable", mAvailableInputDevices[i]->type());
mAvailableInputDevices.remove(mAvailableInputDevices[i]);
continue;
}
+ // The device is now validated and can be appended to the available devices of the engine
+ mEngine->setDeviceConnectionState(mAvailableInputDevices[i],
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
i++;
}
// make sure default device is reachable
if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
- ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->mDeviceType);
+ ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
}
ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
@@ -3254,8 +2765,7 @@
audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
- mOutputs.removeItem(mPrimaryOutput);
-
+ removeOutput(mPrimaryOutput);
sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(NULL);
outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -3314,16 +2824,19 @@
void AudioPolicyManager::addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc)
{
- outputDesc->mIoHandle = output;
- outputDesc->mId = nextUniqueId();
+ outputDesc->setIoHandle(output);
mOutputs.add(output, outputDesc);
nextAudioPortGeneration();
}
+void AudioPolicyManager::removeOutput(audio_io_handle_t output)
+{
+ mOutputs.removeItem(output);
+}
+
void AudioPolicyManager::addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc)
{
- inputDesc->mIoHandle = input;
- inputDesc->mId = nextUniqueId();
+ inputDesc->setIoHandle(input);
mInputs.add(input, inputDesc);
nextAudioPortGeneration();
}
@@ -3342,11 +2855,11 @@
}
status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
- audio_policy_dev_state_t state,
- SortedVector<audio_io_handle_t>& outputs,
- const String8 address)
+ audio_policy_dev_state_t state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 address)
{
- audio_devices_t device = devDesc->mDeviceType;
+ audio_devices_t device = devDesc->type();
sp<AudioOutputDescriptor> desc;
// erase all current sample rates, formats and channel masks
devDesc->clearCapabilities();
@@ -3356,7 +2869,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) {
- if (!deviceDistinguishesOnAddress(device)) {
+ if (!device_distinguishes_on_address(device)) {
ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
outputs.add(mOutputs.keyAt(i));
} else {
@@ -3376,7 +2889,7 @@
{
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
if (profile->mSupportedDevices.types() & device) {
- if (!deviceDistinguishesOnAddress(device) ||
+ if (!device_distinguishes_on_address(device) ||
address == profile->mSupportedDevices[0]->mAddress) {
profiles.add(profile);
ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
@@ -3512,15 +3025,15 @@
if (output != AUDIO_IO_HANDLE_NONE) {
addOutput(output, desc);
- if (deviceDistinguishesOnAddress(device) && address != "0") {
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index >= 0) {
- mPolicyMixes[index]->mOutput = desc;
- desc->mPolicyMix = &mPolicyMixes[index]->mMix;
- } else {
+ if (device_distinguishes_on_address(device) && address != "0") {
+ sp<AudioPolicyMix> policyMix;
+ if (mPolicyMixes.getAudioPolicyMix(address, policyMix) != NO_ERROR) {
ALOGE("checkOutputsForDevice() cannot find policy for address %s",
address.string());
}
+ policyMix->setOutput(desc);
+ desc->mPolicyMix = &(policyMix->getMix());
+
} else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
// no duplicated output for direct outputs and
// outputs used by dynamic policy mixes
@@ -3550,7 +3063,7 @@
ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
mPrimaryOutput, output);
mpClientInterface->closeOutput(output);
- mOutputs.removeItem(output);
+ removeOutput(output);
nextAudioPortGeneration();
output = AUDIO_IO_HANDLE_NONE;
}
@@ -3567,7 +3080,7 @@
outputs.add(output);
devDesc->importAudioPort(profile);
- if (deviceDistinguishesOnAddress(device)) {
+ if (device_distinguishes_on_address(device)) {
ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
device, address.string());
setOutputDevice(output, device, true/*force*/, 0/*delay*/,
@@ -3587,7 +3100,7 @@
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated()) {
// exact match on device
- if (deviceDistinguishesOnAddress(device) &&
+ if (device_distinguishes_on_address(device) &&
(desc->mProfile->mSupportedDevices.types() == device)) {
findIoHandlesByAddress(desc, device, address, outputs);
} else if (!(desc->mProfile->mSupportedDevices.types()
@@ -3630,9 +3143,9 @@
}
status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device,
- audio_policy_dev_state_t state,
- SortedVector<audio_io_handle_t>& inputs,
- const String8 address)
+ audio_policy_dev_state_t state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 address)
{
sp<AudioInputDescriptor> desc;
if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
@@ -3659,7 +3172,7 @@
sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index];
if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
- if (!deviceDistinguishesOnAddress(device) ||
+ if (!device_distinguishes_on_address(device) ||
address == profile->mSupportedDevices[0]->mAddress) {
profiles.add(profile);
ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
@@ -3831,12 +3344,7 @@
ALOGW("closeOutput() unknown output %d", output);
return;
}
-
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- if (mPolicyMixes[i]->mOutput == outputDesc) {
- mPolicyMixes[i]->mOutput.clear();
- }
- }
+ mPolicyMixes.closeOutput(outputDesc);
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -3862,7 +3370,7 @@
ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
mpClientInterface->closeOutput(duplicatedOutput);
- mOutputs.removeItem(duplicatedOutput);
+ removeOutput(duplicatedOutput);
}
}
@@ -3881,7 +3389,7 @@
mpClientInterface->setParameters(output, param.toString());
mpClientInterface->closeOutput(output);
- mOutputs.removeItem(output);
+ removeOutput(output);
mPreviousOutputs = mOutputs;
}
@@ -3910,7 +3418,7 @@
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs)
+ AudioOutputCollection openOutputs)
{
SortedVector<audio_io_handle_t> outputs;
@@ -3927,7 +3435,7 @@
}
bool AudioPolicyManager::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
- SortedVector<audio_io_handle_t>& outputs2)
+ SortedVector<audio_io_handle_t>& outputs2)
{
if (outputs1.size() != outputs2.size()) {
return false;
@@ -3971,7 +3479,7 @@
// mute strategy while moving tracks from one output to another
for (size_t i = 0; i < srcOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueFor(srcOutputs[i]);
- if (desc->isStrategyActive(strategy)) {
+ if (isStrategyActive(desc, strategy)) {
setStrategyMute(strategy, true, srcOutputs[i]);
setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
}
@@ -4010,10 +3518,10 @@
void AudioPolicyManager::checkOutputForAllStrategies()
{
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
checkOutputForStrategy(STRATEGY_PHONE);
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
checkOutputForStrategy(STRATEGY_SONIFICATION);
checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
@@ -4023,21 +3531,9 @@
checkOutputForStrategy(STRATEGY_REROUTING);
}
-audio_io_handle_t AudioPolicyManager::getA2dpOutput()
-{
- for (size_t i = 0; i < mOutputs.size(); i++) {
- sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
- return mOutputs.keyAt(i);
- }
- }
-
- return 0;
-}
-
void AudioPolicyManager::checkA2dpSuspend()
{
- audio_io_handle_t a2dpOutput = getA2dpOutput();
+ audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput();
if (a2dpOutput == 0) {
mA2dpSuspended = false;
return;
@@ -4061,20 +3557,20 @@
//
if (mA2dpSuspended) {
if ((!isScoConnected ||
- ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] != AUDIO_POLICY_FORCE_BT_SCO) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] != AUDIO_POLICY_FORCE_BT_SCO))) &&
- ((mPhoneState != AUDIO_MODE_IN_CALL) &&
- (mPhoneState != AUDIO_MODE_RINGTONE))) {
+ ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) != AUDIO_POLICY_FORCE_BT_SCO) &&
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) != AUDIO_POLICY_FORCE_BT_SCO))) &&
+ ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) &&
+ (mEngine->getPhoneState() != AUDIO_MODE_RINGTONE))) {
mpClientInterface->restoreOutput(a2dpOutput);
mA2dpSuspended = false;
}
} else {
if ((isScoConnected &&
- ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) ||
- (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO))) ||
- ((mPhoneState == AUDIO_MODE_IN_CALL) ||
- (mPhoneState == AUDIO_MODE_RINGTONE))) {
+ ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) ||
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO))) ||
+ ((mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) ||
+ (mEngine->getPhoneState() == AUDIO_MODE_RINGTONE))) {
mpClientInterface->suspendOutput(a2dpOutput);
mA2dpSuspended = true;
@@ -4117,27 +3613,27 @@
// use device for strategy DTMF
// 9: the strategy for beacon, a.k.a. "transmitted through speaker" is active on the output:
// use device for strategy t-t-s
- if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE) &&
- mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+ if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE) &&
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isInCall() ||
- outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+ isStrategyActive(outputDesc, STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_ACCESSIBILITY)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) {
device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache);
- } else if (outputDesc->isStrategyActive(STRATEGY_REROUTING)) {
+ } else if (isStrategyActive(outputDesc, STRATEGY_REROUTING)) {
device = getDeviceForStrategy(STRATEGY_REROUTING, fromCache);
}
@@ -4182,7 +3678,7 @@
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(devices, mOutputs);
for (size_t i = 0; i < outputs.size(); i++) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
- if (outputDesc->isStrategyActive(strategy)) {
+ if (isStrategyActive(outputDesc, strategy)) {
devices = outputDesc->device();
break;
}
@@ -4198,39 +3694,10 @@
return devices;
}
-routing_strategy AudioPolicyManager::getStrategy(
- audio_stream_type_t stream) {
-
+routing_strategy AudioPolicyManager::getStrategy(audio_stream_type_t stream) const
+{
ALOG_ASSERT(stream != AUDIO_STREAM_PATCH,"getStrategy() called for AUDIO_STREAM_PATCH");
-
- // stream to strategy mapping
- switch (stream) {
- case AUDIO_STREAM_VOICE_CALL:
- case AUDIO_STREAM_BLUETOOTH_SCO:
- return STRATEGY_PHONE;
- case AUDIO_STREAM_RING:
- case AUDIO_STREAM_ALARM:
- return STRATEGY_SONIFICATION;
- case AUDIO_STREAM_NOTIFICATION:
- return STRATEGY_SONIFICATION_RESPECTFUL;
- case AUDIO_STREAM_DTMF:
- return STRATEGY_DTMF;
- default:
- ALOGE("unknown stream type %d", stream);
- case AUDIO_STREAM_SYSTEM:
- // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
- // while key clicks are played produces a poor result
- case AUDIO_STREAM_MUSIC:
- return STRATEGY_MEDIA;
- case AUDIO_STREAM_ENFORCED_AUDIBLE:
- return STRATEGY_ENFORCED_AUDIBLE;
- case AUDIO_STREAM_TTS:
- return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
- case AUDIO_STREAM_ACCESSIBILITY:
- return STRATEGY_ACCESSIBILITY;
- case AUDIO_STREAM_REROUTING:
- return STRATEGY_REROUTING;
- }
+ return mEngine->getStrategyForStream(stream);
}
uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
@@ -4241,45 +3708,8 @@
if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
}
-
// usage to strategy mapping
- switch (attr->usage) {
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
- if (isStreamActive(AUDIO_STREAM_RING) || isStreamActive(AUDIO_STREAM_ALARM)) {
- return (uint32_t) STRATEGY_SONIFICATION;
- }
- if (isInCall()) {
- return (uint32_t) STRATEGY_PHONE;
- }
- return (uint32_t) STRATEGY_ACCESSIBILITY;
-
- case AUDIO_USAGE_MEDIA:
- case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
- case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
- return (uint32_t) STRATEGY_MEDIA;
-
- case AUDIO_USAGE_VOICE_COMMUNICATION:
- return (uint32_t) STRATEGY_PHONE;
-
- case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return (uint32_t) STRATEGY_DTMF;
-
- case AUDIO_USAGE_ALARM:
- case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
- return (uint32_t) STRATEGY_SONIFICATION;
-
- case AUDIO_USAGE_NOTIFICATION:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
- case AUDIO_USAGE_NOTIFICATION_EVENT:
- return (uint32_t) STRATEGY_SONIFICATION_RESPECTFUL;
-
- case AUDIO_USAGE_UNKNOWN:
- default:
- return (uint32_t) STRATEGY_MEDIA;
- }
+ return static_cast<uint32_t>(mEngine->getStrategyForUsage(attr->usage));
}
void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -4293,21 +3723,6 @@
}
}
-bool AudioPolicyManager::isAnyOutputActive(audio_stream_type_t streamToIgnore) {
- for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
- if (s == (size_t) streamToIgnore) {
- continue;
- }
- for (size_t i = 0; i < mOutputs.size(); i++) {
- const sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- if (outputDesc->mRefCount[s] != 0) {
- return true;
- }
- }
- }
- return false;
-}
-
uint32_t AudioPolicyManager::handleEventForBeacon(int event) {
switch(event) {
case STARTING_OUTPUT:
@@ -4362,292 +3777,14 @@
}
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
- bool fromCache)
+ bool fromCache)
{
- uint32_t device = AUDIO_DEVICE_NONE;
-
if (fromCache) {
ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
strategy, mDeviceForStrategy[strategy]);
return mDeviceForStrategy[strategy];
}
- audio_devices_t availableOutputDeviceTypes = mAvailableOutputDevices.types();
- switch (strategy) {
-
- case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
- if (!device) {
- ALOGE("getDeviceForStrategy() no device found for "\
- "STRATEGY_TRANSMITTED_THROUGH_SPEAKER");
- }
- break;
-
- case STRATEGY_SONIFICATION_RESPECTFUL:
- if (isInCall()) {
- device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
- } else if (isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
- // while media is playing on a remote device, use the the sonification behavior.
- // Note that we test this usecase before testing if media is playing because
- // the isStreamActive() method only informs about the activity of a stream, not
- // if it's for local playback. Note also that we use the same delay between both tests
- device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
- //user "safe" speaker if available instead of normal speaker to avoid triggering
- //other acoustic safety mechanisms for notification
- if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
- device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- } else if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
- // while media is playing (or has recently played), use the same device
- device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
- } else {
- // when media is not playing anymore, fall back on the sonification behavior
- device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
- //user "safe" speaker if available instead of normal speaker to avoid triggering
- //other acoustic safety mechanisms for notification
- if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
- device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
- }
-
- break;
-
- case STRATEGY_DTMF:
- if (!isInCall()) {
- // when off call, DTMF strategy follows the same rules as MEDIA strategy
- device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
- break;
- }
- // when in call, DTMF and PHONE strategies follow the same rules
- // FALL THROUGH
-
- case STRATEGY_PHONE:
- // Force use of only devices on primary output if:
- // - in call AND
- // - cannot route from voice call RX OR
- // - audio HAL version is < 3.0 and TX device is on the primary HW module
- if (mPhoneState == AUDIO_MODE_IN_CALL) {
- audio_devices_t txDevice =
- getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
- sp<AudioOutputDescriptor> hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
- if (((mAvailableInputDevices.types() &
- AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
- (((txDevice & availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN) != 0) &&
- (hwOutputDesc->getAudioPort()->mModule->mHalVersion <
- AUDIO_DEVICE_API_VERSION_3_0))) {
- availableOutputDeviceTypes = availablePrimaryOutputDevices();
- }
- }
- // for phone strategy, we first consider the forced use and then the available devices by order
- // of priority
- switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
- case AUDIO_POLICY_FORCE_BT_SCO:
- if (!isInCall() || strategy != STRATEGY_DTMF) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- if (device) break;
- }
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
- if (device) break;
- // if SCO device is requested but no SCO device is available, fall back to default case
- // FALL THROUGH
-
- default: // FORCE_NONE
- // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
- if (!isInCall() &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0)) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
- if (device) break;
- }
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
- if (!isInCall()) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
- }
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_EARPIECE;
- if (device) break;
- device = mDefaultOutputDevice->mDeviceType;
- if (device == AUDIO_DEVICE_NONE) {
- ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
- }
- break;
-
- case AUDIO_POLICY_FORCE_SPEAKER:
- // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
- // A2DP speaker when forcing to speaker output
- if (!isInCall() &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0)) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
- if (device) break;
- }
- if (!isInCall()) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
- }
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE;
- if (device) break;
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
- if (device) break;
- device = mDefaultOutputDevice->mDeviceType;
- if (device == AUDIO_DEVICE_NONE) {
- ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
- }
- break;
- }
- break;
-
- case STRATEGY_SONIFICATION:
-
- // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
- // handleIncallSonification().
- if (isInCall()) {
- device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
- break;
- }
- // FALL THROUGH
-
- case STRATEGY_ENFORCED_AUDIBLE:
- // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
- // except:
- // - when in call where it doesn't default to STRATEGY_PHONE behavior
- // - in countries where not enforced in which case it follows STRATEGY_MEDIA
-
- if ((strategy == STRATEGY_SONIFICATION) ||
- (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
- device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
- if (device == AUDIO_DEVICE_NONE) {
- ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
- }
- }
- // The second device used for sonification is the same as the device used by media strategy
- // FALL THROUGH
-
- // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now
- case STRATEGY_ACCESSIBILITY:
- if (strategy == STRATEGY_ACCESSIBILITY) {
- // do not route accessibility prompts to a digital output currently configured with a
- // compressed format as they would likely not be mixed and dropped.
- for (size_t i = 0; i < mOutputs.size(); i++) {
- sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
- audio_devices_t devices = desc->device() &
- (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
- if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
- devices != AUDIO_DEVICE_NONE) {
- availableOutputDeviceTypes = availableOutputDeviceTypes & ~devices;
- }
- }
- }
- // FALL THROUGH
-
- case STRATEGY_REROUTING:
- case STRATEGY_MEDIA: {
- uint32_t device2 = AUDIO_DEVICE_NONE;
- if (strategy != STRATEGY_SONIFICATION) {
- // no sonification on remote submix (e.g. WFD)
- if (mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
- }
- }
- if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
- (getA2dpOutput() != 0)) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
- }
- }
- if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
- }
- if ((device2 == AUDIO_DEVICE_NONE)) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_ACCESSORY;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_USB_DEVICE;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
- }
- if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
- // no sonification on aux digital (e.g. HDMI)
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_DIGITAL;
- }
- if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- }
- if (device2 == AUDIO_DEVICE_NONE) {
- device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
- }
- int device3 = AUDIO_DEVICE_NONE;
- if (strategy == STRATEGY_MEDIA) {
- // ARC, SPDIF and AUX_LINE can co-exist with others.
- device3 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_HDMI_ARC;
- device3 |= (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPDIF);
- device3 |= (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_AUX_LINE);
- }
-
- device2 |= device3;
- // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
- // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
- device |= device2;
-
- // If hdmi system audio mode is on, remove speaker out of output list.
- if ((strategy == STRATEGY_MEDIA) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] ==
- AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
- device &= ~AUDIO_DEVICE_OUT_SPEAKER;
- }
-
- if (device) break;
- device = mDefaultOutputDevice->mDeviceType;
- if (device == AUDIO_DEVICE_NONE) {
- ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
- }
- } break;
-
- default:
- ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
- break;
- }
-
- ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
- return device;
+ return mEngine->getDeviceForStrategy(strategy);
}
void AudioPolicyManager::updateDevicesAndOutputs()
@@ -4698,7 +3835,7 @@
ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
mute ? "muting" : "unmuting", i, curDevice, curOutput);
setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
- if (desc->isStrategyActive((routing_strategy)i)) {
+ if (isStrategyActive(desc, (routing_strategy)i)) {
if (mute) {
// FIXME: should not need to double latency if volume could be applied
// immediately by the audioflinger mixer. We must account for the delay
@@ -4721,7 +3858,7 @@
muteWaitMs = outputDesc->latency() * 2;
}
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
- if (outputDesc->isStrategyActive((routing_strategy)i)) {
+ if (isStrategyActive(outputDesc, (routing_strategy)i)) {
setStrategyMute((routing_strategy)i, true, outputDesc->mIoHandle);
// do tempMute unmute after twice the mute wait time
setStrategyMute((routing_strategy)i, false, outputDesc->mIoHandle,
@@ -4827,8 +3964,7 @@
status, afPatchHandle, patch.num_sources, patch.num_sinks);
if (status == NO_ERROR) {
if (index < 0) {
- patchDesc = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
- &patch, mUidCached);
+ patchDesc = new AudioPatch(&patch, mUidCached);
addAudioPatch(patchDesc->mHandle, patchDesc);
} else {
patchDesc->mPatch = patch;
@@ -4847,7 +3983,7 @@
// inform all input as well
for (size_t i = 0; i < mInputs.size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i);
- if (!isVirtualInputDevice(inputDescriptor->mDevice)) {
+ if (!is_virtual_input_device(inputDescriptor->mDevice)) {
AudioParameter inputCmd = AudioParameter();
ALOGV("%s: inform input %d of device:%d", __func__,
inputDescriptor->mIoHandle, device);
@@ -4934,8 +4070,7 @@
status, afPatchHandle);
if (status == NO_ERROR) {
if (index < 0) {
- patchDesc = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
- &patch, mUidCached);
+ patchDesc = new AudioPatch(&patch, mUidCached);
addAudioPatch(patchDesc->mHandle, patchDesc);
} else {
patchDesc->mPatch = patch;
@@ -4978,11 +4113,11 @@
}
sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
- String8 address,
- uint32_t& samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_input_flags_t flags)
+ String8 address,
+ uint32_t& samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags)
{
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
@@ -5009,224 +4144,35 @@
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
- AudioMix **policyMix)
+ AudioMix **policyMix)
{
- audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
- ~AUDIO_DEVICE_BIT_IN;
+ audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+ audio_devices_t selectedDeviceFromMix =
+ mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) {
- continue;
- }
- for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
- if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) ||
- (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) {
- if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
- if (policyMix != NULL) {
- *policyMix = &mPolicyMixes[i]->mMix;
- }
- return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- }
- break;
- }
- }
+ if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {
+ return selectedDeviceFromMix;
}
-
return getDeviceForInputSource(inputSource);
}
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
{
- uint32_t device = AUDIO_DEVICE_NONE;
- audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
- ~AUDIO_DEVICE_BIT_IN;
-
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
- device = AUDIO_DEVICE_IN_VOICE_CALL;
- break;
- }
- break;
-
- case AUDIO_SOURCE_DEFAULT:
- case AUDIO_SOURCE_MIC:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
- } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&
- (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
-
- case AUDIO_SOURCE_VOICE_COMMUNICATION:
- // Allow only use of devices on primary input if in call and HAL does not support routing
- // to voice call path.
- if ((mPhoneState == AUDIO_MODE_IN_CALL) &&
- (mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
- availableDeviceTypes = availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN;
- }
-
- switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
- case AUDIO_POLICY_FORCE_BT_SCO:
- // if SCO device is requested but no SCO device is available, fall back to default case
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- break;
- }
- // FALL THROUGH
-
- default: // FORCE_NONE
- if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
-
- case AUDIO_POLICY_FORCE_SPEAKER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
- device = AUDIO_DEVICE_IN_BACK_MIC;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
- }
- break;
-
- case AUDIO_SOURCE_VOICE_RECOGNITION:
- case AUDIO_SOURCE_HOTWORD:
- if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
- availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
- device = AUDIO_DEVICE_IN_WIRED_HEADSET;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
- device = AUDIO_DEVICE_IN_USB_DEVICE;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
- case AUDIO_SOURCE_CAMCORDER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
- device = AUDIO_DEVICE_IN_BACK_MIC;
- } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
- device = AUDIO_DEVICE_IN_BUILTIN_MIC;
- }
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- case AUDIO_SOURCE_VOICE_CALL:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
- device = AUDIO_DEVICE_IN_VOICE_CALL;
- }
- break;
- case AUDIO_SOURCE_REMOTE_SUBMIX:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
- device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- }
- break;
- case AUDIO_SOURCE_FM_TUNER:
- if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
- device = AUDIO_DEVICE_IN_FM_TUNER;
- }
- break;
- default:
- ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
- break;
- }
- ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
- return device;
-}
-
-bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device)
-{
- if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
- device &= ~AUDIO_DEVICE_BIT_IN;
- if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
- return true;
- }
- return false;
-}
-
-bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) {
- return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
-}
-
-audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
-{
- for (size_t i = 0; i < mInputs.size(); i++) {
- const sp<AudioInputDescriptor> input_descriptor = mInputs.valueAt(i);
- if ((input_descriptor->mRefCount > 0)
- && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
- return mInputs.keyAt(i);
- }
- }
- return 0;
-}
-
-uint32_t AudioPolicyManager::activeInputsCount() const
-{
- uint32_t count = 0;
- for (size_t i = 0; i < mInputs.size(); i++) {
- const sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
- if (desc->mRefCount > 0) {
- count++;
- }
- }
- return count;
-}
-
-
-void AudioPolicyManager::initializeVolumeCurves()
-{
- for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- for (int j = 0; j < ApmGains::DEVICE_CATEGORY_CNT; j++) {
- mStreams[i].mVolumeCurve[j] =
- ApmGains::sVolumeProfiles[i][j];
- }
- }
-
- // Check availability of DRC on speaker path: if available, override some of the speaker curves
- if (mSpeakerDrcEnabled) {
- mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sDefaultSystemVolumeCurveDrc;
- mStreams[AUDIO_STREAM_RING].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sSpeakerSonificationVolumeCurveDrc;
- mStreams[AUDIO_STREAM_MUSIC].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sSpeakerMediaVolumeCurveDrc;
- mStreams[AUDIO_STREAM_ACCESSIBILITY].mVolumeCurve[ApmGains::DEVICE_CATEGORY_SPEAKER] =
- ApmGains::sSpeakerMediaVolumeCurveDrc;
- }
+ return mEngine->getDeviceForInputSource(inputSource);
}
float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
- int index,
- audio_io_handle_t output,
- audio_devices_t device)
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device)
{
float volume = 1.0;
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- StreamDescriptor &streamDesc = mStreams[stream];
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
}
-
- volume = ApmGains::volIndexToAmpl(device, streamDesc, index);
+ volume = mEngine->volIndexToAmpl(Volume::getDeviceCategory(device), stream, index);
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
@@ -5242,8 +4188,8 @@
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
|| (stream == AUDIO_STREAM_SYSTEM)
|| ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_NONE))) &&
- streamDesc.mCanBeMuted) {
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
+ mStreams.canBeMuted(stream)) {
volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
@@ -5268,11 +4214,11 @@
}
status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
- int index,
- audio_io_handle_t output,
- audio_devices_t device,
- int delayMs,
- bool force)
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
{
// do not change actual stream volume if the stream is muted
@@ -5281,14 +4227,13 @@
stream, mOutputs.valueFor(output)->mMuteCount[stream]);
return NO_ERROR;
}
-
+ audio_policy_forced_cfg_t forceUseForComm =
+ mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
// do not change in call volume if bluetooth is connected and vice versa
- if ((stream == AUDIO_STREAM_VOICE_CALL &&
- mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) ||
- (stream == AUDIO_STREAM_BLUETOOTH_SCO &&
- mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] != AUDIO_POLICY_FORCE_BT_SCO)) {
+ if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
+ (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
- stream, mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]);
+ stream, forceUseForComm);
return INVALID_OPERATION;
}
@@ -5325,7 +4270,7 @@
float voiceVolume;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
if (stream == AUDIO_STREAM_VOICE_CALL) {
- voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ voiceVolume = (float)index/(float)mStreams[stream].getVolumeIndexMax();
} else {
voiceVolume = 1.0;
}
@@ -5340,9 +4285,9 @@
}
void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output,
- audio_devices_t device,
- int delayMs,
- bool force)
+ audio_devices_t device,
+ int delayMs,
+ bool force)
{
ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
@@ -5360,10 +4305,10 @@
}
void AudioPolicyManager::setStrategyMute(routing_strategy strategy,
- bool on,
- audio_io_handle_t output,
- int delayMs,
- audio_devices_t device)
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
{
ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
@@ -5377,12 +4322,12 @@
}
void AudioPolicyManager::setStreamMute(audio_stream_type_t stream,
- bool on,
- audio_io_handle_t output,
- int delayMs,
- audio_devices_t device)
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
{
- StreamDescriptor &streamDesc = mStreams[stream];
+ const StreamDescriptor &streamDesc = mStreams[stream];
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->device();
@@ -5393,9 +4338,9 @@
if (on) {
if (outputDesc->mMuteCount[stream] == 0) {
- if (streamDesc.mCanBeMuted &&
+ if (streamDesc.canBeMuted() &&
((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
- (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_NONE))) {
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
checkAndSetVolume(stream, 0, output, device, delayMs);
}
}
@@ -5461,192 +4406,6 @@
}
}
-bool AudioPolicyManager::isInCall()
-{
- return isStateInCall(mPhoneState);
-}
-
-bool AudioPolicyManager::isStateInCall(int state) {
- return ((state == AUDIO_MODE_IN_CALL) ||
- (state == AUDIO_MODE_IN_COMMUNICATION));
-}
-
-uint32_t AudioPolicyManager::getMaxEffectsCpuLoad()
-{
- return MAX_EFFECTS_CPU_LOAD;
-}
-
-uint32_t AudioPolicyManager::getMaxEffectsMemory()
-{
- return MAX_EFFECTS_MEMORY;
-}
-
-
-// --- EffectDescriptor class implementation
-
-status_t AudioPolicyManager::EffectDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " I/O: %d\n", mIo);
- 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);
- snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
- result.append(buffer);
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
-}
-
-
-// --- audio_policy.conf file parsing
-// TODO candidate to be moved to ConfigParsingUtils
-void AudioPolicyManager::loadHwModule(cnode *root)
-{
- status_t status = NAME_NOT_FOUND;
- cnode *node;
- sp<HwModule> module = new HwModule(root->name);
-
- node = config_find(root, DEVICES_TAG);
- if (node != NULL) {
- node = node->first_child;
- while (node) {
- ALOGV("loadHwModule() loading device %s", node->name);
- status_t tmpStatus = module->loadDevice(node);
- if (status == NAME_NOT_FOUND || status == NO_ERROR) {
- status = tmpStatus;
- }
- node = node->next;
- }
- }
- node = config_find(root, OUTPUTS_TAG);
- if (node != NULL) {
- node = node->first_child;
- while (node) {
- ALOGV("loadHwModule() loading output %s", node->name);
- status_t tmpStatus = module->loadOutput(node);
- if (status == NAME_NOT_FOUND || status == NO_ERROR) {
- status = tmpStatus;
- }
- node = node->next;
- }
- }
- node = config_find(root, INPUTS_TAG);
- if (node != NULL) {
- node = node->first_child;
- while (node) {
- ALOGV("loadHwModule() loading input %s", node->name);
- status_t tmpStatus = module->loadInput(node);
- if (status == NAME_NOT_FOUND || status == NO_ERROR) {
- status = tmpStatus;
- }
- node = node->next;
- }
- }
- loadGlobalConfig(root, module);
-
- if (status == NO_ERROR) {
- mHwModules.add(module);
- }
-}
-
-// TODO candidate to be moved to ConfigParsingUtils
-void AudioPolicyManager::loadHwModules(cnode *root)
-{
- cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
- if (node == NULL) {
- return;
- }
-
- node = node->first_child;
- while (node) {
- ALOGV("loadHwModules() loading module %s", node->name);
- loadHwModule(node);
- node = node->next;
- }
-}
-
-// TODO candidate to be moved to ConfigParsingUtils
-void AudioPolicyManager::loadGlobalConfig(cnode *root, const sp<HwModule>& module)
-{
- cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
-
- if (node == NULL) {
- return;
- }
- DeviceVector declaredDevices;
- if (module != NULL) {
- declaredDevices = module->mDeclaredDevices;
- }
-
- node = node->first_child;
- while (node) {
- if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
- mAvailableOutputDevices.loadDevicesFromName((char *)node->value,
- declaredDevices);
- ALOGV("loadGlobalConfig() Attached Output Devices %08x",
- mAvailableOutputDevices.types());
- } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
- audio_devices_t device = (audio_devices_t)ConfigParsingUtils::stringToEnum(
- sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- (char *)node->value);
- if (device != AUDIO_DEVICE_NONE) {
- mDefaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
- } else {
- ALOGW("loadGlobalConfig() default device not specified");
- }
- ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", mDefaultOutputDevice->mDeviceType);
- } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
- mAvailableInputDevices.loadDevicesFromName((char *)node->value,
- declaredDevices);
- ALOGV("loadGlobalConfig() Available InputDevices %08x", mAvailableInputDevices.types());
- } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
- mSpeakerDrcEnabled = ConfigParsingUtils::stringToBool((char *)node->value);
- ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
- } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
- uint32_t major, minor;
- sscanf((char *)node->value, "%u.%u", &major, &minor);
- module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
- ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
- module->mHalVersion, major, minor);
- }
- node = node->next;
- }
-}
-
-// TODO candidate to be moved to ConfigParsingUtils
-status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
-{
- cnode *root;
- char *data;
-
- data = (char *)load_file(path, NULL);
- if (data == NULL) {
- return -ENODEV;
- }
- root = config_node("", "");
- config_load(root, data);
-
- loadHwModules(root);
- // legacy audio_policy.conf files have one global_configuration section
- loadGlobalConfig(root, getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
- config_free(root);
- free(root);
- free(data);
-
- ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
-
- return NO_ERROR;
-}
-
void AudioPolicyManager::defaultAudioPolicyConfig(void)
{
sp<HwModule> module;
@@ -5732,7 +4491,8 @@
}
}
-bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa) {
+bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa)
+{
// has flags that map to a strategy?
if ((paa->flags & (AUDIO_FLAG_AUDIBILITY_ENFORCED | AUDIO_FLAG_SCO | AUDIO_FLAG_BEACON)) != 0) {
return true;
@@ -5763,4 +4523,39 @@
return true;
}
+bool AudioPolicyManager::isStrategyActive(const sp<AudioOutputDescriptor> outputDesc,
+ routing_strategy strategy, uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if ((sysTime == 0) && (inPastMs != 0)) {
+ sysTime = systemTime();
+ }
+ for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+ if (i == AUDIO_STREAM_PATCH) {
+ continue;
+ }
+ if (((getStrategy((audio_stream_type_t)i) == strategy) ||
+ (NUM_STRATEGIES == strategy)) &&
+ outputDesc->isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+audio_policy_forced_cfg_t AudioPolicyManager::getForceUse(audio_policy_force_use_t usage)
+{
+ return mEngine->getForceUse(usage);
+}
+
+bool AudioPolicyManager::isInCall()
+{
+ return isStateInCall(mEngine->getPhoneState());
+}
+
+bool AudioPolicyManager::isStateInCall(int state)
+{
+ return is_state_in_call(state);
+}
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 61ea6f2..02b678a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -26,14 +27,21 @@
#include <media/AudioPolicy.h>
#include "AudioPolicyInterface.h"
-#include "Gains.h"
-#include "Ports.h"
-#include "ConfigParsingUtils.h"
-#include "Devices.h"
-#include "IOProfile.h"
-#include "HwModule.h"
-#include "AudioInputDescriptor.h"
-#include "AudioOutputDescriptor.h"
+#include <AudioPolicyManagerInterface.h>
+#include <AudioPolicyManagerObserver.h>
+#include <AudioGain.h>
+#include <AudioPort.h>
+#include <AudioPatch.h>
+#include <ConfigParsingUtils.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <HwModule.h>
+#include <AudioInputDescriptor.h>
+#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
+#include <EffectDescriptor.h>
+#include <SoundTriggerSession.h>
+#include <StreamDescriptor.h>
namespace android {
@@ -46,9 +54,7 @@
// Time in milliseconds during which we consider that music is still active after a music
// track was stopped - see computeVolume()
#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
-// Time in milliseconds after media stopped playing during which we consider that the
-// sonification should be as unobtrusive as during the time media was playing.
-#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+
// Time in milliseconds during witch some streams are muted while the audio path
// is switched
#define MUTE_TIME_MS 2000
@@ -61,14 +67,12 @@
// Can be overridden by the audio.offload.min.duration.secs property
#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
-#define MAX_MIXER_SAMPLING_RATE 48000
-#define MAX_MIXER_CHANNEL_COUNT 8
-
// ----------------------------------------------------------------------------
// AudioPolicyManager implements audio policy manager behavior common to all platforms.
// ----------------------------------------------------------------------------
-class AudioPolicyManager: public AudioPolicyInterface
+class AudioPolicyManager : public AudioPolicyInterface, public AudioPolicyManagerObserver
+
#ifdef AUDIO_POLICY_TEST
, public Thread
#endif //AUDIO_POLICY_TEST
@@ -89,6 +93,7 @@
virtual void setForceUse(audio_policy_force_use_t usage,
audio_policy_forced_cfg_t config);
virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
+
virtual void setSystemProperty(const char* property, const char* value);
virtual status_t initCheck();
virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
@@ -158,16 +163,28 @@
uint32_t strategy,
int session,
int id);
- virtual status_t unregisterEffect(int id);
- virtual status_t setEffectEnabled(int id, bool enabled);
+ virtual status_t unregisterEffect(int id)
+ {
+ return mEffects.unregisterEffect(id);
+ }
+ virtual status_t setEffectEnabled(int id, bool enabled)
+ {
+ return mEffects.setEffectEnabled(id, enabled);
+ }
- virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const
+ {
+ return mOutputs.isStreamActive(stream, inPastMs);
+ }
// return whether a stream is playing remotely, override to change the definition of
// local/remote playback, used for instance by notification manager to not make
// media players lose audio focus when not playing locally
// For the base implementation, "remotely" means playing during screen mirroring which
// uses an output for playback with a non-empty, non "0" address.
- virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+ virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const
+ {
+ return mOutputs.isStreamActiveRemotely(stream, inPastMs);
+ }
virtual bool isSourceActive(audio_source_t source) const;
virtual status_t dump(int fd);
@@ -195,39 +212,61 @@
audio_io_handle_t *ioHandle,
audio_devices_t *device);
- virtual status_t releaseSoundTriggerSession(audio_session_t session);
+ virtual status_t releaseSoundTriggerSession(audio_session_t session)
+ {
+ return mSoundTriggerSessions.releaseSession(session);
+ }
virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
- void loadHwModule(cnode *root);
- void loadHwModules(cnode *root);
- void loadGlobalConfig(cnode *root, const sp<HwModule>& module);
- status_t loadAudioPolicyConfig(const char *path);
void defaultAudioPolicyConfig(void);
- // return the strategy corresponding to a given stream type
- static routing_strategy getStrategy(audio_stream_type_t stream);
+ // return the strategy corresponding to a given stream type
+ routing_strategy getStrategy(audio_stream_type_t stream) const;
- static uint32_t nextUniqueId();
-protected:
-
- class EffectDescriptor : public RefBase
+ // From AudioPolicyManagerObserver
+ virtual const AudioPatchCollection &getAudioPatches() const
{
- public:
-
- status_t dump(int fd);
-
- int mIo; // io the effect is attached to
- routing_strategy mStrategy; // routing strategy the effect is associated to
- int mSession; // audio session the effect is on
- effect_descriptor_t mDesc; // effect descriptor
- bool mEnabled; // enabled state: CPU load being used or not
- };
-
+ return mAudioPatches;
+ }
+ virtual const SoundTriggerSessionCollection &getSoundTriggerSessionCollection() const
+ {
+ return mSoundTriggerSessions;
+ }
+ virtual const AudioPolicyMixCollection &getAudioPolicyMixCollection() const
+ {
+ return mPolicyMixes;
+ }
+ virtual const AudioOutputCollection &getOutputs() const
+ {
+ return mOutputs;
+ }
+ virtual const AudioInputCollection &getInputs() const
+ {
+ return mInputs;
+ }
+ virtual const DeviceVector &getAvailableOutputDevices() const
+ {
+ return mAvailableOutputDevices;
+ }
+ virtual const DeviceVector &getAvailableInputDevices() const
+ {
+ return mAvailableInputDevices;
+ }
+ virtual StreamDescriptorCollection &getStreamDescriptors()
+ {
+ return mStreams;
+ }
+ virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
+ {
+ return mDefaultOutputDevice;
+ }
+protected:
void addOutput(audio_io_handle_t output, sp<AudioOutputDescriptor> outputDesc);
+ void removeOutput(audio_io_handle_t output);
void addInput(audio_io_handle_t input, sp<AudioInputDescriptor> inputDesc);
// return appropriate device for streams handled by the specified strategy according to current
@@ -244,6 +283,9 @@
virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
bool fromCache);
+ bool isStrategyActive(const sp<AudioOutputDescriptor> outputDesc, routing_strategy strategy,
+ uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
+
// change the route of the specified output. Returns the number of ms we have slept to
// allow new routing to take effect in certain cases.
virtual uint32_t setOutputDevice(audio_io_handle_t output,
@@ -265,16 +307,6 @@
// select input device corresponding to requested audio source
virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
- // return io handle of active input or 0 if no input is active
- // Only considers inputs from physical devices (e.g. main mic, headset mic) when
- // ignoreVirtualInputs is true.
- audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
-
- uint32_t activeInputsCount() const;
-
- // initialize volume curves for each strategy and device category
- void initializeVolumeCurves();
-
// compute the actual volume for a given stream according to the requested index and a particular
// device
virtual float computeVolume(audio_stream_type_t stream, int index,
@@ -307,9 +339,10 @@
// a special tone in the device used for communication
void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
+ audio_mode_t getPhoneState();
+
// true if device is in a telephony or VoIP call
virtual bool isInCall();
-
// true if given state represents a device in a telephony or VoIP call
virtual bool isStateInCall(int state);
@@ -347,9 +380,6 @@
// manages A2DP output suspend/restore according to phone state and BT SCO usage
void checkA2dpSuspend();
- // returns the A2DP output handle if it is open or 0 otherwise
- audio_io_handle_t getA2dpOutput();
-
// selects the most appropriate device on output for current state
// must be called every time a condition that affects the device choice for a given output is
// changed: connected device, phone state, force use, output start, output stop..
@@ -366,18 +396,23 @@
// selects the most appropriate device on input for current state
audio_devices_t getNewInputDevice(audio_io_handle_t input);
- virtual uint32_t getMaxEffectsCpuLoad();
- virtual uint32_t getMaxEffectsMemory();
+ virtual uint32_t getMaxEffectsCpuLoad()
+ {
+ return mEffects.getMaxEffectsCpuLoad();
+ }
+
+ virtual uint32_t getMaxEffectsMemory()
+ {
+ return mEffects.getMaxEffectsMemory();
+ }
#ifdef AUDIO_POLICY_TEST
virtual bool threadLoop();
void exit();
int testOutputIndex(audio_io_handle_t output);
#endif //AUDIO_POLICY_TEST
- status_t setEffectEnabled(const sp<EffectDescriptor>& effectDesc, bool enabled);
-
SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > openOutputs);
+ AudioOutputCollection openOutputs);
bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
SortedVector<audio_io_handle_t>& outputs2);
@@ -407,60 +442,57 @@
audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
- bool isNonOffloadableEffectEnabled();
+ virtual status_t addAudioPatch(audio_patch_handle_t handle, const sp<AudioPatch>& patch)
+ {
+ return mAudioPatches.addAudioPatch(handle, patch);
+ }
+ virtual status_t removeAudioPatch(audio_patch_handle_t handle)
+ {
+ return mAudioPatches.removeAudioPatch(handle);
+ }
- virtual status_t addAudioPatch(audio_patch_handle_t handle,
- const sp<AudioPatch>& patch);
- virtual status_t removeAudioPatch(audio_patch_handle_t handle);
-
- sp<AudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const;
- sp<AudioInputDescriptor> getInputFromId(audio_port_handle_t id) const;
- sp<HwModule> getModuleForDevice(audio_devices_t device) const;
- sp<HwModule> getModuleFromName(const char *name) const;
- audio_devices_t availablePrimaryOutputDevices();
- audio_devices_t availablePrimaryInputDevices();
+ audio_devices_t availablePrimaryOutputDevices() const
+ {
+ return mOutputs.getSupportedDevices(mPrimaryOutput) & mAvailableOutputDevices.types();
+ }
+ audio_devices_t availablePrimaryInputDevices() const
+ {
+ return mAvailableInputDevices.getDevicesFromHwModule(
+ mOutputs.valueFor(mPrimaryOutput)->getModuleHandle());
+ }
void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
-
uid_t mUidCached;
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
audio_io_handle_t mPrimaryOutput; // primary output handle
// list of descriptors for outputs currently opened
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mOutputs;
+ AudioOutputCollection mOutputs;
// copy of mOutputs before setDeviceConnectionState() opens new outputs
// reset to mOutputs when updateDevicesAndOutputs() is called.
- DefaultKeyedVector<audio_io_handle_t, sp<AudioOutputDescriptor> > mPreviousOutputs;
- DefaultKeyedVector<audio_io_handle_t, sp<AudioInputDescriptor> > mInputs; // list of input descriptors
+ AudioOutputCollection mPreviousOutputs;
+ AudioInputCollection mInputs; // list of input descriptors
DeviceVector mAvailableOutputDevices; // all available output devices
DeviceVector mAvailableInputDevices; // all available input devices
- int mPhoneState; // current phone state
- audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT]; // current forced use configuration
- StreamDescriptor mStreams[AUDIO_STREAM_CNT]; // stream descriptors for volume control
- bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
+ StreamDescriptorCollection mStreams; // stream descriptors for volume control
+ bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
- float mLastVoiceVolume; // last voice volume value sent to audio HAL
+ float mLastVoiceVolume; // last voice volume value sent to audio HAL
- // 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
- KeyedVector<int, sp<EffectDescriptor> > mEffects; // list of registered audio effects
+ EffectDescriptorCollection mEffects; // list of registered audio effects
bool mA2dpSuspended; // true if A2DP output is suspended
sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
// to boost soft sounds, used to adjust volume curves accordingly
- Vector < sp<HwModule> > mHwModules;
- static volatile int32_t mNextUniqueId;
+ HwModuleCollection mHwModules;
+
volatile int32_t mAudioPortGeneration;
- DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> > mAudioPatches;
+ AudioPatchCollection mAudioPatches;
- DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions;
+ SoundTriggerSessionCollection mSoundTriggerSessions;
sp<AudioPatch> mCallTxPatch;
sp<AudioPatch> mCallRxPatch;
@@ -477,16 +509,7 @@
uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
bool mBeaconMuted; // has STREAM_TTS been muted
- // custom mix entry in mPolicyMixes
- class AudioPolicyMix : public RefBase {
- public:
- AudioPolicyMix() {}
-
- AudioMix mMix; // Audio policy mix descriptor
- sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
- };
- DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes
-
+ AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
#ifdef AUDIO_POLICY_TEST
Mutex mLock;
@@ -503,14 +526,14 @@
uint32_t mTestLatencyMs;
#endif //AUDIO_POLICY_TEST
- static bool isVirtualInputDevice(audio_devices_t device);
-
uint32_t nextAudioPortGeneration();
+
+ // Audio Policy Engine Interface.
+ AudioPolicyManagerInterface *mEngine;
private:
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
- static bool deviceDistinguishesOnAddress(audio_devices_t device);
// find the outputs on a given output descriptor that have the given address.
// to be called on an AudioOutputDescriptor whose supported devices (as defined
// in mProfile->mSupportedDevices) matches the device whose address is to be matched.
@@ -533,8 +556,6 @@
const audio_offload_info_t *offloadInfo);
// internal function to derive a stream type value from audio attributes
audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
- // return true if any output is playing anything besides the stream to ignore
- bool isAnyOutputActive(audio_stream_type_t streamToIgnore);
// event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
// returns 0 if no mute/unmute event happened, the largest latency of the device where
// the mute/unmute happened
@@ -552,9 +573,6 @@
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
- sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name);
};
};
diff --git a/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp b/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp
deleted file mode 100644
index 1afd487..0000000
--- a/services/audiopolicy/managerdefault/ConfigParsingUtils.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::ConfigParsingUtils"
-//#define LOG_NDEBUG 0
-
-#include "AudioPolicyManager.h"
-
-namespace android {
-
-//static
-uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
- size_t size,
- const char *name)
-{
- for (size_t i = 0; i < size; i++) {
- if (strcmp(table[i].name, name) == 0) {
- ALOGV("stringToEnum() found %s", table[i].name);
- return table[i].value;
- }
- }
- return 0;
-}
-
-//static
-const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
- size_t size,
- uint32_t value)
-{
- for (size_t i = 0; i < size; i++) {
- if (table[i].value == value) {
- return table[i].name;
- }
- }
- return "";
-}
-
-//static
-bool ConfigParsingUtils::stringToBool(const char *value)
-{
- return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
-}
-
-
-// --- audio_policy.conf file parsing
-//static
-uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
-{
- uint32_t flag = 0;
-
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
- ARRAY_SIZE(sOutputFlagNameToEnumTable),
- flagName);
- }
- flagName = strtok(NULL, "|");
- }
- //force direct flag if offload flag is set: offloading implies a direct output stream
- // and all common behaviors are driven by checking only the direct flag
- // this should normally be set appropriately in the policy configuration file
- if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- flag |= AUDIO_OUTPUT_FLAG_DIRECT;
- }
-
- return flag;
-}
-
-//static
-uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
-{
- uint32_t flag = 0;
-
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= stringToEnum(sInputFlagNameToEnumTable,
- ARRAY_SIZE(sInputFlagNameToEnumTable),
- flagName);
- }
- flagName = strtok(NULL, "|");
- }
- return flag;
-}
-
-//static
-audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
-{
- uint32_t device = 0;
-
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
- device |= stringToEnum(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- devName);
- }
- devName = strtok(NULL, "|");
- }
- return device;
-}
-
-}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Gains.cpp b/services/audiopolicy/managerdefault/Gains.cpp
deleted file mode 100644
index 4aca26d..0000000
--- a/services/audiopolicy/managerdefault/Gains.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::Gains"
-//#define LOG_NDEBUG 0
-
-//#define VERY_VERBOSE_LOGGING
-#ifdef VERY_VERBOSE_LOGGING
-#define ALOGVV ALOGV
-#else
-#define ALOGVV(a...) do { } while(0)
-#endif
-
-#include "AudioPolicyManager.h"
-
-#include <math.h>
-
-namespace android {
-
-const VolumeCurvePoint
-ApmGains::sDefaultVolumeCurve[ApmGains::VOLCNT] = {
- {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
-};
-
-
-const VolumeCurvePoint
-ApmGains::sDefaultMediaVolumeCurve[ApmGains::VOLCNT] = {
- {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sExtMediaSystemVolumeCurve[ApmGains::VOLCNT] = {
- {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSpeakerMediaVolumeCurve[ApmGains::VOLCNT] = {
- {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT] = {
- {1, -55.0f}, {20, -43.0f}, {86, -12.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT] = {
- {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT] = {
- {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
-};
-
-// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
-// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
-// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
-// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
-
-const VolumeCurvePoint
-ApmGains::sDefaultSystemVolumeCurve[ApmGains::VOLCNT] = {
- {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT] = {
- {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sHeadsetSystemVolumeCurve[ApmGains::VOLCNT] = {
- {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sDefaultVoiceVolumeCurve[ApmGains::VOLCNT] = {
- {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT] = {
- {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sLinearVolumeCurve[ApmGains::VOLCNT] = {
- {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sSilentVolumeCurve[ApmGains::VOLCNT] = {
- {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
-};
-
-const VolumeCurvePoint
-ApmGains::sFullScaleVolumeCurve[ApmGains::VOLCNT] = {
- {0, 0.0f}, {1, 0.0f}, {2, 0.0f}, {100, 0.0f}
-};
-
-const VolumeCurvePoint *ApmGains::sVolumeProfiles[AUDIO_STREAM_CNT]
- [ApmGains::DEVICE_CATEGORY_CNT] = {
- { // AUDIO_STREAM_VOICE_CALL
- ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_SYSTEM
- ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_RING
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_MUSIC
- ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ALARM
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_NOTIFICATION
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_BLUETOOTH_SCO
- ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ENFORCED_AUDIBLE
- ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_DTMF
- ApmGains::sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_TTS
- // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
- ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_ACCESSIBILITY
- ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_REROUTING
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
- { // AUDIO_STREAM_PATCH
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_HEADSET
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- ApmGains::sFullScaleVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- ApmGains::sFullScaleVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
- },
-};
-
-//static
-audio_devices_t ApmGains::getDeviceForVolume(audio_devices_t device)
-{
- if (device == AUDIO_DEVICE_NONE) {
- // this happens when forcing a route update and no track is active on an output.
- // In this case the returned category is not important.
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (popcount(device) > 1) {
- // Multiple device selection is either:
- // - speaker + one other device: give priority to speaker in this case.
- // - one A2DP device + another device: happens with duplicated output. In this case
- // retain the device on the A2DP output as the other must not correspond to an active
- // selection if not the speaker.
- // - HDMI-CEC system audio mode only output: give priority to available item in order.
- if (device & AUDIO_DEVICE_OUT_SPEAKER) {
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
- device = AUDIO_DEVICE_OUT_HDMI_ARC;
- } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
- device = AUDIO_DEVICE_OUT_AUX_LINE;
- } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
- device = AUDIO_DEVICE_OUT_SPDIF;
- } else {
- device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
- }
- }
-
- /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
- if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
- device = AUDIO_DEVICE_OUT_SPEAKER;
-
- ALOGW_IF(popcount(device) != 1,
- "getDeviceForVolume() invalid device combination: %08x",
- device);
-
- return device;
-}
-
-//static
-ApmGains::device_category ApmGains::getDeviceCategory(audio_devices_t device)
-{
- switch(getDeviceForVolume(device)) {
- case AUDIO_DEVICE_OUT_EARPIECE:
- return ApmGains::DEVICE_CATEGORY_EARPIECE;
- case AUDIO_DEVICE_OUT_WIRED_HEADSET:
- case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
- return ApmGains::DEVICE_CATEGORY_HEADSET;
- case AUDIO_DEVICE_OUT_LINE:
- case AUDIO_DEVICE_OUT_AUX_DIGITAL:
- /*USB? Remote submix?*/
- return ApmGains::DEVICE_CATEGORY_EXT_MEDIA;
- case AUDIO_DEVICE_OUT_SPEAKER:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
- case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
- case AUDIO_DEVICE_OUT_USB_ACCESSORY:
- case AUDIO_DEVICE_OUT_USB_DEVICE:
- case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
- default:
- return ApmGains::DEVICE_CATEGORY_SPEAKER;
- }
-}
-
-//static
-float ApmGains::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
- int indexInUi)
-{
- ApmGains::device_category deviceCategory = ApmGains::getDeviceCategory(device);
- const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
-
- // the volume index in the UI is relative to the min and max volume indices for this stream type
- int nbSteps = 1 + curve[ApmGains::VOLMAX].mIndex -
- curve[ApmGains::VOLMIN].mIndex;
- int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
- (streamDesc.mIndexMax - streamDesc.mIndexMin);
-
- // find what part of the curve this index volume belongs to, or if it's out of bounds
- int segment = 0;
- if (volIdx < curve[ApmGains::VOLMIN].mIndex) { // out of bounds
- return 0.0f;
- } else if (volIdx < curve[ApmGains::VOLKNEE1].mIndex) {
- segment = 0;
- } else if (volIdx < curve[ApmGains::VOLKNEE2].mIndex) {
- segment = 1;
- } else if (volIdx <= curve[ApmGains::VOLMAX].mIndex) {
- segment = 2;
- } else { // out of bounds
- return 1.0f;
- }
-
- // linear interpolation in the attenuation table in dB
- float decibels = curve[segment].mDBAttenuation +
- ((float)(volIdx - curve[segment].mIndex)) *
- ( (curve[segment+1].mDBAttenuation -
- curve[segment].mDBAttenuation) /
- ((float)(curve[segment+1].mIndex -
- curve[segment].mIndex)) );
-
- float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
-
- ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
- curve[segment].mIndex, volIdx,
- curve[segment+1].mIndex,
- curve[segment].mDBAttenuation,
- decibels,
- curve[segment+1].mDBAttenuation,
- amplification);
-
- return amplification;
-}
-
-
-
-AudioGain::AudioGain(int index, bool useInChannelMask)
-{
- mIndex = index;
- mUseInChannelMask = useInChannelMask;
- memset(&mGain, 0, sizeof(struct audio_gain));
-}
-
-void AudioGain::getDefaultConfig(struct audio_gain_config *config)
-{
- config->index = mIndex;
- config->mode = mGain.mode;
- config->channel_mask = mGain.channel_mask;
- if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- config->values[0] = mGain.default_value;
- } else {
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- config->values[i] = mGain.default_value;
- }
- }
- if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- config->ramp_duration_ms = mGain.min_ramp_ms;
- }
-}
-
-status_t AudioGain::checkConfig(const struct audio_gain_config *config)
-{
- if ((config->mode & ~mGain.mode) != 0) {
- return BAD_VALUE;
- }
- if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
- if ((config->values[0] < mGain.min_value) ||
- (config->values[0] > mGain.max_value)) {
- return BAD_VALUE;
- }
- } else {
- if ((config->channel_mask & ~mGain.channel_mask) != 0) {
- return BAD_VALUE;
- }
- uint32_t numValues;
- if (mUseInChannelMask) {
- numValues = audio_channel_count_from_in_mask(config->channel_mask);
- } else {
- numValues = audio_channel_count_from_out_mask(config->channel_mask);
- }
- for (size_t i = 0; i < numValues; i++) {
- if ((config->values[i] < mGain.min_value) ||
- (config->values[i] > mGain.max_value)) {
- return BAD_VALUE;
- }
- }
- }
- if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
- if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
- (config->ramp_duration_ms > mGain.max_ramp_ms)) {
- return BAD_VALUE;
- }
- }
- return NO_ERROR;
-}
-
-void AudioGain::dump(int fd, int spaces, int index) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
-}
-
-
-// --- StreamDescriptor class implementation
-
-StreamDescriptor::StreamDescriptor()
- : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
-{
- mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
-}
-
-int StreamDescriptor::getVolumeIndex(audio_devices_t device)
-{
- device = ApmGains::getDeviceForVolume(device);
- // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
- if (mIndexCur.indexOfKey(device) < 0) {
- device = AUDIO_DEVICE_OUT_DEFAULT;
- }
- return mIndexCur.valueFor(device);
-}
-
-void StreamDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%s %02d %02d ",
- mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
- result.append(buffer);
- for (size_t i = 0; i < mIndexCur.size(); i++) {
- snprintf(buffer, SIZE, "%04x : %02d, ",
- mIndexCur.keyAt(i),
- mIndexCur.valueAt(i));
- result.append(buffer);
- }
- result.append("\n");
-
- write(fd, result.string(), result.size());
-}
-
-}; // namespace android
diff --git a/services/audiopolicy/managerdefault/Gains.h b/services/audiopolicy/managerdefault/Gains.h
deleted file mode 100644
index b4ab129..0000000
--- a/services/audiopolicy/managerdefault/Gains.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace android {
-
-class VolumeCurvePoint
-{
-public:
- int mIndex;
- float mDBAttenuation;
-};
-
-class StreamDescriptor;
-
-class ApmGains
-{
-public :
- // 4 points to define the volume attenuation curve, each characterized by the volume
- // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
- // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
- enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
-
- // device categories used for volume curve management.
- enum device_category {
- DEVICE_CATEGORY_HEADSET,
- DEVICE_CATEGORY_SPEAKER,
- DEVICE_CATEGORY_EARPIECE,
- DEVICE_CATEGORY_EXT_MEDIA,
- DEVICE_CATEGORY_CNT
- };
-
- // returns the category the device belongs to with regard to volume curve management
- static ApmGains::device_category getDeviceCategory(audio_devices_t device);
-
- // extract one device relevant for volume control from multiple device selection
- static audio_devices_t getDeviceForVolume(audio_devices_t device);
-
- static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
- int indexInUi);
-
- // default volume curve
- static const VolumeCurvePoint sDefaultVolumeCurve[ApmGains::VOLCNT];
- // default volume curve for media strategy
- static const VolumeCurvePoint sDefaultMediaVolumeCurve[ApmGains::VOLCNT];
- // volume curve for non-media audio on ext media outputs (HDMI, Line, etc)
- static const VolumeCurvePoint sExtMediaSystemVolumeCurve[ApmGains::VOLCNT];
- // volume curve for media strategy on speakers
- static const VolumeCurvePoint sSpeakerMediaVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[ApmGains::VOLCNT];
- // volume curve for sonification strategy on speakers
- static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[ApmGains::VOLCNT];
- static const VolumeCurvePoint sDefaultSystemVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[ApmGains::VOLCNT];
- static const VolumeCurvePoint sHeadsetSystemVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sDefaultVoiceVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sLinearVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sSilentVolumeCurve[ApmGains::VOLCNT];
- static const VolumeCurvePoint sFullScaleVolumeCurve[ApmGains::VOLCNT];
- // default volume curves per stream and device category. See initializeVolumeCurves()
- static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][ApmGains::DEVICE_CATEGORY_CNT];
-};
-
-
-class AudioGain: public RefBase
-{
-public:
- AudioGain(int index, bool useInChannelMask);
- virtual ~AudioGain() {}
-
- void dump(int fd, int spaces, int index) const;
-
- void getDefaultConfig(struct audio_gain_config *config);
- status_t checkConfig(const struct audio_gain_config *config);
- int mIndex;
- struct audio_gain mGain;
- bool mUseInChannelMask;
-};
-
-
-// stream descriptor used for volume control
-class StreamDescriptor
-{
-public:
- StreamDescriptor();
-
- int getVolumeIndex(audio_devices_t device);
- void dump(int fd);
-
- int mIndexMin; // min volume index
- int mIndexMax; // max volume index
- KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device
- bool mCanBeMuted; // true is the stream can be muted
-
- const VolumeCurvePoint *mVolumeCurve[ApmGains::DEVICE_CATEGORY_CNT];
-};
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c2df489..e9c96c6 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -35,7 +35,6 @@
#include <binder/ProcessInfoService.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
-#include <cutils/multiuser.h>
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
@@ -123,9 +122,8 @@
// should be ok for now.
static CameraService *gCameraService;
-CameraService::CameraService()
- : mEventLog(DEFAULT_EVICTION_LOG_LENGTH), mSoundRef(0), mModule(0), mFlashlight(0)
-{
+CameraService::CameraService() : mEventLog(DEFAULT_EVICTION_LOG_LENGTH),
+ mLastUserId(DEFAULT_LAST_USER_ID), mSoundRef(0), mModule(0), mFlashlight(0) {
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
@@ -757,7 +755,8 @@
return INVALID_OPERATION;
}
-status_t CameraService::validateConnect(const String8& cameraId, /*inout*/int& clientUid) const {
+status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid)
+ const {
int callingPid = getCallingPid();
@@ -797,6 +796,13 @@
return -EACCES;
}
+ // Only allow clients who are being used by the current foreground device user.
+ if (mLastUserId != clientUserId && mLastUserId != DEFAULT_LAST_USER_ID) {
+ ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from non-foreground "
+ "device user)", callingPid);
+ return PERMISSION_DENIED;
+ }
+
return checkIfDeviceIsUsable(cameraId);
}
@@ -1163,6 +1169,21 @@
return OK;
}
+void CameraService::notifySystemEvent(int eventId, int arg0) {
+ switch(eventId) {
+ case ICameraService::USER_SWITCHED: {
+ doUserSwitch(/*newUserId*/arg0);
+ break;
+ }
+ case ICameraService::NO_EVENT:
+ default: {
+ ALOGW("%s: Received invalid system event from system_server: %d", __FUNCTION__,
+ eventId);
+ break;
+ }
+ }
+}
+
status_t CameraService::addListener(
const sp<ICameraServiceListener>& listener) {
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -1351,6 +1372,8 @@
// other clients from connecting in mServiceLockWrapper if held
mServiceLock.unlock();
+ // Do not clear caller identity, remote caller should be client proccess
+
for (auto& i : evicted) {
if (i.get() != nullptr) {
i->disconnect();
@@ -1392,6 +1415,60 @@
return clientDescriptorPtr->getValue();
}
+void CameraService::doUserSwitch(int newUserId) {
+ // Acquire mServiceLock and prevent other clients from connecting
+ std::unique_ptr<AutoConditionLock> lock =
+ AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
+
+ if (newUserId <= 0) {
+ ALOGW("%s: Bad user ID %d given during user switch, resetting to default.", __FUNCTION__,
+ newUserId);
+ newUserId = DEFAULT_LAST_USER_ID;
+ }
+
+ mLastUserId = newUserId;
+
+ // Current user has switched, evict all current clients.
+ std::vector<sp<BasicClient>> evicted;
+ for (auto& i : mActiveClientManager.getAll()) {
+ auto clientSp = i->getValue();
+
+ if (clientSp.get() == nullptr) {
+ ALOGE("%s: Dead client still in mActiveClientManager.", __FUNCTION__);
+ continue;
+ }
+
+ evicted.push_back(clientSp);
+
+ String8 curTime = getFormattedCurrentTime();
+
+ ALOGE("Evicting conflicting client for camera ID %s due to user change",
+ i->getKey().string());
+ // Log the clients evicted
+ mEventLog.add(String8::format("%s : EVICT device %s client for package %s (PID %"
+ PRId32 ", priority %" PRId32 ")\n - Evicted due to user switch.",
+ curTime.string(), i->getKey().string(),
+ String8{clientSp->getPackageName()}.string(), i->getOwnerId(),
+ i->getPriority()));
+
+ }
+
+ // Do not hold mServiceLock while disconnecting clients, but retain the condition
+ // blocking other clients from connecting in mServiceLockWrapper if held.
+ mServiceLock.unlock();
+
+ // Clear caller identity temporarily so client disconnect PID checks work correctly
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+
+ for (auto& i : evicted) {
+ i->disconnect();
+ }
+
+ IPCThreadState::self()->restoreCallingIdentity(token);
+
+ // Reacquire mServiceLock
+ mServiceLock.lock();
+}
void CameraService::logDisconnected(const String8& cameraId, int clientPid,
const String8& clientPackage) {
@@ -1411,16 +1488,18 @@
curTime.string(), cameraId.string(), clientPackage.string(), clientPid));
}
-status_t CameraService::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+
+ const int pid = getCallingPid();
+ const int selfPid = getpid();
+
// Permission checks
switch (code) {
case BnCameraService::CONNECT:
case BnCameraService::CONNECT_DEVICE:
- case BnCameraService::CONNECT_LEGACY:
- const int pid = getCallingPid();
- const int self_pid = getpid();
- if (pid != self_pid) {
+ case BnCameraService::CONNECT_LEGACY: {
+ if (pid != selfPid) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.CAMERA"))) {
@@ -1431,6 +1510,21 @@
}
}
break;
+ }
+ case BnCameraService::NOTIFY_SYSTEM_EVENT: {
+ if (pid != selfPid) {
+ // Ensure we're being called by system_server, or similar process with
+ // permissions to notify the camera service about system events
+ if (!checkCallingPermission(
+ String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+ const int uid = getCallingUid();
+ ALOGE("Permission Denial: cannot send updates to camera service about system"
+ " events from pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ break;
+ }
}
return BnCameraService::onTransact(code, data, reply, flags);
@@ -1544,7 +1638,11 @@
}
void CameraService::BasicClient::disconnect() {
- if (mDisconnected) return;
+ if (mDisconnected) {
+ ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__,
+ mCameraId);
+ return;
+ }
mDisconnected = true;;
mCameraService->removeByClient(this);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 53f1c72..ca1c504 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
+#include <cutils/multiuser.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <binder/AppOpsManager.h>
@@ -92,6 +93,11 @@
// Default number of messages to store in eviction log
static const size_t DEFAULT_EVICTION_LOG_LENGTH = 50;
+ enum {
+ // Default last user id
+ DEFAULT_LAST_USER_ID = 0,
+ };
+
// Implementation of BinderService<T>
static char const* getServiceName() { return "media.camera"; }
@@ -145,6 +151,8 @@
virtual status_t setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder);
+ virtual void notifySystemEvent(int eventId, int arg0);
+
// OK = supports api of that version, -EOPNOTSUPP = does not support
virtual status_t supportsCameraApi(
int cameraId, int apiVersion);
@@ -447,7 +455,7 @@
virtual void onFirstRef();
// Check if we can connect, before we acquire the service lock.
- status_t validateConnect(const String8& cameraId, /*inout*/int& clientUid) const;
+ status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid) const;
// Handle active client evictions, and update service state.
// Only call with with mServiceLock held.
@@ -485,6 +493,9 @@
// Circular buffer for storing event logging for dumps
RingBuffer<String8> mEventLog;
+ // UID of last user.
+ int mLastUserId;
+
/**
* Get the camera state for a given camera id.
*
@@ -530,6 +541,11 @@
sp<CameraService::BasicClient> removeClientLocked(const String8& cameraId);
/**
+ * Handle a notification that the current device user has changed.
+ */
+ void doUserSwitch(int newUserId);
+
+ /**
* Add a event log message that a client has been disconnected.
*/
void logDisconnected(const String8& cameraId, int clientPid, const String8& clientPackage);
@@ -702,22 +718,24 @@
"Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
halVersion, static_cast<int>(effectiveApiLevel));
- // Enforce client permissions and do basic sanity checks
- if((ret = validateConnect(cameraId, /*inout*/clientUid)) != NO_ERROR) {
- return ret;
- }
-
sp<CLIENT> client = nullptr;
{
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
+
if (lock == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting)."
, clientPid);
return -EBUSY;
}
+ // Enforce client permissions and do basic sanity checks
+ if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
+ return ret;
+ }
+ mLastUserId = multiuser_get_user_id(clientUid);
+
// Check the shim parameters after acquiring lock, if they have already been updated and
// we were doing a shim update, return immediately
if (shimUpdateOnly) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 87e0132..6b0f8b5 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -65,15 +65,29 @@
const Size MAX_PREVIEW_SIZE = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
// Treat the H.264 max size as the max supported video size.
MediaProfiles *videoEncoderProfiles = MediaProfiles::getInstance();
- int32_t maxVideoWidth = videoEncoderProfiles->getVideoEncoderParamByName(
- "enc.vid.width.max", VIDEO_ENCODER_H264);
- int32_t maxVideoHeight = videoEncoderProfiles->getVideoEncoderParamByName(
- "enc.vid.height.max", VIDEO_ENCODER_H264);
- const Size MAX_VIDEO_SIZE = {maxVideoWidth, maxVideoHeight};
+ Vector<video_encoder> encoders = videoEncoderProfiles->getVideoEncoders();
+ int32_t maxVideoWidth = 0;
+ int32_t maxVideoHeight = 0;
+ for (size_t i = 0; i < encoders.size(); i++) {
+ int width = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.width.max", encoders[i]);
+ int height = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.height.max", encoders[i]);
+ // Treat width/height separately here to handle the case where different
+ // profile might report max size of different aspect ratio
+ if (width > maxVideoWidth) {
+ maxVideoWidth = width;
+ }
+ if (height > maxVideoHeight) {
+ maxVideoHeight = height;
+ }
+ }
+ // This is just an upper bound and may not be an actually valid video size
+ const Size VIDEO_SIZE_UPPER_BOUND = {maxVideoWidth, maxVideoHeight};
res = getFilteredSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);
if (res != OK) return res;
- res = getFilteredSizes(MAX_VIDEO_SIZE, &availableVideoSizes);
+ res = getFilteredSizes(VIDEO_SIZE_UPPER_BOUND, &availableVideoSizes);
if (res != OK) return res;
// Select initial preview and video size that's under the initial bound and