summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp73
-rw-r--r--services/audioflinger/AudioFlinger.h3
-rw-r--r--services/audioflinger/ServiceUtilities.cpp7
-rw-r--r--services/audioflinger/ServiceUtilities.h1
-rw-r--r--services/audioflinger/Threads.cpp6
-rw-r--r--services/audiopolicy/AudioPolicyEffects.cpp77
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImpl.cpp35
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp35
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp217
-rw-r--r--services/audiopolicy/AudioPolicyManager.h31
-rw-r--r--services/camera/libcameraservice/api1/Camera2Client.cpp20
-rw-r--r--services/camera/libcameraservice/api1/client2/BurstCapture.cpp2
-rw-r--r--services/camera/libcameraservice/api1/client2/BurstCapture.h2
-rw-r--r--services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp2
-rw-r--r--services/camera/libcameraservice/api1/client2/CallbackProcessor.h2
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegProcessor.cpp2
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegProcessor.h2
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp14
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp2
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.h2
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.cpp2
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.h2
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.cpp4
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.h2
24 files changed, 440 insertions, 105 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e48af20..ea9d7d3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -650,6 +650,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
}
}
+ setAudioHwSyncForSession_l(thread, (audio_session_t)lSessionId);
}
if (lStatus != NO_ERROR) {
@@ -1604,22 +1605,69 @@ status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice)
audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId)
{
Mutex::Autolock _l(mLock);
+
+ ssize_t index = mHwAvSyncIds.indexOfKey(sessionId);
+ if (index >= 0) {
+ ALOGV("getAudioHwSyncForSession found ID %d for session %d",
+ mHwAvSyncIds.valueAt(index), sessionId);
+ return mHwAvSyncIds.valueAt(index);
+ }
+
+ audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
+ if (dev == NULL) {
+ return AUDIO_HW_SYNC_INVALID;
+ }
+ char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
+ AudioParameter param = AudioParameter(String8(reply));
+ free(reply);
+
+ int value;
+ if (param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), value) != NO_ERROR) {
+ ALOGW("getAudioHwSyncForSession error getting sync for session %d", sessionId);
+ return AUDIO_HW_SYNC_INVALID;
+ }
+
+ // allow only one session for a given HW A/V sync ID.
+ for (size_t i = 0; i < mHwAvSyncIds.size(); i++) {
+ if (mHwAvSyncIds.valueAt(i) == (audio_hw_sync_t)value) {
+ ALOGV("getAudioHwSyncForSession removing ID %d for session %d",
+ value, mHwAvSyncIds.keyAt(i));
+ mHwAvSyncIds.removeItemsAt(i);
+ break;
+ }
+ }
+
+ mHwAvSyncIds.add(sessionId, value);
+
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<PlaybackThread> thread = mPlaybackThreads.valueAt(i);
- if ((thread->hasAudioSession(sessionId) & ThreadBase::TRACK_SESSION) != 0) {
- // A session can only be on one thread, so exit after first match
- String8 reply = thread->getParameters(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC));
- AudioParameter param = AudioParameter(reply);
- int value;
- if (param.getInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value) == NO_ERROR) {
- return value;
- }
+ uint32_t sessions = thread->hasAudioSession(sessionId);
+ if (sessions & PlaybackThread::TRACK_SESSION) {
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), value);
+ thread->setParameters(param.toString());
break;
}
}
- return AUDIO_HW_SYNC_INVALID;
+
+ ALOGV("getAudioHwSyncForSession adding ID %d for session %d", value, sessionId);
+ return (audio_hw_sync_t)value;
+}
+
+// setAudioHwSyncForSession_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId)
+{
+ ssize_t index = mHwAvSyncIds.indexOfKey(sessionId);
+ if (index >= 0) {
+ audio_hw_sync_t syncId = mHwAvSyncIds.valueAt(index);
+ ALOGV("setAudioHwSyncForSession_l found ID %d for session %d", syncId, sessionId);
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AUDIO_PARAMETER_STREAM_HW_AV_SYNC), syncId);
+ thread->setParameters(param.toString());
+ }
}
+
// ----------------------------------------------------------------------------
@@ -1928,13 +1976,13 @@ sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t m
status_t status = inHwHal->open_input_stream(inHwHal, *input, device, &halconfig,
&inStream, flags, address.string(), source);
ALOGV("openInput_l() openInputStream returned input %p, SamplingRate %d"
- ", Format %#x, Channels %x, flags %#x, status %d",
+ ", Format %#x, Channels %x, flags %#x, status %d addr %s",
inStream,
halconfig.sample_rate,
halconfig.format,
halconfig.channel_mask,
flags,
- status);
+ status, address.string());
// If the input could not be opened with the requested parameters and we can handle the
// conversion internally, try to open again with the proposed parameters. The AudioFlinger can
@@ -2585,7 +2633,8 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
// Check whether the destination thread has a channel count of FCC_2, which is
// currently required for (most) effects. Prevent moving the effect chain here rather
// than disabling the addEffect_l() call in dstThread below.
- if (dstThread->mChannelCount != FCC_2) {
+ if ((dstThread->type() == ThreadBase::MIXER || dstThread->type() == ThreadBase::DUPLICATING) &&
+ dstThread->mChannelCount != FCC_2) {
ALOGW("moveEffectChain_l() effect chain failed because"
" destination thread %p channel count(%u) != %u",
dstThread, dstThread->mChannelCount, FCC_2);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1003017..4fb372d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -733,6 +733,8 @@ private:
// Effect chains without a valid thread
DefaultKeyedVector< audio_session_t , sp<EffectChain> > mOrphanEffectChains;
+ // list of sessions for which a valid HW A/V sync ID was retrieved from the HAL
+ DefaultKeyedVector< audio_session_t , audio_hw_sync_t >mHwAvSyncIds;
private:
sp<Client> registerPid(pid_t pid); // always returns non-0
@@ -741,6 +743,7 @@ private:
void closeOutputInternal_l(sp<PlaybackThread> thread);
status_t closeInput_nonvirtual(audio_io_handle_t input);
void closeInputInternal_l(sp<RecordThread> thread);
+ void setAudioHwSyncForSession_l(PlaybackThread *thread, audio_session_t sessionId);
#ifdef TEE_SINK
// all record threads serially share a common tee sink, which is re-created on format change
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 8246fef..fae19a1 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -50,6 +50,13 @@ bool captureHotwordAllowed() {
return ok;
}
+bool captureFmTunerAllowed() {
+ static const String16 sCaptureFmTunerAllowed("android.permission.ACCESS_FM_RADIO");
+ bool ok = checkCallingPermission(sCaptureFmTunerAllowed);
+ if (!ok) ALOGE("android.permission.ACCESS_FM_RADIO");
+ return ok;
+}
+
bool settingsAllowed() {
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index df6f6f4..ce18a90 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -23,6 +23,7 @@ extern pid_t getpid_cached;
bool recordingAllowed();
bool captureAudioOutputAllowed();
bool captureHotwordAllowed();
+bool captureFmTunerAllowed();
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
bool dumpAllowed();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e443476..71a6a73 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4660,7 +4660,11 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix()
if (outputsReady(outputTracks)) {
mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
} else {
- memset(mSinkBuffer, 0, mSinkBufferSize);
+ if (mMixerBufferValid) {
+ memset(mMixerBuffer, 0, mMixerBufferSize);
+ } else {
+ memset(mSinkBuffer, 0, mSinkBufferSize);
+ }
}
sleepTime = 0;
writeFrames = mNormalFrameCount;
diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/AudioPolicyEffects.cpp
index 3c1c042..e7e1b36 100644
--- a/services/audiopolicy/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/AudioPolicyEffects.cpp
@@ -105,26 +105,28 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
inputDesc->mRefCount++;
ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
-
- Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
- for (size_t i = 0; i < effects.size(); i++) {
- EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
- status_t status = fx->initCheck();
- if (status != NO_ERROR && status != ALREADY_EXISTS) {
- ALOGW("addInputEffects(): failed to create Fx %s on source %d",
+ if (inputDesc->mRefCount == 1) {
+ Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
+ for (size_t i = 0; i < effects.size(); i++) {
+ EffectDesc *effect = effects[i];
+ sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0,
+ audioSession, input);
+ status_t status = fx->initCheck();
+ if (status != NO_ERROR && status != ALREADY_EXISTS) {
+ ALOGW("addInputEffects(): failed to create Fx %s on source %d",
+ effect->mName, (int32_t)aliasSource);
+ // fx goes out of scope and strong ref on AudioEffect is released
+ continue;
+ }
+ for (size_t j = 0; j < effect->mParams.size(); j++) {
+ fx->setParameter(effect->mParams[j]);
+ }
+ ALOGV("addInputEffects(): added Fx %s on source: %d",
effect->mName, (int32_t)aliasSource);
- // fx goes out of scope and strong ref on AudioEffect is released
- continue;
- }
- for (size_t j = 0; j < effect->mParams.size(); j++) {
- fx->setParameter(effect->mParams[j]);
+ inputDesc->mEffects.add(fx);
}
- ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource);
- inputDesc->mEffects.add(fx);
+ inputDesc->setProcessorEnabled(true);
}
- inputDesc->setProcessorEnabled(true);
-
return status;
}
@@ -241,26 +243,28 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
}
procDesc->mRefCount++;
- ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount);
-
- Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
- for (size_t i = 0; i < effects.size(); i++) {
- EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, audioSession, output);
- status_t status = fx->initCheck();
- if (status != NO_ERROR && status != ALREADY_EXISTS) {
- ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
- effect->mName, audioSession);
- // fx goes out of scope and strong ref on AudioEffect is released
- continue;
+ ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
+ audioSession, procDesc->mRefCount);
+ if (procDesc->mRefCount == 1) {
+ Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
+ for (size_t i = 0; i < effects.size(); i++) {
+ EffectDesc *effect = effects[i];
+ sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0,
+ audioSession, output);
+ status_t status = fx->initCheck();
+ if (status != NO_ERROR && status != ALREADY_EXISTS) {
+ ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
+ effect->mName, audioSession);
+ // fx goes out of scope and strong ref on AudioEffect is released
+ continue;
+ }
+ ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
+ effect->mName, audioSession, (int32_t)stream);
+ procDesc->mEffects.add(fx);
}
- ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
- effect->mName, audioSession, (int32_t)stream);
- procDesc->mEffects.add(fx);
- }
-
- procDesc->setProcessorEnabled(true);
+ procDesc->setProcessorEnabled(true);
+ }
return status;
}
@@ -281,7 +285,8 @@ status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t outpu
EffectVector *procDesc = mOutputSessions.valueAt(index);
procDesc->mRefCount--;
- ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount);
+ ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
+ audioSession, procDesc->mRefCount);
if (procDesc->mRefCount == 0) {
procDesc->setProcessorEnabled(false);
procDesc->mEffects.clear();
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index 6cd0ac8..c06ca72 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -129,8 +129,11 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
if (mAudioPolicyManager == NULL) {
- return 0;
+ return AUDIO_IO_HANDLE_NONE;
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
@@ -158,6 +161,9 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return BAD_VALUE;
+ }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -182,6 +188,9 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return BAD_VALUE;
+ }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -238,11 +247,13 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
return 0;
}
// already checked by client, but double-check in case the client wrapper is bypassed
- if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) {
+ if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD &&
+ inputSource != AUDIO_SOURCE_FM_TUNER) {
return 0;
}
- if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
+ if (((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) ||
+ ((inputSource == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) {
return 0;
}
audio_io_handle_t input;
@@ -366,6 +377,9 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return 0;
+ }
if (mAudioPolicyManager == NULL) {
return 0;
}
@@ -376,8 +390,11 @@ uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return AUDIO_DEVICE_NONE;
+ }
if (mAudioPolicyManager == NULL) {
- return (audio_devices_t)0;
+ return AUDIO_DEVICE_NONE;
}
return mAudioPolicyManager->getDevicesForStream(stream);
}
@@ -422,8 +439,11 @@ status_t AudioPolicyService::setEffectEnabled(int id, bool enabled)
bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return false;
+ }
if (mAudioPolicyManager == NULL) {
- return 0;
+ return false;
}
Mutex::Autolock _l(mLock);
return mAudioPolicyManager->isStreamActive(stream, inPastMs);
@@ -431,8 +451,11 @@ bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inP
bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return false;
+ }
if (mAudioPolicyManager == NULL) {
- return 0;
+ return false;
}
Mutex::Autolock _l(mLock);
return mAudioPolicyManager->isStreamActiveRemotely(stream, inPastMs);
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index e1e81e1..09476c1 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -134,8 +134,11 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
if (mpAudioPolicy == NULL) {
- return 0;
+ return AUDIO_IO_HANDLE_NONE;
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
@@ -147,6 +150,9 @@ status_t AudioPolicyService::startOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return BAD_VALUE;
+ }
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
@@ -172,6 +178,9 @@ status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return BAD_VALUE;
+ }
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
@@ -228,11 +237,13 @@ audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
return 0;
}
// already checked by client, but double-check in case the client wrapper is bypassed
- if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) {
+ if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD &&
+ inputSource != AUDIO_SOURCE_FM_TUNER) {
return 0;
}
- if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
+ if (((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) ||
+ ((inputSource == AUDIO_SOURCE_FM_TUNER) && !captureFmTunerAllowed())) {
return 0;
}
@@ -368,6 +379,9 @@ status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return 0;
+ }
if (mpAudioPolicy == NULL) {
return 0;
}
@@ -378,8 +392,11 @@ uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return AUDIO_DEVICE_NONE;
+ }
if (mpAudioPolicy == NULL) {
- return (audio_devices_t)0;
+ return AUDIO_DEVICE_NONE;
}
return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
}
@@ -424,8 +441,11 @@ status_t AudioPolicyService::setEffectEnabled(int id, bool enabled)
bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return false;
+ }
if (mpAudioPolicy == NULL) {
- return 0;
+ return false;
}
Mutex::Autolock _l(mLock);
return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs);
@@ -433,8 +453,11 @@ bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inP
bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
{
+ if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ return false;
+ }
if (mpAudioPolicy == NULL) {
- return 0;
+ return false;
}
Mutex::Autolock _l(mLock);
return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs);
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 536987a..584e170 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -26,7 +26,7 @@
// 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
+#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
@@ -216,6 +216,10 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
const char *device_address)
{
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");
+ }
ALOGV("setDeviceConnectionState() device: %x, state %d, address %s",
device, state, address.string());
@@ -419,6 +423,10 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi
audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device);
devDesc->mAddress = (device_address == NULL) ? String8("") : String8(device_address);
+ // handle legacy remote submix case where the address was not always specified
+ if (deviceDistinguishesOnAddress(device) && (devDesc->mAddress.length() == 0)) {
+ devDesc->mAddress = String8("0");
+ }
ssize_t index;
DeviceVector *deviceVector;
@@ -707,7 +715,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
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_NO_BT_A2DP && config != AUDIO_POLICY_FORCE_SPEAKER ) {
ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
return;
}
@@ -854,7 +862,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
}
- ALOGV("getOutputForAttr() device %d, samplingRate %d, format %x, channelMask %x, flags %x",
+ ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x",
device, samplingRate, format, channelMask, flags);
audio_stream_type_t stream = streamTypefromAttributesInt(attr);
@@ -1119,6 +1127,20 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
return BAD_VALUE;
}
+ // cannot start playback of STREAM_TTS if any other output is being used
+ uint32_t beaconMuteLatency = 0;
+ if (stream == AUDIO_STREAM_TTS) {
+ ALOGV("\t found BEACON stream");
+ if (isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+ return INVALID_OPERATION;
+ } else {
+ beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
+ }
+ } else {
+ // some playback other than beacon starts
+ beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
+ }
+
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
// increment usage count for this stream on the requested output:
@@ -1130,8 +1152,9 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
audio_devices_t newDevice = getNewOutputDevice(output, false /*fromCache*/);
routing_strategy strategy = getStrategy(stream);
bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
- (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
- uint32_t waitMs = 0;
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL) ||
+ (beaconMuteLatency > 0);
+ uint32_t waitMs = beaconMuteLatency;
bool force = false;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
@@ -1145,7 +1168,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
force = true;
}
// wait for audio on other active outputs to be presented when starting
- // a notification so that audio focus effect can propagate.
+ // a notification so that audio focus effect can propagate, or that a mute/unmute
+ // event occurred for beacon
uint32_t latency = desc->latency();
if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
waitMs = latency;
@@ -1189,6 +1213,9 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ // always handle stream stop, check which stream type is stopping
+ handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
+
// handle special case for sonification while in call
if (isInCall()) {
handleIncallSonification(stream, false, false);
@@ -1356,11 +1383,14 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
config.channel_mask = channelMask;
config.format = format;
+ // handle legacy remote submix case where the address was not always specified
+ String8 address = deviceDistinguishesOnAddress(device) ? String8("0") : String8("");
+
status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
&input,
&config,
&device,
- String8(""),
+ address,
halInputSource,
flags);
@@ -1584,12 +1614,17 @@ status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
}
mStreams[stream].mIndexCur.add(device, index);
- // compute and apply stream volume on all outputs according to connected device
+ // update volume on all outputs whose current device is also selected by the same
+ // strategy as the device specified by the caller
+ audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+ if ((device != AUDIO_DEVICE_OUT_DEFAULT) && (device & strategyDevice) == 0) {
+ return NO_ERROR;
+ }
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
getDeviceForVolume(mOutputs.valueAt(i)->device());
- if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
status = volStatus;
@@ -2653,7 +2688,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
mA2dpSuspended(false),
mSpeakerDrcEnabled(false), mNextUniqueId(1),
- mAudioPortGeneration(1)
+ mAudioPortGeneration(1),
+ mBeaconMuteRefCount(0),
+ mBeaconPlayingRefCount(0),
+ mBeaconMuted(false)
{
mUidCached = getuid();
mpClientInterface = clientInterface;
@@ -2787,6 +2825,14 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
inputDesc->mInputSource = AUDIO_SOURCE_MIC;
inputDesc->mDevice = profileType;
+ // find the address
+ DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
+ // the inputs vector must be of size 1, but we don't want to crash here
+ String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
+ : String8("");
+ ALOGV(" for input device 0x%x using address %s", profileType, address.string());
+ ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = inputDesc->mSamplingRate;
config.channel_mask = inputDesc->mChannelMask;
@@ -2796,7 +2842,7 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa
&input,
&config,
&inputDesc->mDevice,
- String8(""),
+ address,
AUDIO_SOURCE_MIC,
AUDIO_INPUT_FLAG_NONE);
@@ -3816,6 +3862,8 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output,
// use device for strategy media
// 7: the strategy DTMF is active on the output:
// use device for strategy DTMF
+ // 8: 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) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
@@ -3832,6 +3880,8 @@ audio_devices_t AudioPolicyManager::getNewOutputDevice(audio_io_handle_t output,
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
} else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_TRANSMITTED_THROUGH_SPEAKER)) {
+ device = getDeviceForStrategy(STRATEGY_TRANSMITTED_THROUGH_SPEAKER, fromCache);
}
ALOGV("getNewOutputDevice() selected device %x", device);
@@ -3910,16 +3960,20 @@ AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
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_TTS:
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;
}
}
uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
// flags to strategy mapping
+ if ((attr->flags & AUDIO_FLAG_BEACON) == AUDIO_FLAG_BEACON) {
+ return (uint32_t) STRATEGY_TRANSMITTED_THROUGH_SPEAKER;
+ }
if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
}
@@ -3967,6 +4021,74 @@ void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t
}
}
+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:
+ mBeaconMuteRefCount++;
+ break;
+ case STOPPING_OUTPUT:
+ if (mBeaconMuteRefCount > 0) {
+ mBeaconMuteRefCount--;
+ }
+ break;
+ case STARTING_BEACON:
+ mBeaconPlayingRefCount++;
+ break;
+ case STOPPING_BEACON:
+ if (mBeaconPlayingRefCount > 0) {
+ mBeaconPlayingRefCount--;
+ }
+ break;
+ }
+
+ if (mBeaconMuteRefCount > 0) {
+ // any playback causes beacon to be muted
+ return setBeaconMute(true);
+ } else {
+ // no other playback: unmute when beacon starts playing, mute when it stops
+ return setBeaconMute(mBeaconPlayingRefCount == 0);
+ }
+}
+
+uint32_t AudioPolicyManager::setBeaconMute(bool mute) {
+ ALOGV("setBeaconMute(%d) mBeaconMuteRefCount=%d mBeaconPlayingRefCount=%d",
+ mute, mBeaconMuteRefCount, mBeaconPlayingRefCount);
+ // keep track of muted state to avoid repeating mute/unmute operations
+ if (mBeaconMuted != mute) {
+ // mute/unmute AUDIO_STREAM_TTS on all outputs
+ ALOGV("\t muting %d", mute);
+ uint32_t maxLatency = 0;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ setStreamMute(AUDIO_STREAM_TTS, mute/*on*/,
+ desc->mIoHandle,
+ 0 /*delay*/, AUDIO_DEVICE_NONE);
+ const uint32_t latency = desc->latency() * 2;
+ if (latency > maxLatency) {
+ maxLatency = latency;
+ }
+ }
+ mBeaconMuted = mute;
+ return maxLatency;
+ }
+ return 0;
+}
+
audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
bool fromCache)
{
@@ -3980,6 +4102,14 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
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*/);
@@ -4158,6 +4288,10 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
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;
}
@@ -4248,6 +4382,7 @@ uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp<AudioOutputDescriptor>
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ curDevice = curDevice & outputDesc->mProfile->mSupportedDevices.types();
bool mute = shouldMute && (curDevice & device) && (curDevice != device);
bool doMute = false;
@@ -4348,11 +4483,15 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
// Do not change the routing if:
- // - the requested device is AUDIO_DEVICE_NONE
- // - the requested device is the same as current device and force is not specified.
+ // the requested device is AUDIO_DEVICE_NONE
+ // OR the requested device is the same as current device
+ // AND force is not specified
+ // AND the output is connected by a valid audio patch.
// Doing this check here allows the caller to call setOutputDevice() without conditions
- if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
- ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force &&
+ outputDesc->mPatchHandle != 0) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d",
+ device, output);
return muteWaitMs;
}
@@ -4667,6 +4806,11 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
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;
@@ -4891,6 +5035,16 @@ const AudioPolicyManager::VolumeCurvePoint
};
const AudioPolicyManager::VolumeCurvePoint
+ AudioPolicyManager::sLinearVolumeCurve[AudioPolicyManager::VOLCNT] = {
+ {0, -96.0f}, {33, -68.0f}, {66, -34.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+ AudioPolicyManager::sSilentVolumeCurve[AudioPolicyManager::VOLCNT] = {
+ {0, -96.0f}, {1, -96.0f}, {2, -96.0f}, {100, -96.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
*AudioPolicyManager::sVolumeProfiles[AUDIO_STREAM_CNT]
[AudioPolicyManager::DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
@@ -4948,10 +5102,11 @@ const AudioPolicyManager::VolumeCurvePoint
sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
},
{ // AUDIO_STREAM_TTS
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
- sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
- sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
- sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
+ // "Transmitted Through Speaker": always silent except on DEVICE_CATEGORY_SPEAKER
+ sSilentVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sLinearVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sSilentVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+ sSilentVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA
},
};
@@ -5843,12 +5998,28 @@ void AudioPolicyManager::AudioPort::importAudioPort(const sp<AudioPort> port) {
}
}
}
+ for (size_t k = 0 ; k < port->mGains.size() ; k++) {
+ sp<AudioGain> gain = port->mGains.itemAt(k);
+ if (gain != 0) {
+ bool hasGain = false;
+ for (size_t l = 0 ; l < mGains.size() ; l++) {
+ if (gain == mGains.itemAt(l)) {
+ hasGain = true;
+ break;
+ }
+ }
+ if (!hasGain) { // never import a gain twice
+ mGains.add(gain);
+ }
+ }
+ }
}
void AudioPolicyManager::AudioPort::clearCapabilities() {
mChannelMasks.clear();
mFormats.clear();
mSamplingRates.clear();
+ mGains.clear();
}
void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
@@ -6791,7 +6962,11 @@ void AudioPolicyManager::DeviceVector::loadDevicesFromName(char *name,
ARRAY_SIZE(sDeviceNameToEnumTable),
devName);
if (type != AUDIO_DEVICE_NONE) {
- add(new DeviceDescriptor(String8(""), type));
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(""), type);
+ if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ dev->mAddress = String8("0");
+ }
+ add(dev);
} else {
sp<DeviceDescriptor> deviceDesc =
declaredDevices.getDeviceFromName(String8(devName));
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index 0ea7b97..50d7831 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -187,6 +187,7 @@ protected:
STRATEGY_SONIFICATION_RESPECTFUL,
STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
NUM_STRATEGIES
};
@@ -434,6 +435,8 @@ protected:
static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT];
static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
+ static const VolumeCurvePoint sLinearVolumeCurve[AudioPolicyManager::VOLCNT];
+ static const VolumeCurvePoint sSilentVolumeCurve[AudioPolicyManager::VOLCNT];
// default volume curves per stream and device category. See initializeVolumeCurves()
static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
@@ -600,8 +603,10 @@ protected:
audio_io_handle_t output, audio_devices_t device);
// check that volume change is permitted, compute and send new volume to audio hardware
- status_t checkAndSetVolume(audio_stream_type_t stream, int index, audio_io_handle_t output,
- audio_devices_t device, int delayMs = 0, bool force = false);
+ virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs = 0, bool force = false);
// apply all stream volumes to the specified output and device
void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
@@ -806,6 +811,18 @@ protected:
sp<AudioPatch> mCallTxPatch;
sp<AudioPatch> mCallRxPatch;
+ // for supporting "beacon" streams, i.e. streams that only play on speaker, and never
+ // when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
+ enum {
+ STARTING_OUTPUT,
+ STARTING_BEACON,
+ STOPPING_OUTPUT,
+ STOPPING_BEACON
+ };
+ uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
+ uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
+ bool mBeaconMuted; // has STREAM_TTS been muted
+
#ifdef AUDIO_POLICY_TEST
Mutex mLock;
Condition mWaitWorkCV;
@@ -820,10 +837,9 @@ protected:
uint32_t mTestChannels;
uint32_t mTestLatencyMs;
#endif //AUDIO_POLICY_TEST
-
-private:
static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
int indexInUi);
+private:
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -851,6 +867,13 @@ private:
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
+ uint32_t handleEventForBeacon(int event);
+ uint32_t setBeaconMute(bool mute);
};
};
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index dd2f64d..8e40534 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -420,12 +420,20 @@ void Camera2Client::disconnect() {
ALOGV("Camera %d: Waiting for threads", mCameraId);
- mStreamingProcessor->join();
- mFrameProcessor->join();
- mCaptureSequencer->join();
- mJpegProcessor->join();
- mZslProcessorThread->join();
- mCallbackProcessor->join();
+ {
+ // Don't wait with lock held, in case the other threads need to
+ // complete callbacks that re-enter Camera2Client
+ mBinderSerializationLock.unlock();
+
+ mStreamingProcessor->join();
+ mFrameProcessor->join();
+ mCaptureSequencer->join();
+ mJpegProcessor->join();
+ mZslProcessorThread->join();
+ mCallbackProcessor->join();
+
+ mBinderSerializationLock.lock();
+ }
ALOGV("Camera %d: Deleting streams", mCameraId);
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
index 0bfdfd4..5502dcb 100644
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
+++ b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
@@ -44,7 +44,7 @@ status_t BurstCapture::start(Vector<CameraMetadata> &/*metadatas*/,
return INVALID_OPERATION;
}
-void BurstCapture::onFrameAvailable() {
+void BurstCapture::onFrameAvailable(const BufferItem &/*item*/) {
ALOGV("%s", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
if(!mInputChanged) {
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.h b/services/camera/libcameraservice/api1/client2/BurstCapture.h
index ea321fd..c3b7722 100644
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.h
+++ b/services/camera/libcameraservice/api1/client2/BurstCapture.h
@@ -39,7 +39,7 @@ public:
BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
virtual ~BurstCapture();
- virtual void onFrameAvailable();
+ virtual void onFrameAvailable(const BufferItem& item);
virtual status_t start(Vector<CameraMetadata> &metadatas, int32_t firstCaptureId);
protected:
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index bf3318e..eadaa00 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -46,7 +46,7 @@ CallbackProcessor::~CallbackProcessor() {
deleteStream();
}
-void CallbackProcessor::onFrameAvailable() {
+void CallbackProcessor::onFrameAvailable(const BufferItem& /*item*/) {
Mutex::Autolock l(mInputMutex);
if (!mCallbackAvailable) {
mCallbackAvailable = true;
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index 613f5be..7fdc329 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -44,7 +44,7 @@ class CallbackProcessor:
CallbackProcessor(sp<Camera2Client> client);
~CallbackProcessor();
- void onFrameAvailable();
+ void onFrameAvailable(const BufferItem& item);
// Set to NULL to disable the direct-to-app callback window
status_t setCallbackWindow(sp<ANativeWindow> callbackWindow);
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index b433781..2772267 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -51,7 +51,7 @@ JpegProcessor::~JpegProcessor() {
deleteStream();
}
-void JpegProcessor::onFrameAvailable() {
+void JpegProcessor::onFrameAvailable(const BufferItem& /*item*/) {
Mutex::Autolock l(mInputMutex);
if (!mCaptureAvailable) {
mCaptureAvailable = true;
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index b2c05df..2040b30 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -47,7 +47,7 @@ class JpegProcessor:
~JpegProcessor();
// CpuConsumer listener implementation
- void onFrameAvailable();
+ void onFrameAvailable(const BufferItem& item);
status_t updateStream(const Parameters &params);
status_t deleteStream();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 7b90d28..42a5507 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2954,6 +2954,10 @@ status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
staticInfo(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, 2, 2);
if (!sensorSize.count) return NO_INIT;
+ camera_metadata_ro_entry_t pixelArraySize =
+ staticInfo(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, 2, 2);
+ if (!pixelArraySize.count) return NO_INIT;
+
float arrayAspect = static_cast<float>(fastInfo.arrayWidth) /
fastInfo.arrayHeight;
float stillAspect = static_cast<float>(pictureWidth) / pictureHeight;
@@ -3003,6 +3007,16 @@ status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
vertCropFactor = (arrayAspect < stillAspect) ?
(arrayAspect / stillAspect) : 1.f;
}
+
+ /**
+ * Convert the crop factors w.r.t the active array size to the crop factors
+ * w.r.t the pixel array size.
+ */
+ horizCropFactor *= (static_cast<float>(fastInfo.arrayWidth) /
+ pixelArraySize.data.i32[0]);
+ vertCropFactor *= (static_cast<float>(fastInfo.arrayHeight) /
+ pixelArraySize.data.i32[1]);
+
ALOGV("Horiz crop factor: %f, vert crop fact: %f",
horizCropFactor, vertCropFactor);
/**
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 9e7fff8..470624b 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -635,7 +635,7 @@ status_t StreamingProcessor::incrementStreamingIds() {
return OK;
}
-void StreamingProcessor::onFrameAvailable() {
+void StreamingProcessor::onFrameAvailable(const BufferItem& /*item*/) {
ATRACE_CALL();
Mutex::Autolock l(mMutex);
if (!mRecordingFrameAvailable) {
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 8466af4..1d679a4 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -80,7 +80,7 @@ class StreamingProcessor:
status_t incrementStreamingIds();
// Callback for new recording frames from HAL
- virtual void onFrameAvailable();
+ virtual void onFrameAvailable(const BufferItem& item);
// Callback from stagefright which returns used recording frames
void releaseRecordingFrame(const sp<IMemory>& mem);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 8f78103..8b7e4b4 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -66,7 +66,7 @@ ZslProcessor::~ZslProcessor() {
disconnect();
}
-void ZslProcessor::onFrameAvailable() {
+void ZslProcessor::onFrameAvailable(const BufferItem& /*item*/) {
Mutex::Autolock l(mInputMutex);
if (!mZslBufferAvailable) {
mZslBufferAvailable = true;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index b6533cf..2099c38 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -53,7 +53,7 @@ class ZslProcessor:
~ZslProcessor();
// From mZslConsumer
- virtual void onFrameAvailable();
+ virtual void onFrameAvailable(const BufferItem& item);
// From FrameProcessor
virtual void onResultAvailable(const CaptureResult &result);
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index f8562ec..d0f29de 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -268,7 +268,7 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
return OK;
}
-void RingBufferConsumer::onFrameAvailable() {
+void RingBufferConsumer::onFrameAvailable(const android::BufferItem& item) {
status_t err;
{
@@ -321,7 +321,7 @@ void RingBufferConsumer::onFrameAvailable() {
item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
} // end of mMutex lock
- ConsumerBase::onFrameAvailable();
+ ConsumerBase::onFrameAvailable(item);
}
void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index da97a11..90fd734 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -165,7 +165,7 @@ class RingBufferConsumer : public ConsumerBase,
private:
// Override ConsumerBase::onFrameAvailable
- virtual void onFrameAvailable();
+ virtual void onFrameAvailable(const android::BufferItem& item);
void pinBufferLocked(const BufferItem& item);
void unpinBuffer(const BufferItem& item);