Merge "more complete 64bit mediaserver build targets"
diff --git a/media/audioserver/Android.bp b/media/audioserver/Android.bp
index ca3c81c..ddfd57a 100644
--- a/media/audioserver/Android.bp
+++ b/media/audioserver/Android.bp
@@ -32,7 +32,6 @@
"libpowermanager",
"libutils",
"libvibrator",
-
],
// TODO check if we still need all of these include directories
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 19414a0..5072323 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "Codec2Buffer"
#include <utils/Log.h>
+#include <android-base/properties.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <android/hardware/drm/1.0/types.h>
#include <hidlmemory/FrameworkUtils.h>
@@ -580,7 +581,23 @@
}
std::shared_ptr<C2Buffer> GraphicMetadataBuffer::asC2Buffer() {
-#ifndef __LP64__
+#ifdef __LP64__
+ static std::once_flag s_checkOnce;
+ static bool s_64bitonly {false};
+ std::call_once(s_checkOnce, [&](){
+ const std::string abi32list =
+ ::android::base::GetProperty("ro.product.cpu.abilist32", "");
+ if (abi32list.empty()) {
+ s_64bitonly = true;
+ }
+ });
+
+ if (!s_64bitonly) {
+ ALOGE("GraphicMetadataBuffer does not work in 32+64 system if compiled as 64-bit object");
+ return nullptr;
+ }
+#endif
+
VideoNativeMetadata *meta = (VideoNativeMetadata *)base();
ANativeWindowBuffer *buffer = (ANativeWindowBuffer *)meta->pBuffer;
if (buffer == nullptr) {
@@ -613,10 +630,6 @@
}
return C2Buffer::CreateGraphicBuffer(
block->share(C2Rect(buffer->width, buffer->height), C2Fence()));
-#else
- ALOGE("GraphicMetadataBuffer does not work on 64-bit arch");
- return nullptr;
-#endif
}
// ConstGraphicBlockBuffer
diff --git a/media/codec2/vndk/C2DmaBufAllocator.cpp b/media/codec2/vndk/C2DmaBufAllocator.cpp
index 59e82e2..750aa31 100644
--- a/media/codec2/vndk/C2DmaBufAllocator.cpp
+++ b/media/codec2/vndk/C2DmaBufAllocator.cpp
@@ -315,8 +315,8 @@
if (mUsageMapper) {
res = mUsageMapper(usage, capacity, heap_name, flags);
} else {
- // No system-uncached yet, so disabled for now
- if (0 && !(usage.expected & (C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE)))
+ if (C2DmaBufAllocator::system_uncached_supported() &&
+ !(usage.expected & (C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE)))
*heap_name = "system-uncached";
else
*heap_name = "system";
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 499ab72..dee3bf6 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -822,7 +822,13 @@
};
static C2R setDmaBufUsage(bool /* mayBlock */, C2P<C2StoreDmaBufUsageInfo> &me) {
- strncpy(me.set().m.heapName, "system", me.v.flexCount());
+ long long usage = (long long)me.get().m.usage;
+ if (C2DmaBufAllocator::system_uncached_supported() &&
+ !(usage & (C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE))) {
+ strncpy(me.set().m.heapName, "system-uncached", me.v.flexCount());
+ } else {
+ strncpy(me.set().m.heapName, "system", me.v.flexCount());
+ }
me.set().m.allocFlags = 0;
return C2R::Ok();
};
diff --git a/media/codec2/vndk/include/C2DmaBufAllocator.h b/media/codec2/vndk/include/C2DmaBufAllocator.h
index abb8307..d84c8c6 100644
--- a/media/codec2/vndk/include/C2DmaBufAllocator.h
+++ b/media/codec2/vndk/include/C2DmaBufAllocator.h
@@ -84,6 +84,16 @@
void setUsageMapper(const UsageMapperFn& mapper, uint64_t minUsage, uint64_t maxUsage,
uint64_t blockSize);
+ static bool system_uncached_supported(void) {
+ static int cached_result = -1;
+
+ if (cached_result == -1) {
+ struct stat buffer;
+ cached_result = (stat("/dev/dma_heap/system-uncached", &buffer) == 0);
+ }
+ return (cached_result == 1);
+ };
+
private:
c2_status_t mInit;
BufferAllocator mBufferAllocator;
diff --git a/media/codecs/amrwb/dec/src/wb_syn_filt.cpp b/media/codecs/amrwb/dec/src/wb_syn_filt.cpp
index d960322..f12828d 100644
--- a/media/codecs/amrwb/dec/src/wb_syn_filt.cpp
+++ b/media/codecs/amrwb/dec/src/wb_syn_filt.cpp
@@ -181,12 +181,14 @@
L_tmp4 = fxp_mac_16by16(yy[(i<<2)+3 - j], a[j], L_tmp4);
L_tmp1 = shl_int32(L_tmp1, 4);
+ L_tmp1 = L_tmp1 == INT32_MIN ? INT32_MIN + 1 : L_tmp1;
y[(i<<2)] = yy[(i<<2)] = amr_wb_round(-L_tmp1);
L_tmp2 = fxp_mac_16by16(yy[(i<<2)], a[1], L_tmp2);
L_tmp2 = shl_int32(L_tmp2, 4);
+ L_tmp2 = L_tmp2 == INT32_MIN ? INT32_MIN + 1 : L_tmp2;
y[(i<<2)+1] = yy[(i<<2)+1] = amr_wb_round(-L_tmp2);
@@ -197,12 +199,14 @@
L_tmp3 = fxp_mac_16by16(yy[(i<<2) + 1], a[1], L_tmp3);
L_tmp3 = shl_int32(L_tmp3, 4);
+ L_tmp3 = L_tmp3 == INT32_MIN ? INT32_MIN + 1 : L_tmp3;
y[(i<<2)+2] = yy[(i<<2)+2] = amr_wb_round(-L_tmp3);
L_tmp4 = fxp_mac_16by16(yy[(i<<2)+2], a[1], L_tmp4);
L_tmp4 = shl_int32(L_tmp4, 4);
+ L_tmp4 = L_tmp4 == INT32_MIN ? INT32_MIN + 1 : L_tmp4;
y[(i<<2)+3] = yy[(i<<2)+3] = amr_wb_round(-L_tmp4);
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index aa740a7..f1bb001 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -112,7 +112,6 @@
"libprocessgroup",
"libshmemcompat",
"libutils",
- "libvibrator",
],
export_shared_lib_headers: [
"audioflinger-aidl-unstable-cpp",
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index 39b0ceb..ee5b770 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -53,7 +53,7 @@
header_libs: [
"libaudiohal_headers",
"libbase_headers",
- "libmedia_headers"
+ "libmedia_headers",
],
shared_libs: [
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 0695bdb..21d60ea 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -260,7 +260,12 @@
return AMEDIA_ERROR_INVALID_PARAMETER;
}
+#if !defined(__ANDROID_APEX__)
+ // TODO(jiyong): replace this #ifdef with a __builtin_available check.
AMediaCodec* encoder = AMediaCodec_createEncoderByTypeForClient(destinationMime, mPid, mUid);
+#else
+ AMediaCodec* encoder = AMediaCodec_createEncoderByType(destinationMime);
+#endif
if (encoder == nullptr) {
LOG(ERROR) << "Unable to create encoder for type " << destinationMime;
return AMEDIA_ERROR_UNSUPPORTED;
@@ -290,7 +295,12 @@
return AMEDIA_ERROR_INVALID_PARAMETER;
}
+#if !defined(__ANDROID_APEX__)
+ // TODO(jiyong): replace this #ifdef with a __builtin_available check.
mDecoder = AMediaCodec_createDecoderByTypeForClient(sourceMime, mPid, mUid);
+#else
+ mDecoder = AMediaCodec_createDecoderByType(sourceMime);
+#endif
if (mDecoder == nullptr) {
LOG(ERROR) << "Unable to create decoder for type " << sourceMime;
return AMEDIA_ERROR_UNSUPPORTED;
diff --git a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
index d2ffb01..e3f3f4f 100644
--- a/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
+++ b/media/libmediatranscoding/transcoder/include/media/VideoTrackTranscoder.h
@@ -97,8 +97,12 @@
BlockingQueue<std::function<void()>> mCodecMessageQueue;
std::shared_ptr<AMediaFormat> mDestinationFormat;
std::shared_ptr<AMediaFormat> mActualOutputFormat;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-private-field"
+ // These could be unused on older platforms
pid_t mPid;
uid_t mUid;
+#pragma clang diagnostic pop
};
} // namespace android
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 237b66e..2b389fe 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -167,11 +167,11 @@
AMediaCodecCryptoInfo_setPattern; # introduced=24
AMediaCodec_configure;
AMediaCodec_createCodecByName;
- AMediaCodec_createCodecByNameForClient; # apex #introduced = 31
+ AMediaCodec_createCodecByNameForClient; # apex # introduced=31
AMediaCodec_createDecoderByType;
- AMediaCodec_createDecoderByTypeForClient; # apex #introduced = 31
+ AMediaCodec_createDecoderByTypeForClient; # apex # introduced=31
AMediaCodec_createEncoderByType;
- AMediaCodec_createEncoderByTypeForClient; # apex #introduced = 31
+ AMediaCodec_createEncoderByTypeForClient; # apex # introduced=31
AMediaCodec_delete;
AMediaCodec_dequeueInputBuffer;
AMediaCodec_dequeueOutputBuffer;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 80afe9d..59876c6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -198,10 +198,18 @@
~SourceClientDescriptor() override = default;
+ void connect(audio_patch_handle_t patchHandle, const sp<DeviceDescriptor>& sinkDevice) {
+ mPatchHandle = patchHandle;
+ mSinkDevice = sinkDevice;
+ }
+ void disconnect() {
+ mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ mSinkDevice = nullptr;
+ }
+ bool isConnected() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
- void setPatchHandle(audio_patch_handle_t patchHandle) { mPatchHandle = patchHandle; }
-
sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
+ sp<DeviceDescriptor> sinkDevice() const { return mSinkDevice; }
wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
@@ -213,6 +221,7 @@
private:
audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
const sp<DeviceDescriptor> mSrcDevice;
+ sp<DeviceDescriptor> mSinkDevice;
wp<SwAudioOutputDescriptor> mSwOutput;
wp<HwAudioOutputDescriptor> mHwOutput;
};
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0ec57bf..51abef1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -246,6 +246,7 @@
if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
(((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
(desc->mDirectOpenCount == 0))) {
+ clearAudioSourcesForOutput(output);
closeOutput(output);
}
}
@@ -384,7 +385,11 @@
DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevices);
}
-
+ // Reconnect Audio Source
+ for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
+ auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
+ checkAudioSourceForAttributes(attributes);
+ }
if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
cleanUpForDevice(device);
}
@@ -469,7 +474,7 @@
// Case 1: A2DP active device switches from primary to primary
// module
// Case 2: A2DP device config changes on primary module.
- if (audio_is_a2dp_out_device(device)) {
+ if (audio_is_a2dp_out_device(device) && hasPrimaryOutput()) {
sp<HwModule> module = mHwModules.getModuleForDeviceType(device, encodedFormat);
audio_module_handle_t primaryHandle = mPrimaryOutput->getModuleHandle();
if (availablePrimaryOutputDevices().contains(devDesc) &&
@@ -563,11 +568,7 @@
ALOGV("updateCallRouting device rxDevice %s txDevice %s",
rxDevices.itemAt(0)->toString().c_str(), txSourceDevice->toString().c_str());
- // release existing RX patch if any
- if (mCallRxPatch != 0) {
- releaseAudioPatchInternal(mCallRxPatch->getHandle());
- mCallRxPatch.clear();
- }
+ disconnectTelephonyRxAudioSource();
// release TX patch if any
if (mCallTxPatch != 0) {
releaseAudioPatchInternal(mCallTxPatch->getHandle());
@@ -615,8 +616,7 @@
if (!createRxPatch) {
muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
} else { // create RX path audio patch
- mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
-
+ connectTelephonyRxAudioSource();
// If the TX device is on the primary HW module but RX device is
// on other HW module, SinkMetaData of telephony input should handle it
// assuming the device uses audio HAL V5.0 and above
@@ -679,6 +679,24 @@
return false;
}
+void AudioPolicyManager::connectTelephonyRxAudioSource()
+{
+ disconnectTelephonyRxAudioSource();
+ const struct audio_port_config source = {
+ .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE,
+ .ext.device.type = AUDIO_DEVICE_IN_TELEPHONY_RX, .ext.device.address = ""
+ };
+ const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
+ status_t status = startAudioSource(&source, &aa, &mCallRxSourceClientPort, 0/*uid*/);
+ ALOGE_IF(status != NO_ERROR, "%s failed to start Telephony Rx AudioSource", __func__);
+}
+
+void AudioPolicyManager::disconnectTelephonyRxAudioSource()
+{
+ stopAudioSource(mCallRxSourceClientPort);
+ mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
+}
+
void AudioPolicyManager::setPhoneState(audio_mode_t state)
{
ALOGV("setPhoneState() state %d", state);
@@ -746,10 +764,7 @@
if (state == AUDIO_MODE_IN_CALL) {
updateCallRouting(rxDevices, delayMs);
} else if (oldState == AUDIO_MODE_IN_CALL) {
- if (mCallRxPatch != 0) {
- releaseAudioPatchInternal(mCallRxPatch->getHandle());
- mCallRxPatch.clear();
- }
+ disconnectTelephonyRxAudioSource();
if (mCallTxPatch != 0) {
releaseAudioPatchInternal(mCallTxPatch->getHandle());
mCallTxPatch.clear();
@@ -3858,6 +3873,41 @@
sinkDevice->toAudioPortConfig(&sinkPortConfig, &patch->sinks[i]);
patchBuilder.addSink(sinkPortConfig);
+ // Whatever Sw or Hw bridge, we do attach an SwOutput to an Audio Source for
+ // volume management purpose (tracking activity)
+ // In case of Hw bridge, it is a Work Around. The mixPort used is the one declared
+ // in config XML to reach the sink so that is can be declared as available.
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ sp<SwAudioOutputDescriptor> outputDesc = nullptr;
+ if (sourceDesc != nullptr) {
+ // take care of dynamic routing for SwOutput selection,
+ audio_attributes_t attributes = sourceDesc->attributes();
+ audio_stream_type_t stream = sourceDesc->stream();
+ audio_attributes_t resultAttr;
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = sourceDesc->config().sample_rate;
+ config.channel_mask = sourceDesc->config().channel_mask;
+ config.format = sourceDesc->config().format;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ bool isRequestedDeviceForExclusiveUse = false;
+ output_type_t outputType;
+ getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
+ &stream, sourceDesc->uid(), &config, &flags,
+ &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
+ nullptr, &outputType);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %s",
+ __FUNCTION__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
+ outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGE("%s output is duplicated", __func__);
+ return INVALID_OPERATION;
+ }
+ sourceDesc->setSwOutput(outputDesc);
+ }
// create a software bridge in PatchPanel if:
// - source and sink devices are on different HW modules OR
// - audio HAL version is < 3.0
@@ -3873,49 +3923,25 @@
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
}
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- if (sourceDesc != nullptr) {
- // take care of dynamic routing for SwOutput selection,
- audio_attributes_t attributes = sourceDesc->attributes();
- audio_stream_type_t stream = sourceDesc->stream();
- audio_attributes_t resultAttr;
- audio_config_t config = AUDIO_CONFIG_INITIALIZER;
- config.sample_rate = sourceDesc->config().sample_rate;
- config.channel_mask = sourceDesc->config().channel_mask;
- config.format = sourceDesc->config().format;
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- bool isRequestedDeviceForExclusiveUse = false;
- output_type_t outputType;
- getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
- &stream, sourceDesc->uid(), &config, &flags,
- &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
- nullptr, &outputType);
- if (output == AUDIO_IO_HANDLE_NONE) {
- ALOGV("%s no output for device %s",
- __FUNCTION__, sinkDevice->toString().c_str());
- return INVALID_OPERATION;
- }
- } else {
+ if (sourceDesc == nullptr) {
SortedVector<audio_io_handle_t> outputs =
getOutputsForDevices(DeviceVector(sinkDevice), 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
output = selectOutput(outputs);
- }
- if (output != AUDIO_IO_HANDLE_NONE) {
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
- ALOGV("%s output for device %s is duplicated",
- __FUNCTION__, sinkDevice->toString().c_str());
- return INVALID_OPERATION;
+ if (output != AUDIO_IO_HANDLE_NONE) {
+ outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %s is duplicated",
+ __FUNCTION__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
}
+ }
+ if (outputDesc != nullptr) {
audio_port_config srcMixPortConfig = {};
outputDesc->toAudioPortConfig(&srcMixPortConfig, &patch->sources[0]);
- if (sourceDesc != nullptr) {
- sourceDesc->setSwOutput(outputDesc);
- }
// for volume control, we may need a valid stream
srcMixPortConfig.ext.mix.usecase.stream = sourceDesc != nullptr ?
sourceDesc->stream() : AUDIO_STREAM_PATCH;
@@ -4006,8 +4032,9 @@
sp<SwAudioOutputDescriptor> outputDesc =
mOutputs.getOutputFromId(patch->sources[1].id);
if (outputDesc == NULL) {
- ALOGE("%s output not found for id %d", __func__, patch->sources[0].id);
- return BAD_VALUE;
+ ALOGW("%s output not found for id %d", __func__, patch->sources[0].id);
+ // releaseOutput has already called closeOuput in case of direct output
+ return NO_ERROR;
}
if (patchDesc->getHandle() != outputDesc->getPatchHandle()) {
// force SwOutput patch removal as AF counter part patch has already gone.
@@ -4273,15 +4300,19 @@
disconnectAudioSource(sourceDesc);
audio_attributes_t attributes = sourceDesc->attributes();
- sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
-
+ // May the device (dynamic) have been disconnected/reconnected, id has changed.
+ sp<DeviceDescriptor> srcDevice = mAvailableInputDevices.getDevice(
+ sourceDesc->srcDevice()->type(),
+ String8(sourceDesc->srcDevice()->address().c_str()),
+ AUDIO_FORMAT_DEFAULT);
DeviceVector sinkDevices =
- mEngine->getOutputDevicesForAttributes(attributes, nullptr, true);
+ mEngine->getOutputDevicesForAttributes(attributes, nullptr, false /*fromCache*/);
ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for attributes");
sp<DeviceDescriptor> sinkDevice = sinkDevices.itemAt(0);
- ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
- __FUNCTION__, sinkDevice->toString().c_str());
-
+ if (!mAvailableOutputDevices.contains(sinkDevice)) {
+ ALOGE("%s Device %s not available", __func__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
PatchBuilder patchBuilder;
patchBuilder.addSink(sinkDevice).addSource(srcDevice);
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
@@ -4291,7 +4322,7 @@
ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
return INVALID_OPERATION;
}
- sourceDesc->setPatchHandle(handle);
+ sourceDesc->connect(handle, sinkDevice);
// SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
@@ -4588,6 +4619,10 @@
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
+ if (!sourceDesc->isConnected()) {
+ ALOGV("%s port Id %d already disconnected", __FUNCTION__, sourceDesc->portId());
+ return NO_ERROR;
+ }
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
status_t status = stopSource(swOutput, sourceDesc);
@@ -4607,7 +4642,9 @@
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
- return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
+ status_t status = releaseAudioPatchInternal(sourceDesc->getPatchHandle());
+ sourceDesc->disconnect();
+ return status;
}
sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@@ -4722,10 +4759,7 @@
}
}
- if (mPrimaryOutput == 0) {
- ALOGE("Failed to open primary output");
- status = NO_INIT;
- }
+ ALOGW_IF(mPrimaryOutput == nullptr, "The policy configuration does not declare a primary output");
// Silence ALOGV statements
property_set("log.tag." LOG_TAG, "D");
@@ -4835,7 +4869,7 @@
setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
}
}
- if (mPrimaryOutput == 0 &&
+ if (mPrimaryOutput == nullptr &&
outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
}
@@ -4912,6 +4946,10 @@
void AudioPolicyManager::removeOutput(audio_io_handle_t output)
{
+ if (mPrimaryOutput != 0 && mPrimaryOutput == mOutputs.valueFor(output)) {
+ ALOGV("%s: removing primary output", __func__);
+ mPrimaryOutput = nullptr;
+ }
mOutputs.removeItem(output);
selectOutputForMusicEffects();
}
@@ -5360,6 +5398,29 @@
mEngine->getProductStrategyForAttributes(rAttr);
}
+void AudioPolicyManager::checkAudioSourceForAttributes(const audio_attributes_t &attr)
+{
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc != nullptr && followsSameRouting(attr, sourceDesc->attributes())
+ && sourceDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE
+ && !isCallRxAudioSource(sourceDesc)) {
+ connectAudioSource(sourceDesc);
+ }
+ }
+}
+
+void AudioPolicyManager::clearAudioSourcesForOutput(audio_io_handle_t output)
+{
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc != nullptr && sourceDesc->swOutput().promote() != nullptr
+ && sourceDesc->swOutput().promote()->mIoHandle == output) {
+ disconnectAudioSource(sourceDesc);
+ }
+ }
+}
+
void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr)
{
auto psId = mEngine->getProductStrategyForAttributes(attr);
@@ -5456,7 +5517,7 @@
newDevices.types());
}
sp<SourceClientDescriptor> source = getSourceForAttributesOnOutput(srcOut, attr);
- if (source != 0){
+ if (source != nullptr && !isCallRxAudioSource(source)) {
connectAudioSource(source);
}
}
@@ -5479,6 +5540,7 @@
for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
checkOutputForAttributes(attributes);
+ checkAudioSourceForAttributes(attributes);
}
}
@@ -6450,9 +6512,10 @@
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->srcDevice()->equals(deviceDesc)) {
- ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
- stopAudioSource(sourceDesc->portId());
+ if (sourceDesc->isConnected() && (sourceDesc->srcDevice()->equals(deviceDesc) ||
+ sourceDesc->sinkDevice()->equals(deviceDesc))
+ && !isCallRxAudioSource(sourceDesc)) {
+ disconnectAudioSource(sourceDesc);
}
}
@@ -6466,10 +6529,14 @@
release = true;
}
}
+ const char *address = deviceDesc->address().c_str();
for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++) {
const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
- sink->ext.device.type == deviceDesc->type()) {
+ sink->ext.device.type == deviceDesc->type() &&
+ (strnlen(address, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0
+ || strncmp(sink->ext.device.address, address,
+ AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
release = true;
}
}
@@ -6810,6 +6877,10 @@
return nullptr;
}
}
+ if (mPrimaryOutput == nullptr && profile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ ALOGV("%s(): re-assigning mPrimaryOutput", __func__);
+ mPrimaryOutput = desc;
+ }
return desc;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index eca8781..eba0c44 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -556,6 +556,15 @@
*/
void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0);
+ bool isCallRxAudioSource(const sp<SourceClientDescriptor> &source) {
+ return mCallRxSourceClientPort != AUDIO_PORT_HANDLE_NONE
+ && source == mAudioSources.valueFor(mCallRxSourceClientPort);
+ }
+
+ void connectTelephonyRxAudioSource();
+
+ void disconnectTelephonyRxAudioSource();
+
/**
* @brief updates routing for all inputs.
*/
@@ -571,6 +580,16 @@
*/
void checkOutputForAttributes(const audio_attributes_t &attr);
+ /**
+ * @brief checkAudioSourceForAttributes checks if any AudioSource following the same routing
+ * as the given audio attributes is not routed and try to connect it.
+ * It must be called once checkOutputForAttributes has been called for orphans AudioSource,
+ * aka AudioSource not attached to any Audio Output (e.g. AudioSource connected to direct
+ * Output which has been disconnected (and output closed) due to sink device unavailable).
+ * @param attr to be considered
+ */
+ void checkAudioSourceForAttributes(const audio_attributes_t &attr);
+
bool followsSameRouting(const audio_attributes_t &lAttr,
const audio_attributes_t &rAttr) const;
@@ -740,6 +759,7 @@
sp<SourceClientDescriptor> getSourceForAttributesOnOutput(audio_io_handle_t output,
const audio_attributes_t &attr);
+ void clearAudioSourcesForOutput(audio_io_handle_t output);
void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
@@ -786,7 +806,6 @@
SoundTriggerSessionCollection mSoundTriggerSessions;
sp<AudioPatch> mCallTxPatch;
- sp<AudioPatch> mCallRxPatch;
HwAudioOutputCollection mHwOutputs;
SourceClientCollection mAudioSources;
@@ -825,6 +844,10 @@
// Cached product strategy ID corresponding to legacy strategy STRATEGY_PHONE
product_strategy_t mCommunnicationStrategy;
+ // The port handle of the hardware audio source created internally for the Call RX audio
+ // end point.
+ audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
+
private:
void onNewAudioModulesAvailableInt(DeviceVector *newDevices);