Merge "GenericSource: timed text support" into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 142b7cb..42a03bb 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -32,6 +32,7 @@
struct ABuffer;
struct MemoryDealer;
+struct DescribeColorFormatParams;
struct ACodec : public AHierarchicalStateMachine, public CodecBase {
ACodec();
@@ -305,6 +306,8 @@
OMX_ERRORTYPE error = OMX_ErrorUndefined,
status_t internalError = UNKNOWN_ERROR);
+ static void describeDefaultColorFormat(DescribeColorFormatParams &describeParams);
+
status_t requestIDRFrame();
status_t setParameters(const sp<AMessage> ¶ms);
diff --git a/include/media/stagefright/foundation/ABuffer.h b/include/media/stagefright/foundation/ABuffer.h
index 28f0aed..602f7ab 100644
--- a/include/media/stagefright/foundation/ABuffer.h
+++ b/include/media/stagefright/foundation/ABuffer.h
@@ -42,6 +42,9 @@
void setRange(size_t offset, size_t size);
+ // create buffer from dup of some memory block
+ static sp<ABuffer> CreateAsCopy(const void *data, size_t capacity);
+
void setInt32Data(int32_t data) { mInt32Data = data; }
int32_t int32Data() const { return mInt32Data; }
diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp
index 9cea721..1b20e36 100644
--- a/media/img_utils/src/TiffEntry.cpp
+++ b/media/img_utils/src/TiffEntry.cpp
@@ -203,14 +203,20 @@
}
break;
}
- case FLOAT:
- case DOUBLE: {
+ case FLOAT: {
const float* typed_data = getData<float>();
for (size_t i = 0; i < cappedCount; ++i) {
output.appendFormat("%f ", typed_data[i]);
}
break;
}
+ case DOUBLE: {
+ const double* typed_data = getData<double>();
+ for (size_t i = 0; i < cappedCount; ++i) {
+ output.appendFormat("%f ", typed_data[i]);
+ }
+ break;
+ }
default: {
output.append("unknown type ");
break;
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
index d85289e..ac41734 100644
--- a/media/img_utils/src/TiffWriter.cpp
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -66,10 +66,6 @@
return BAD_VALUE;
}
- if (LOG_NDEBUG == 0) {
- log();
- }
-
uint32_t totalSize = getTotalSize();
KeyedVector<uint32_t, uint32_t> offsetVector;
@@ -104,7 +100,9 @@
ifd = ifd->getNextIfd();
}
- log();
+ if (LOG_NDEBUG == 0) {
+ log();
+ }
for (size_t i = 0; i < offVecSize; ++i) {
uint32_t ifdKey = offsetVector.keyAt(i);
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index e9c5e8e..dacb144 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -62,18 +62,18 @@
player_type MediaPlayerFactory::getDefaultPlayerType() {
char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.use-nuplayer", value, NULL)
+ if (property_get("media.stagefright.use-awesome", value, NULL)
&& (!strcmp("1", value) || !strcasecmp("true", value))) {
- return NU_PLAYER;
+ return STAGEFRIGHT_PLAYER;
}
// TODO: remove this EXPERIMENTAL developer settings property
- if (property_get("persist.sys.media.use-nuplayer", value, NULL)
+ if (property_get("persist.sys.media.use-awesome", value, NULL)
&& !strcasecmp("true", value)) {
- return NU_PLAYER;
+ return STAGEFRIGHT_PLAYER;
}
- return STAGEFRIGHT_PLAYER;
+ return NU_PLAYER;
}
status_t MediaPlayerFactory::registerFactory(IFactory* factory,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b6cc742..1b1d7a9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2709,6 +2709,83 @@
}
}
+// static
+void ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) {
+ MediaImage &image = params.sMediaImage;
+ memset(&image, 0, sizeof(image));
+
+ image.mType = MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN;
+ image.mNumPlanes = 0;
+
+ const OMX_COLOR_FORMATTYPE fmt = params.eColorFormat;
+ // we need stride and slice-height to be non-zero
+ if (params.nStride == 0 || params.nSliceHeight == 0) {
+ ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
+ fmt, fmt, params.nStride, params.nSliceHeight);
+ return;
+ }
+
+ image.mWidth = params.nFrameWidth;
+ image.mHeight = params.nFrameHeight;
+
+ // only supporting YUV420
+ if (fmt != OMX_COLOR_FormatYUV420Planar &&
+ fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
+ fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
+ fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar) {
+ ALOGW("do not know color format 0x%x = %d", fmt, fmt);
+ return;
+ }
+
+ // set-up YUV format
+ image.mType = MediaImage::MEDIA_IMAGE_TYPE_YUV;
+ image.mNumPlanes = 3;
+ image.mBitDepth = 8;
+ image.mPlane[image.Y].mOffset = 0;
+ image.mPlane[image.Y].mColInc = 1;
+ image.mPlane[image.Y].mRowInc = params.nStride;
+ image.mPlane[image.Y].mHorizSubsampling = 1;
+ image.mPlane[image.Y].mVertSubsampling = 1;
+
+ switch (fmt) {
+ case OMX_COLOR_FormatYUV420Planar: // used for YV12
+ case OMX_COLOR_FormatYUV420PackedPlanar:
+ image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
+ image.mPlane[image.U].mColInc = 1;
+ image.mPlane[image.U].mRowInc = params.nStride / 2;
+ image.mPlane[image.U].mHorizSubsampling = 2;
+ image.mPlane[image.U].mVertSubsampling = 2;
+
+ image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset
+ + (params.nStride * params.nSliceHeight / 4);
+ image.mPlane[image.V].mColInc = 1;
+ image.mPlane[image.V].mRowInc = params.nStride / 2;
+ image.mPlane[image.V].mHorizSubsampling = 2;
+ image.mPlane[image.V].mVertSubsampling = 2;
+ break;
+
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder
+ case OMX_COLOR_FormatYUV420PackedSemiPlanar:
+ // NV12
+ image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight;
+ image.mPlane[image.U].mColInc = 2;
+ image.mPlane[image.U].mRowInc = params.nStride;
+ image.mPlane[image.U].mHorizSubsampling = 2;
+ image.mPlane[image.U].mVertSubsampling = 2;
+
+ image.mPlane[image.V].mOffset = image.mPlane[image.U].mOffset + 1;
+ image.mPlane[image.V].mColInc = 2;
+ image.mPlane[image.V].mRowInc = params.nStride;
+ image.mPlane[image.V].mHorizSubsampling = 2;
+ image.mPlane[image.V].mVertSubsampling = 2;
+ break;
+
+ default:
+ TRESPASS();
+ }
+}
+
status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) {
// TODO: catch errors an return them instead of using CHECK
OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -2736,6 +2813,33 @@
notify->setInt32("slice-height", videoDef->nSliceHeight);
notify->setInt32("color-format", videoDef->eColorFormat);
+
+ DescribeColorFormatParams describeParams;
+ InitOMXParams(&describeParams);
+ describeParams.eColorFormat = videoDef->eColorFormat;
+ describeParams.nFrameWidth = videoDef->nFrameWidth;
+ describeParams.nFrameHeight = videoDef->nFrameHeight;
+ describeParams.nStride = videoDef->nStride;
+ describeParams.nSliceHeight = videoDef->nSliceHeight;
+
+ OMX_INDEXTYPE describeColorFormatIndex;
+ if (mOMX->getExtensionIndex(
+ mNode, "OMX.google.android.index.describeColorFormat",
+ &describeColorFormatIndex) ||
+ mOMX->getParameter(
+ mNode, describeColorFormatIndex,
+ &describeParams, sizeof(describeParams))) {
+ describeDefaultColorFormat(describeParams);
+ }
+
+ if (describeParams.sMediaImage.mType != MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN) {
+ notify->setBuffer(
+ "image-data",
+ ABuffer::CreateAsCopy(
+ &describeParams.sMediaImage,
+ sizeof(describeParams.sMediaImage)));
+ }
+
OMX_CONFIG_RECTTYPE rect;
InitOMXParams(&rect);
rect.nPortIndex = kPortIndexOutput;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 15e062e..e944766 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1948,6 +1948,18 @@
Mutex::Autolock al(mBufferLock);
info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
info->mOwnedByClient = true;
+
+ // set image-data
+ if (info->mFormat != NULL) {
+ sp<ABuffer> imageData;
+ if (info->mFormat->findBuffer("image-data", &imageData)) {
+ info->mData->meta()->setBuffer("image-data", imageData);
+ }
+ int32_t left, top, right, bottom;
+ if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) {
+ info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
+ }
+ }
}
return index;
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index 6173db4..c93c7e8 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -40,6 +40,14 @@
mOwnsData(false) {
}
+// static
+sp<ABuffer> ABuffer::CreateAsCopy(const void *data, size_t capacity)
+{
+ sp<ABuffer> res = new ABuffer(capacity);
+ memcpy(res->data(), data, capacity);
+ return res;
+}
+
ABuffer::~ABuffer() {
if (mOwnsData) {
if (mData != NULL) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c3aafd9..c959b9f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -167,7 +167,7 @@
// Initially this heap is used to allocate client buffers for "fast" AudioRecord.
// Eventually it will be the single buffer that FastCapture writes into via HAL read(),
// and that all "fast" AudioRecord clients read from. In either case, the size can be small.
-static const size_t kRecordThreadReadOnlyHeapSize = 0x1000;
+static const size_t kRecordThreadReadOnlyHeapSize = 0x2000;
// ----------------------------------------------------------------------------
@@ -4862,8 +4862,8 @@
// or primary output sample rate is unknown, and capture sample rate is reasonable
((primaryOutputSampleRate == 0) &&
((mSampleRate == 44100 || mSampleRate == 48000)))) &&
- // and the buffer size is < 10 ms
- (mFrameCount * 1000) / mSampleRate < 10;
+ // and the buffer size is < 12 ms
+ (mFrameCount * 1000) / mSampleRate < 12;
break;
// case FastCapture_Dynamic:
}
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 737cacd..c5248fe 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -30,6 +30,10 @@
// 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>
@@ -228,14 +232,6 @@
}
ALOGV("setDeviceConnectionState() connecting device %x", device);
- if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
- return INVALID_OPERATION;
- }
- // outputs should never be empty here
- ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
- "checkOutputsForDevice() returned no outputs but status OK");
- ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
- outputs.size());
// register new device as available
index = mAvailableOutputDevices.add(devDesc);
if (index >= 0) {
@@ -248,6 +244,15 @@
return NO_MEMORY;
}
+ if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
+ mAvailableOutputDevices.remove(devDesc);
+ return INVALID_OPERATION;
+ }
+ // outputs should never be empty here
+ ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
+ "checkOutputsForDevice() returned no outputs but status OK");
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+ outputs.size());
break;
// handle output device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
@@ -261,8 +266,6 @@
mAvailableOutputDevices.remove(devDesc);
checkOutputsForDevice(device, state, outputs, address);
- // not currently handling multiple simultaneous submixes: ignoring remote submix
- // case and address
} break;
default:
@@ -295,10 +298,13 @@
// 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)
+ // always force when disconnecting (a non-duplicated device)
+ || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
setOutputDevice(mOutputs.keyAt(i),
getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
- !mOutputs.valueAt(i)->isDuplicated(),
- 0);
+ force, 0);
}
mpClientInterface->onAudioPortListUpdate();
@@ -617,20 +623,10 @@
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- bool found = false;
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
- if (profile->isCompatibleProfile(device, samplingRate, format,
- channelMask,
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
- found = true;
- }
- } else {
- if (profile->isCompatibleProfile(device, samplingRate, format,
- channelMask,
- AUDIO_OUTPUT_FLAG_DIRECT)) {
- found = true;
- }
- }
+ bool found = profile->isCompatibleProfile(device, samplingRate,
+ NULL /*updatedSamplingRate*/, format, channelMask,
+ flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
return profile;
}
@@ -1895,6 +1891,7 @@
if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
patch->sources[0].sample_rate,
+ NULL, // updatedSamplingRate
patch->sources[0].format,
patch->sources[0].channel_mask,
AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
@@ -1940,7 +1937,8 @@
}
if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
- patch->sinks[0].sample_rate,
+ patch->sinks[0].sample_rate,
+ NULL, /*updatedSampleRate*/
patch->sinks[0].format,
patch->sinks[0].channel_mask,
// FIXME for the parameter type,
@@ -2643,10 +2641,39 @@
{
if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
return String8("a2dp_sink_address=")+address;
+ } else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ return String8("mix=")+address;
}
return address;
}
+void AudioPolicyManager::findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+ const String8 address /*in*/,
+ SortedVector<audio_io_handle_t>& outputs /*out*/) {
+ // look for a match on the given address on the addresses of the outputs:
+ // find the address by finding the patch that maps to this output
+ ssize_t patchIdx = mAudioPatches.indexOfKey(desc->mPatchHandle);
+ //ALOGV(" inspecting output %d (patch %d) for supported device=0x%x",
+ // outputIdx, patchIdx, desc->mProfile->mSupportedDevices.types());
+ if (patchIdx >= 0) {
+ const sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patchIdx);
+ const int numSinks = patchDesc->mPatch.num_sinks;
+ for (ssize_t j=0; j < numSinks; j++) {
+ if (patchDesc->mPatch.sinks[j].type == AUDIO_PORT_TYPE_DEVICE) {
+ const char* patchAddr =
+ patchDesc->mPatch.sinks[j].ext.device.address;
+ if (strncmp(patchAddr,
+ address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d on same address %s",
+ desc->mIoHandle, patchDesc->mPatch.sinks[j].ext.device.address);
+ outputs.add(desc->mIoHandle);
+ break;
+ }
+ }
+ }
+ }
+}
+
status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs,
@@ -2659,8 +2686,13 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) {
- ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
- outputs.add(mOutputs.keyAt(i));
+ if (!deviceDistinguishesOnAddress(device)) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ } else {
+ ALOGV(" checking address match due to device 0x%x", device);
+ findIoHandlesByAddress(desc, address, outputs);
+ }
}
}
// then look for output profiles that can be routed to this device
@@ -2679,6 +2711,8 @@
}
}
+ ALOGV(" found %d profiles, %d outputs", profiles.size(), outputs.size());
+
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
return BAD_VALUE;
@@ -2691,13 +2725,13 @@
// nothing to do if one output is already opened for this profile
size_t j;
- for (j = 0; j < mOutputs.size(); j++) {
- desc = mOutputs.valueAt(j);
+ for (j = 0; j < outputs.size(); j++) {
+ desc = mOutputs.valueFor(outputs.itemAt(j));
if (!desc->isDuplicated() && desc->mProfile == profile) {
break;
}
}
- if (j != mOutputs.size()) {
+ if (j != outputs.size()) {
continue;
}
@@ -2730,7 +2764,7 @@
if (profile->mSamplingRates[0] == 0) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+ ALOGV("checkOutputsForDevice() supported sampling rates %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2740,7 +2774,7 @@
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() direct output sup formats %s",
+ ALOGV("checkOutputsForDevice() supported formats %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2750,7 +2784,7 @@
if (profile->mChannelMasks[0] == 0) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+ ALOGV("checkOutputsForDevice() supported channel masks %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2763,7 +2797,7 @@
(profile->mFormats.size() < 2)) ||
((profile->mChannelMasks[0] == 0) &&
(profile->mChannelMasks.size() < 2))) {
- ALOGW("checkOutputsForDevice() direct output missing param");
+ ALOGW("checkOutputsForDevice() missing param");
mpClientInterface->closeOutput(output);
output = 0;
} else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
@@ -2827,6 +2861,12 @@
profile_index--;
} else {
outputs.add(output);
+ if (deviceDistinguishesOnAddress(device)) {
+ ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
+ device, address.string());
+ setOutputDevice(output, device, true/*force*/, 0/*delay*/,
+ NULL/*patch handle*/, address.string());
+ }
ALOGV("checkOutputsForDevice(): adding output %d", output);
}
}
@@ -2839,11 +2879,17 @@
// check if one opened output is not needed any more after disconnecting one device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
- if (!desc->isDuplicated() &&
- !(desc->mProfile->mSupportedDevices.types() &
- mAvailableOutputDevices.types())) {
- ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
- outputs.add(mOutputs.keyAt(i));
+ if (!desc->isDuplicated()) {
+ if (!(desc->mProfile->mSupportedDevices.types()
+ & mAvailableOutputDevices.types())) {
+ ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
+ mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ } else if (deviceDistinguishesOnAddress(device) &&
+ // exact match on device
+ (desc->mProfile->mSupportedDevices.types() == device)) {
+ findIoHandlesByAddress(desc, address, outputs);
+ }
}
}
// Clear any profiles associated with the disconnected device.
@@ -3736,7 +3782,8 @@
audio_devices_t device,
bool force,
int delayMs,
- audio_patch_handle_t *patchHandle)
+ audio_patch_handle_t *patchHandle,
+ const char* address)
{
ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -3782,7 +3829,9 @@
if (device == AUDIO_DEVICE_NONE) {
resetOutputDevice(output, delayMs, NULL);
} else {
- DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ DeviceVector deviceList = (address == NULL) ?
+ mAvailableOutputDevices.getDevicesFromType(device)
+ : mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
if (!deviceList.isEmpty()) {
struct audio_patch patch;
outputDesc->toAudioPortConfig(&patch.sources[0]);
@@ -3949,10 +3998,10 @@
}
sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
- uint32_t samplingRate,
+ uint32_t& samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- audio_input_flags_t flags __unused)
+ audio_input_flags_t flags)
{
// Choose an input profile based on the requested capture parameters: select the first available
// profile supporting all requested parameters.
@@ -3966,8 +4015,9 @@
{
sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
// profile->log();
- if (profile->isCompatibleProfile(device, samplingRate, format,
- channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+ if (profile->isCompatibleProfile(device, samplingRate,
+ &samplingRate /*updatedSamplingRate*/,
+ format, channelMask, (audio_output_flags_t) flags)) {
return profile;
}
}
@@ -4046,6 +4096,10 @@
return false;
}
+bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) {
+ return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0);
+}
+
audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < mInputs.size(); i++) {
@@ -4566,13 +4620,13 @@
}
if (profile != NULL) {
mAudioPort = profile;
+ mFlags = profile->mFlags;
mSamplingRate = profile->pickSamplingRate();
mFormat = profile->pickFormat();
mChannelMask = profile->pickChannelMask();
if (profile->mGains.size() > 0) {
profile->mGains[0]->getDefaultConfig(&mGain);
}
- mFlags = profile->mFlags;
}
}
@@ -5269,7 +5323,7 @@
}
}
-status_t AudioPolicyManager::AudioPort::checkSamplingRate(uint32_t samplingRate) const
+status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
{
for (size_t i = 0; i < mSamplingRates.size(); i ++) {
if (mSamplingRates[i] == samplingRate) {
@@ -5279,9 +5333,68 @@
return BAD_VALUE;
}
-status_t AudioPolicyManager::AudioPort::checkChannelMask(audio_channel_mask_t channelMask) const
+status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t *updatedSamplingRate) const
{
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ // Search for the closest supported sampling rate that is above (preferred)
+ // or below (acceptable) the desired sampling rate, within a permitted ratio.
+ // The sampling rates do not need to be sorted in ascending order.
+ ssize_t maxBelow = -1;
+ ssize_t minAbove = -1;
+ uint32_t candidate;
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ candidate = mSamplingRates[i];
+ if (candidate == samplingRate) {
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = candidate;
+ }
+ return NO_ERROR;
+ }
+ // candidate < desired
+ if (candidate < samplingRate) {
+ if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
+ maxBelow = i;
+ }
+ // candidate > desired
+ } else {
+ if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
+ minAbove = i;
+ }
+ }
+ }
+ // This uses hard-coded knowledge about AudioFlinger resampling ratios.
+ // TODO Move these assumptions out.
+ static const uint32_t kMaxDownSampleRatio = 6; // beyond this aliasing occurs
+ static const uint32_t kMaxUpSampleRatio = 256; // beyond this sample rate inaccuracies occur
+ // due to approximation by an int32_t of the
+ // phase increments
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (minAbove >= 0) {
+ candidate = mSamplingRates[minAbove];
+ if (candidate / kMaxDownSampleRatio <= samplingRate) {
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = candidate;
+ }
+ return NO_ERROR;
+ }
+ }
+ // But if we have to up-sample from a lower sampling rate, that's OK.
+ if (maxBelow >= 0) {
+ candidate = mSamplingRates[maxBelow];
+ if (candidate * kMaxUpSampleRatio >= samplingRate) {
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = candidate;
+ }
+ return NO_ERROR;
+ }
+ }
+ // leave updatedSamplingRate unmodified
+ return BAD_VALUE;
+}
+
+status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
+{
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
if (mChannelMasks[i] == channelMask) {
return NO_ERROR;
}
@@ -5289,6 +5402,30 @@
return BAD_VALUE;
}
+status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
+ const
+{
+ const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+ for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ // FIXME Does not handle multi-channel automatic conversions yet
+ audio_channel_mask_t supported = mChannelMasks[i];
+ if (supported == channelMask) {
+ return NO_ERROR;
+ }
+ if (isRecordThread) {
+ // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
+ // FIXME Abstract this out to a table.
+ if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
+ && channelMask == AUDIO_CHANNEL_IN_MONO) ||
+ (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const
{
for (size_t i = 0; i < mFormats.size(); i ++) {
@@ -5409,7 +5546,7 @@
// limit format otherwise
if ((mType != AUDIO_PORT_TYPE_MIX) ||
((mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) == 0)))) {
+ (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
bestFormat = AUDIO_FORMAT_INVALID;
}
@@ -5623,14 +5760,14 @@
goto exit;
}
if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- status = mAudioPort->checkSamplingRate(config->sample_rate);
+ status = mAudioPort->checkExactSamplingRate(config->sample_rate);
if (status != NO_ERROR) {
goto exit;
}
mSamplingRate = config->sample_rate;
}
if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- status = mAudioPort->checkChannelMask(config->channel_mask);
+ status = mAudioPort->checkExactChannelMask(config->channel_mask);
if (status != NO_ERROR) {
goto exit;
}
@@ -5721,30 +5858,60 @@
// get a valid a match
bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags) const
{
- if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
- return false;
- }
+ 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 ((mSupportedDevices.types() & device) != device) {
+ if ((mSupportedDevices.types() & device) != device) {
+ return false;
+ }
+
+ if (samplingRate == 0) {
return false;
- }
- if ((mFlags & flags) != flags) {
+ }
+ uint32_t myUpdatedSamplingRate = samplingRate;
+ if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
return false;
- }
- if (checkSamplingRate(samplingRate) != NO_ERROR) {
+ }
+ if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
+ NO_ERROR) {
return false;
- }
- if (checkChannelMask(channelMask) != NO_ERROR) {
- return false;
- }
- if (checkFormat(format) != NO_ERROR) {
- return false;
- }
- return true;
+ }
+
+ if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
+ return false;
+ }
+
+ if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
+ checkExactChannelMask(channelMask) != NO_ERROR)) {
+ return false;
+ }
+ if (isRecordThread && (!audio_is_input_channel(channelMask) ||
+ checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
+ return false;
+ }
+
+ if (isPlaybackThread && (mFlags & flags) != flags) {
+ return false;
+ }
+ // The only input flag that is allowed to be different is the fast flag.
+ // An existing fast stream is compatible with a normal track request.
+ // An existing normal stream is compatible with a fast track request,
+ // but the fast request will be denied by AudioFlinger and converted to normal track.
+ if (isRecordThread && (((audio_input_flags_t) mFlags ^ (audio_input_flags_t) flags) &
+ ~AUDIO_INPUT_FLAG_FAST)) {
+ return false;
+ }
+
+ if (updatedSamplingRate != NULL) {
+ *updatedSamplingRate = myUpdatedSamplingRate;
+ }
+ return true;
}
void AudioPolicyManager::IOProfile::dump(int fd)
@@ -5954,6 +6121,24 @@
return devices;
}
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromTypeAddr(
+ audio_devices_t type, String8 address) const
+{
+ DeviceVector devices;
+ //ALOGV(" looking for device=%x, addr=%s", type, address.string());
+ for (size_t i = 0; i < size(); i++) {
+ //ALOGV(" at i=%d: device=%x, addr=%s",
+ // i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string());
+ if (itemAt(i)->mDeviceType == type) {
+ if (itemAt(i)->mAddress == address) {
+ //ALOGV(" found matching address %s", address.string());
+ devices.add(itemAt(i));
+ }
+ }
+ }
+ return devices;
+}
+
sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDeviceFromName(
const String8& name) const
{
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index e9ec78e..62b3ce5 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -240,8 +240,15 @@
void loadGain(cnode *root, int index);
void loadGains(cnode *root);
- status_t checkSamplingRate(uint32_t samplingRate) const;
- status_t checkChannelMask(audio_channel_mask_t channelMask) const;
+ // searches for an exact match
+ status_t checkExactSamplingRate(uint32_t samplingRate) const;
+ // searches for a compatible match, and returns the best match via updatedSamplingRate
+ status_t checkCompatibleSamplingRate(uint32_t samplingRate,
+ uint32_t *updatedSamplingRate) const;
+ // searches for an exact match
+ status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
+ // searches for a compatible match, currently implemented for input channel masks only
+ status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask) const;
status_t checkFormat(audio_format_t format) const;
status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
@@ -339,6 +346,8 @@
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;
private:
void refreshTypes();
@@ -356,8 +365,13 @@
IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
virtual ~IOProfile();
+ // This method is used for both output and input.
+ // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
+ // For input, flags is interpreted as audio_input_flags_t.
+ // TODO: merge audio_output_flags_t and audio_input_flags_t.
bool isCompatibleProfile(audio_devices_t device,
uint32_t samplingRate,
+ uint32_t *updatedSamplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags) const;
@@ -534,7 +548,8 @@
audio_devices_t device,
bool force = false,
int delayMs = 0,
- audio_patch_handle_t *patchHandle = NULL);
+ audio_patch_handle_t *patchHandle = NULL,
+ const char* address = NULL);
status_t resetOutputDevice(audio_io_handle_t output,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
@@ -673,8 +688,9 @@
audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags);
+ // samplingRate parameter is an in/out and so may be modified
sp<IOProfile> getInputProfile(audio_devices_t device,
- uint32_t samplingRate,
+ uint32_t& samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_input_flags_t flags);
@@ -774,6 +790,15 @@
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
static bool isVirtualInputDevice(audio_devices_t device);
+ 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.
+ // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
+ // where addresses are used to distinguish between one connected device and another.
+ void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+ const String8 address /*in*/,
+ SortedVector<audio_io_handle_t>& outputs /*out*/);
uint32_t nextUniqueId();
uint32_t nextAudioPortGeneration();
uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }