diff options
-rw-r--r-- | include/media/IOMX.h | 2 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 22 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 38 | ||||
-rw-r--r-- | media/libstagefright/omx/OMX.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 4 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 460 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 9 |
8 files changed, 371 insertions, 170 deletions
diff --git a/include/media/IOMX.h b/include/media/IOMX.h index f6f9e7a..176f72d 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -184,8 +184,6 @@ struct omx_message { OMX_U32 range_length; OMX_U32 flags; OMX_TICKS timestamp; - OMX_PTR platform_private; - OMX_PTR data_ptr; } extended_buffer_data; } u; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a7bf380..2c8605c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -79,14 +79,14 @@ AudioRecord::AudioRecord( uint32_t notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags __unused) + audio_input_flags_t flags) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) { mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, - notificationFrames, false /*threadCanCallJava*/, sessionId, transferType); + notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags); } AudioRecord::~AudioRecord() diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5bca317..537d9de 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -100,12 +100,6 @@ struct CodecObserver : public BnOMXObserver { msg->setInt64( "timestamp", omx_msg.u.extended_buffer_data.timestamp); - msg->setPointer( - "platform_private", - omx_msg.u.extended_buffer_data.platform_private); - msg->setPointer( - "data_ptr", - omx_msg.u.extended_buffer_data.data_ptr); break; } @@ -160,9 +154,7 @@ private: IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void *platformPrivate, - void *dataPtr); + int64_t timeUs); void getMoreInputDataIfPossible(); @@ -3228,23 +3220,17 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) { int32_t rangeOffset, rangeLength, flags; int64_t timeUs; - void *platformPrivate; - void *dataPtr; CHECK(msg->findInt32("range_offset", &rangeOffset)); CHECK(msg->findInt32("range_length", &rangeLength)); CHECK(msg->findInt32("flags", &flags)); CHECK(msg->findInt64("timestamp", &timeUs)); - CHECK(msg->findPointer("platform_private", &platformPrivate)); - CHECK(msg->findPointer("data_ptr", &dataPtr)); return onOMXFillBufferDone( bufferID, (size_t)rangeOffset, (size_t)rangeLength, (OMX_U32)flags, - timeUs, - platformPrivate, - dataPtr); + timeUs); } default: @@ -3543,9 +3529,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void * /* platformPrivate */, - void * /* dataPtr */) { + int64_t timeUs) { ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", mCodec->mComponentName.c_str(), bufferID, timeUs, flags); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index a879656..9a7f3db 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1627,15 +1627,15 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { info.mMediaBuffer = NULL; if (portIndex == kPortIndexOutput) { - if (!(mOMXLivesLocally - && (mQuirks & kRequiresAllocateBufferOnOutputPorts) - && (mQuirks & kDefersOutputBufferAllocation))) { - // If the node does not fill in the buffer ptr at this time, - // we will defer creating the MediaBuffer until receiving - // the first FILL_BUFFER_DONE notification instead. - info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); - info.mMediaBuffer->setObserver(this); - } + // Fail deferred MediaBuffer creation until FILL_BUFFER_DONE; + // this legacy mode is no longer supported. + LOG_ALWAYS_FATAL_IF((mOMXLivesLocally + && (mQuirks & kRequiresAllocateBufferOnOutputPorts) + && (mQuirks & kDefersOutputBufferAllocation)), + "allocateBuffersOnPort cannot defer buffer allocation"); + + info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); + info.mMediaBuffer->setObserver(this); } mPortBuffers[portIndex].push(info); @@ -2234,22 +2234,6 @@ void OMXCodec::on_message(const omx_message &msg) { } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) { CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED); - if (info->mMediaBuffer == NULL) { - CHECK(mOMXLivesLocally); - CHECK(mQuirks & kRequiresAllocateBufferOnOutputPorts); - CHECK(mQuirks & kDefersOutputBufferAllocation); - - // The qcom video decoders on Nexus don't actually allocate - // output buffer memory on a call to OMX_AllocateBuffer - // the "pBuffer" member of the OMX_BUFFERHEADERTYPE - // structure is only filled in later. - - info->mMediaBuffer = new MediaBuffer( - msg.u.extended_buffer_data.data_ptr, - info->mSize); - info->mMediaBuffer->setObserver(this); - } - MediaBuffer *buffer = info->mMediaBuffer; bool isGraphicBuffer = buffer->graphicBuffer() != NULL; @@ -2285,10 +2269,6 @@ void OMXCodec::on_message(const omx_message &msg) { } buffer->meta_data()->setPointer( - kKeyPlatformPrivate, - msg.u.extended_buffer_data.platform_private); - - buffer->meta_data()->setPointer( kKeyBufferID, msg.u.extended_buffer_data.buffer); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 74076c6..b62d5f5 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -470,8 +470,6 @@ OMX_ERRORTYPE OMX::OnFillBufferDone( msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; msg.u.extended_buffer_data.flags = pBuffer->nFlags; msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; - msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; - msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; findDispatcher(node)->post(msg); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index be37436..a916b32 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5102,8 +5102,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe // PCM data audio_is_linear_pcm(format) && // mono or stereo - ( (channelMask == AUDIO_CHANNEL_OUT_MONO) || - (channelMask == AUDIO_CHANNEL_OUT_STEREO) ) && + ( (channelMask == AUDIO_CHANNEL_IN_MONO) || + (channelMask == AUDIO_CHANNEL_IN_STEREO) ) && // hardware sample rate // FIXME actually the native hardware sample rate (sampleRate == mSampleRate) && diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 45f98d2..fc9b81a 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -31,14 +31,16 @@ // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX +#include <inttypes.h> +#include <math.h> + +#include <cutils/properties.h> #include <utils/Log.h> -#include "AudioPolicyManager.h" -#include <hardware/audio_effect.h> #include <hardware/audio.h> -#include <math.h> +#include <hardware/audio_effect.h> #include <hardware_legacy/audio_policy_conf.h> -#include <cutils/properties.h> #include <media/AudioParameter.h> +#include "AudioPolicyManager.h" namespace android { @@ -85,6 +87,7 @@ const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY), + STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE), }; const StringToEnum sFlagNameToEnumTable[] = { @@ -162,7 +165,6 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) { - SortedVector <audio_io_handle_t> outputs; String8 address = String8(device_address); ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); @@ -172,6 +174,8 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, // handle output devices if (audio_is_output_device(device)) { + SortedVector <audio_io_handle_t> outputs; + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, address, 0); @@ -193,7 +197,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) { return INVALID_OPERATION; } - ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", + ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs", outputs.size()); // register new device as available index = mAvailableOutputDevices.add(devDesc); @@ -265,9 +269,12 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, } else { return NO_ERROR; } - } + } // end if is output device + // handle input devices if (audio_is_input_device(device)) { + SortedVector <audio_io_handle_t> inputs; + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, address, 0); @@ -281,14 +288,17 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } + if (checkInputsForDevice(device, state, inputs, address) != NO_ERROR) { + return INVALID_OPERATION; + } + index = mAvailableInputDevices.add(devDesc); if (index >= 0) { mAvailableInputDevices[index]->mId = nextUniqueId(); } else { return NO_MEMORY; } - } - break; + } break; // handle input device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { @@ -296,30 +306,19 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } + checkInputsForDevice(device, state, inputs, address); mAvailableInputDevices.remove(devDesc); - } break; + } break; default: ALOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } - audio_io_handle_t activeInput = getActiveInput(); - if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); - } - } + closeAllInputs(); return NO_ERROR; - } + } // end if is input device ALOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; @@ -1050,7 +1049,7 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, delete inputDesc; return 0; } - mInputs.add(input, inputDesc); + addInput(input, inputDesc); return input; } @@ -1152,6 +1151,13 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input) ALOGV("releaseInput() exit"); } +void AudioPolicyManager::closeAllInputs() { + for(size_t input_index = 0; input_index < mInputs.size(); input_index++) { + mpClientInterface->closeInput(mInputs.keyAt(input_index)); + } + mInputs.clear(); +} + void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) @@ -1247,7 +1253,7 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( for (size_t i = 0; i < outputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); - ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags); + ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags); if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { outputOffloaded = outputs[i]; } @@ -1484,7 +1490,7 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, "\nHW Modules dump:\n"); write(fd, buffer, strlen(buffer)); for (size_t i = 0; i < mHwModules.size(); i++) { - snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1); + snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1); write(fd, buffer, strlen(buffer)); mHwModules[i]->dump(fd); } @@ -1511,7 +1517,7 @@ status_t AudioPolicyManager::dump(int fd) " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n"); write(fd, buffer, strlen(buffer)); for (int i = 0; i < AUDIO_STREAM_CNT; i++) { - snprintf(buffer, SIZE, " %02d ", i); + snprintf(buffer, SIZE, " %02zu ", i); write(fd, buffer, strlen(buffer)); mStreams[i].dump(fd); } @@ -1538,7 +1544,7 @@ status_t AudioPolicyManager::dump(int fd) bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo) { ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," - " BitRate=%u, duration=%lld us, has_video=%d", + " BitRate=%u, duration=%" PRId64 " us, has_video=%d", offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format, offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, @@ -1680,10 +1686,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mHwModules[i]->mName); delete outputDesc; } else { - for (size_t i = 0; i < outProfile->mSupportedDevices.size(); i++) { - audio_devices_t type = outProfile->mSupportedDevices[i]->mType; + for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) { + audio_devices_t type = outProfile->mSupportedDevices[k]->mType; ssize_t index = - mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[i]); + mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) { mAvailableOutputDevices[index]->mId = nextUniqueId(); @@ -1725,10 +1731,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &inputDesc->mChannelMask); if (input != 0) { - for (size_t i = 0; i < inProfile->mSupportedDevices.size(); i++) { - audio_devices_t type = inProfile->mSupportedDevices[i]->mType; + for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) { + audio_devices_t type = inProfile->mSupportedDevices[k]->mType; ssize_t index = - mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[i]); + mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) { mAvailableInputDevices[index]->mId = nextUniqueId(); @@ -1978,6 +1984,11 @@ void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor * mOutputs.add(id, outputDesc); } +void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc) +{ + inputDesc->mId = id; + mInputs.add(id, inputDesc); +} String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address) { @@ -2013,7 +2024,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) { - ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i); + ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); profiles.add(mHwModules[i]->mOutputProfiles[j]); } } @@ -2058,84 +2069,99 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, desc->mFlags, &offloadInfo); if (output != 0) { + // Here is where the out_set_parameters() for card & device gets called if (!address.isEmpty()) { mpClientInterface->setParameters(output, addressToParameter(device, address)); } - if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { - String8 reply; - char *value; - if (profile->mSamplingRates[0] == 0) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); - ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadSamplingRates(value + 1, profile); - } + // Here is where we step through and resolve any "dynamic" fields + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value + 1, profile); } - if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); - ALOGV("checkOutputsForDevice() direct output sup formats %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadFormats(value + 1, profile); - } - } - if (profile->mChannelMasks[0] == 0) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); - ALOGV("checkOutputsForDevice() direct output sup channel masks %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadOutChannels(value + 1, profile); - } + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkOutputsForDevice() direct output sup formats %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value + 1, profile); } - if (((profile->mSamplingRates[0] == 0) && - (profile->mSamplingRates.size() < 2)) || - ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && - (profile->mFormats.size() < 2)) || - ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && - (profile->mChannelMasks.size() < 2))) { - ALOGW("checkOutputsForDevice() direct output missing param"); - mpClientInterface->closeOutput(output); - output = 0; - } else { - addOutput(output, desc); + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkOutputsForDevice() direct output sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadOutChannels(value + 1, profile); } - } else { - audio_io_handle_t duplicatedOutput = 0; - // add output descriptor + } + if (((profile->mSamplingRates[0] == 0) && + (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && + (profile->mFormats.size() < 2)) || + ((profile->mChannelMasks[0] == 0) && + (profile->mChannelMasks.size() < 2))) { + ALOGW("checkOutputsForDevice() direct output missing param"); + mpClientInterface->closeOutput(output); + output = 0; + } else if (profile->mSamplingRates[0] == 0) { + mpClientInterface->closeOutput(output); + desc->mSamplingRate = profile->mSamplingRates[1]; + offloadInfo.sample_rate = desc->mSamplingRate; + output = mpClientInterface->openOutput( + profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask, + &desc->mLatency, + desc->mFlags, + &offloadInfo); + } + + if (output != 0) { addOutput(output, desc); - // set initial stream volume for device - applyStreamVolumes(output, device, 0, true); - - //TODO: configure audio effect output stage here - - // open a duplicating output thread for the new output and the primary output - duplicatedOutput = mpClientInterface->openDuplicateOutput(output, - mPrimaryOutput); - if (duplicatedOutput != 0) { - // add duplicated output descriptor - AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); - dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); - dupOutputDesc->mOutput2 = mOutputs.valueFor(output); - dupOutputDesc->mSamplingRate = desc->mSamplingRate; - dupOutputDesc->mFormat = desc->mFormat; - dupOutputDesc->mChannelMask = desc->mChannelMask; - dupOutputDesc->mLatency = desc->mLatency; - addOutput(duplicatedOutput, dupOutputDesc); - applyStreamVolumes(duplicatedOutput, device, 0, true); - } else { - ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", - mPrimaryOutput, output); - mpClientInterface->closeOutput(output); - mOutputs.removeItem(output); - output = 0; + if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + audio_io_handle_t duplicatedOutput = 0; + + // set initial stream volume for device + applyStreamVolumes(output, device, 0, true); + + //TODO: configure audio effect output stage here + + // open a duplicating output thread for the new output and the primary output + duplicatedOutput = mpClientInterface->openDuplicateOutput(output, + mPrimaryOutput); + if (duplicatedOutput != 0) { + // add duplicated output descriptor + AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); + dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); + dupOutputDesc->mOutput2 = mOutputs.valueFor(output); + dupOutputDesc->mSamplingRate = desc->mSamplingRate; + dupOutputDesc->mFormat = desc->mFormat; + dupOutputDesc->mChannelMask = desc->mChannelMask; + dupOutputDesc->mLatency = desc->mLatency; + addOutput(duplicatedOutput, dupOutputDesc); + applyStreamVolumes(duplicatedOutput, device, 0, true); + } else { + ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", + mPrimaryOutput, output); + mpClientInterface->closeOutput(output); + mOutputs.removeItem(output); + output = 0; + } } } } @@ -2154,7 +2180,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, ALOGW("checkOutputsForDevice(): No output available for device %04x", device); return BAD_VALUE; } - } else { + } else { // Disconnect // 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); @@ -2165,6 +2191,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, outputs.add(mOutputs.keyAt(i)); } } + // Clear any profiles associated with the disconnected device. for (size_t i = 0; i < mHwModules.size(); i++) { if (mHwModules[i]->mHandle == 0) { @@ -2173,10 +2200,9 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; - if ((profile->mSupportedDevices.types() & device) && - (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { - ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d", - j, i); + if (profile->mSupportedDevices.types() & device) { + ALOGV("checkOutputsForDevice(): " + "clearing direct output profile %zu on module %zu", j, i); if (profile->mSamplingRates[0] == 0) { profile->mSamplingRates.clear(); profile->mSamplingRates.add(0); @@ -2196,6 +2222,183 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, return NO_ERROR; } +status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, + audio_policy_dev_state_t state, + SortedVector<audio_io_handle_t>& inputs, + const String8 address) +{ + AudioInputDescriptor *desc; + if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { + // first list already open inputs that can be routed to this device + for (size_t input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (desc->mProfile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) { + ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index)); + inputs.add(mInputs.keyAt(input_index)); + } + } + + // then look for input profiles that can be routed to this device + SortedVector<IOProfile *> profiles; + for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++) + { + if (mHwModules[module_idx]->mHandle == 0) { + continue; + } + for (size_t profile_index = 0; + profile_index < mHwModules[module_idx]->mInputProfiles.size(); + profile_index++) + { + if (mHwModules[module_idx]->mInputProfiles[profile_index]->mSupportedDevices.types() + & (device & ~AUDIO_DEVICE_BIT_IN)) { + ALOGV("checkInputsForDevice(): adding profile %d from module %d", + profile_index, module_idx); + profiles.add(mHwModules[module_idx]->mInputProfiles[profile_index]); + } + } + } + + if (profiles.isEmpty() && inputs.isEmpty()) { + ALOGW("checkInputsForDevice(): No input available for device 0x%X", device); + return BAD_VALUE; + } + + // open inputs for matching profiles if needed. Direct inputs are also opened to + // query for dynamic parameters and will be closed later by setDeviceConnectionState() + for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { + + IOProfile *profile = profiles[profile_index]; + // nothing to do if one input is already opened for this profile + size_t input_index; + for (input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (desc->mProfile == profile) { + break; + } + } + if (input_index != mInputs.size()) { + continue; + } + + ALOGV("opening input for device 0x%X with params %s", device, address.string()); + desc = new AudioInputDescriptor(profile); + desc->mDevice = device; + + audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask); + + if (input != 0) { + if (!address.isEmpty()) { + mpClientInterface->setParameters(input, addressToParameter(device, address)); + } + + // Here is where we step through and resolve any "dynamic" fields + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkInputsForDevice() direct input sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value + 1, profile); + } + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value + 1, profile); + } + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkInputsForDevice() direct input sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadInChannels(value + 1, profile); + } + } + if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) || + ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) { + ALOGW("checkInputsForDevice() direct input missing param"); + mpClientInterface->closeInput(input); + input = 0; + } + + if (input != 0) { + addInput(input, desc); + } + } // endif input != 0 + + if (input == 0) { + ALOGW("checkInputsForDevice() could not open input for device 0x%X", device); + delete desc; + profiles.removeAt(profile_index); + profile_index--; + } else { + inputs.add(input); + ALOGV("checkInputsForDevice(): adding input %d", input); + } + } // end scan profiles + + if (profiles.isEmpty()) { + ALOGW("checkInputsForDevice(): No input available for device 0x%X", device); + return BAD_VALUE; + } + } else { + // Disconnect + // check if one opened input is not needed any more after disconnecting one device + for (size_t input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types())) { + ALOGV("checkInputsForDevice(): disconnecting adding input %d", + mInputs.keyAt(input_index)); + inputs.add(mInputs.keyAt(input_index)); + } + } + // Clear any profiles associated with the disconnected device. + for (size_t module_index = 0; module_index < mHwModules.size(); module_index++) { + if (mHwModules[module_index]->mHandle == 0) { + continue; + } + for (size_t profile_index = 0; + profile_index < mHwModules[module_index]->mInputProfiles.size(); + profile_index++) { + IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index]; + if (profile->mSupportedDevices.types() & device) { + ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d", + profile_index, module_index); + if (profile->mSamplingRates[0] == 0) { + profile->mSamplingRates.clear(); + profile->mSamplingRates.add(0); + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + profile->mFormats.clear(); + profile->mFormats.add(AUDIO_FORMAT_DEFAULT); + } + if (profile->mChannelMasks[0] == 0) { + profile->mChannelMasks.clear(); + profile->mChannelMasks.add(0); + } + } + } + } + } // end disconnect + + return NO_ERROR; +} + + void AudioPolicyManager::closeOutput(audio_io_handle_t output) { ALOGV("closeOutput(%d)", output); @@ -2846,6 +3049,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { IOProfile *profile = mHwModules[i]->mInputProfiles[j]; + // profile->log(); if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_NONE)) { return profile; @@ -2878,6 +3082,8 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { + device = AUDIO_DEVICE_IN_USB_DEVICE; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; } @@ -3579,7 +3785,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) // --- AudioInputDescriptor class implementation AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile) - : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), + : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), mDevice(AUDIO_DEVICE_NONE), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile) { @@ -3706,7 +3912,7 @@ void AudioPolicyManager::HwModule::dump(int fd) if (mOutputProfiles.size()) { write(fd, " - outputs:\n", strlen(" - outputs:\n")); for (size_t i = 0; i < mOutputProfiles.size(); i++) { - snprintf(buffer, SIZE, " output %d:\n", i); + snprintf(buffer, SIZE, " output %zu:\n", i); write(fd, buffer, strlen(buffer)); mOutputProfiles[i]->dump(fd); } @@ -3714,7 +3920,7 @@ void AudioPolicyManager::HwModule::dump(int fd) if (mInputProfiles.size()) { write(fd, " - inputs:\n", strlen(" - inputs:\n")); for (size_t i = 0; i < mInputProfiles.size(); i++) { - snprintf(buffer, SIZE, " input %d:\n", i); + snprintf(buffer, SIZE, " input %zu:\n", i); write(fd, buffer, strlen(buffer)); mInputProfiles[i]->dump(fd); } @@ -3824,6 +4030,32 @@ void AudioPolicyManager::IOProfile::dump(int fd) write(fd, result.string(), result.size()); } +void AudioPolicyManager::IOProfile::log() +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + ALOGV(" - sampling rates: "); + for (size_t i = 0; i < mSamplingRates.size(); i++) { + ALOGV(" %d", mSamplingRates[i]); + } + + ALOGV(" - channel masks: "); + for (size_t i = 0; i < mChannelMasks.size(); i++) { + ALOGV(" 0x%04x", mChannelMasks[i]); + } + + ALOGV(" - formats: "); + for (size_t i = 0; i < mFormats.size(); i++) { + ALOGV(" 0x%08x", mFormats[i]); + } + + ALOGV(" - devices: 0x%04x\n", mSupportedDevices.types()); + ALOGV(" - flags: 0x%04x\n", mFlags); +} + + // --- DeviceDescriptor implementation bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 8a631ba..f00fa8a 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -103,6 +103,7 @@ public: // indicates to the audio policy manager that the input stops being used. virtual status_t stopInput(audio_io_handle_t input); virtual void releaseInput(audio_io_handle_t input); + virtual void closeAllInputs(); virtual void initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax); @@ -246,6 +247,7 @@ protected: audio_output_flags_t flags) const; void dump(int fd); + void log(); // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats // indicates the supported parameters should be read from the output stream @@ -329,6 +331,7 @@ protected: status_t dump(int fd); + audio_io_handle_t mId; // input handle uint32_t mSamplingRate; // audio_format_t mFormat; // input configuration audio_channel_mask_t mChannelMask; // @@ -370,6 +373,7 @@ protected: }; void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc); + void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc); // return the strategy corresponding to a given stream type static routing_strategy getStrategy(audio_stream_type_t stream); @@ -453,6 +457,11 @@ protected: SortedVector<audio_io_handle_t>& outputs, const String8 address); + status_t checkInputsForDevice(audio_devices_t device, + audio_policy_dev_state_t state, + SortedVector<audio_io_handle_t>& inputs, + const String8 address); + // close an output and its companion duplicating output. void closeOutput(audio_io_handle_t output); |