From 054d9d3dea1390294650ac704acb4aa0a0731217 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 24 Apr 2015 08:48:48 -0700 Subject: PatchPanel: do not use setParameters() internally. Do not use setParameters() with AUDIO_PARAMETER_STREAM_ROUTING when communicating the input or output device selected to playback or record threads, even for HAL version less than 3.0. Use createAudioPatch()/releaseAudioPatch() instead. This allows to send more information on the output or input device being selected. Also fix a regression introduced in L where the output device selection was not communicated to effects on record threads. Change-Id: I4780ada53241d56694b005c992171e173c3bf8f5 --- services/audioflinger/AudioFlinger.cpp | 12 +- services/audioflinger/AudioFlinger.h | 1 + services/audioflinger/PatchPanel.cpp | 132 ++++++--------------- services/audioflinger/Threads.cpp | 205 +++++++++++++++++++++++++++------ services/audioflinger/Threads.h | 4 + 5 files changed, 219 insertions(+), 135 deletions(-) diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 5002099..0530aae 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1013,6 +1013,14 @@ bool AudioFlinger::streamMute(audio_stream_type_t stream) const return streamMute_l(stream); } + +void AudioFlinger::broacastParametersToRecordThreads_l(const String8& keyValuePairs) +{ + for (size_t i = 0; i < mRecordThreads.size(); i++) { + mRecordThreads.valueAt(i)->setParameters(keyValuePairs); + } +} + status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) { ALOGV("setParameters(): io %d, keyvalue %s, calling pid %d", @@ -1087,9 +1095,7 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& int value; if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) && (value != 0)) { - for (size_t i = 0; i < mRecordThreads.size(); i++) { - mRecordThreads.valueAt(i)->setParameters(keyValuePairs); - } + broacastParametersToRecordThreads_l(keyValuePairs); } } } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index e1ddcbc..9858b02 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -588,6 +588,7 @@ private: // Return true if the effect was found in mOrphanEffectChains, false otherwise. bool updateOrphanEffectChains(const sp& effect); + void broacastParametersToRecordThreads_l(const String8& keyValuePairs); // AudioStreamIn is immutable, so their fields are const. // For emphasis, we could also make all pointers to them be "const *", diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp index 834947f..9248bba 100644 --- a/services/audioflinger/PatchPanel.cpp +++ b/services/audioflinger/PatchPanel.cpp @@ -274,57 +274,29 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa goto exit; } } else { - if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { - sp thread = audioflinger->checkRecordThread_l( - patch->sinks[0].ext.mix.handle); - if (thread == 0) { - ALOGW("createAudioPatch() bad capture I/O handle %d", - patch->sinks[0].ext.mix.handle); - status = BAD_VALUE; - goto exit; - } - status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); - } else { - audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); - status = hwDevice->create_audio_patch(hwDevice, - patch->num_sources, - patch->sources, - patch->num_sinks, - patch->sinks, - &halHandle); - } - } else { - if (patch->sinks[0].type != AUDIO_PORT_TYPE_MIX) { - status = INVALID_OPERATION; - goto exit; - } - + if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { sp thread = audioflinger->checkRecordThread_l( - patch->sinks[0].ext.mix.handle); + patch->sinks[0].ext.mix.handle); if (thread == 0) { ALOGW("createAudioPatch() bad capture I/O handle %d", - patch->sinks[0].ext.mix.handle); + patch->sinks[0].ext.mix.handle); status = BAD_VALUE; goto exit; } - char *address; - if (strcmp(patch->sources[0].ext.device.address, "") != 0) { - address = audio_device_address_to_parameter( - patch->sources[0].ext.device.type, - patch->sources[0].ext.device.address); - } else { - address = (char *)calloc(1, 1); + status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); + } else { + if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) { + status = INVALID_OPERATION; + goto exit; } - AudioParameter param = AudioParameter(String8(address)); - free(address); - param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), - (int)patch->sources[0].ext.device.type); - param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE), - (int)patch->sinks[0].ext.mix.usecase.source); - ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", - param.toString().string()); - status = thread->setParameters(param.toString()); + + audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); + status = hwDevice->create_audio_patch(hwDevice, + patch->num_sources, + patch->sources, + patch->num_sinks, + patch->sinks, + &halHandle); } } } break; @@ -337,6 +309,7 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa goto exit; } // limit to connections between devices and output streams + audio_devices_t type = AUDIO_DEVICE_NONE; for (unsigned int i = 0; i < patch->num_sinks; i++) { if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) { ALOGW("createAudioPatch() invalid sink type %d for mix source", @@ -349,8 +322,8 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa status = BAD_VALUE; goto exit; } + type |= patch->sinks[i].ext.device.type; } - AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); sp thread = audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle); if (thread == 0) { @@ -359,28 +332,14 @@ status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *pa status = BAD_VALUE; goto exit; } - if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); - } else { - audio_devices_t type = AUDIO_DEVICE_NONE; - for (unsigned int i = 0; i < patch->num_sinks; i++) { - type |= patch->sinks[i].ext.device.type; - } - char *address; - if (strcmp(patch->sinks[0].ext.device.address, "") != 0) { - //FIXME: we only support address on first sink with HAL version < 3.0 - address = audio_device_address_to_parameter( - patch->sinks[0].ext.device.type, - patch->sinks[0].ext.device.address); - } else { - address = (char *)calloc(1, 1); - } - AudioParameter param = AudioParameter(String8(address)); - free(address); + if (thread == audioflinger->primaryPlaybackThread_l()) { + AudioParameter param = AudioParameter(); param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type); - status = thread->setParameters(param.toString()); + + audioflinger->broacastParametersToRecordThreads_l(param.toString()); } + status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle); } break; default: status = BAD_VALUE; @@ -581,36 +540,24 @@ status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle break; } - AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); - if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { - sp thread = audioflinger->checkRecordThread_l( - patch->sinks[0].ext.mix.handle); - if (thread == 0) { - ALOGW("releaseAudioPatch() bad capture I/O handle %d", - patch->sinks[0].ext.mix.handle); - status = BAD_VALUE; - break; - } - status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); - } else { - audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); - status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle); - } - } else { + if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) { sp thread = audioflinger->checkRecordThread_l( - patch->sinks[0].ext.mix.handle); + patch->sinks[0].ext.mix.handle); if (thread == 0) { ALOGW("releaseAudioPatch() bad capture I/O handle %d", - patch->sinks[0].ext.mix.handle); + patch->sinks[0].ext.mix.handle); status = BAD_VALUE; break; } - AudioParameter param; - param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); - ALOGV("releaseAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s", - param.toString().string()); - status = thread->setParameters(param.toString()); + status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); + } else { + AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); + if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) { + status = INVALID_OPERATION; + break; + } + audio_hw_device_t *hwDevice = audioHwDevice->hwDevice(); + status = hwDevice->release_audio_patch(hwDevice, removedPatch->mHalHandle); } } break; case AUDIO_PORT_TYPE_MIX: { @@ -629,14 +576,7 @@ status_t AudioFlinger::PatchPanel::releaseAudioPatch(audio_patch_handle_t handle status = BAD_VALUE; break; } - AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index); - if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); - } else { - AudioParameter param; - param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); - status = thread->setParameters(param.toString()); - } + status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle); } break; default: status = BAD_VALUE; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 4039564..234e45f 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2933,21 +2933,78 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) return INVALID_OPERATION; } +status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle) +{ + // if !&IDLE, holds the FastMixer state to restore after new parameters processed + FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE; + if (mFastMixer != 0) { + FastMixerStateQueue *sq = mFastMixer->sq(); + FastMixerState *state = sq->begin(); + if (!(state->mCommand & FastMixerState::IDLE)) { + previousCommand = state->mCommand; + state->mCommand = FastMixerState::HOT_IDLE; + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED); + } else { + sq->end(false /*didModify*/); + } + } + status_t status = PlaybackThread::createAudioPatch_l(patch, handle); + + if (!(previousCommand & FastMixerState::IDLE)) { + ALOG_ASSERT(mFastMixer != 0); + FastMixerStateQueue *sq = mFastMixer->sq(); + FastMixerState *state = sq->begin(); + ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE); + state->mCommand = previousCommand; + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); + } + + return status; +} + status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch, audio_patch_handle_t *handle) { status_t status = NO_ERROR; - if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - // store new device and send to effects - audio_devices_t type = AUDIO_DEVICE_NONE; - for (unsigned int i = 0; i < patch->num_sinks; i++) { - type |= patch->sinks[i].ext.device.type; + + // store new device and send to effects + audio_devices_t type = AUDIO_DEVICE_NONE; + for (unsigned int i = 0; i < patch->num_sinks; i++) { + type |= patch->sinks[i].ext.device.type; + } + +#ifdef ADD_BATTERY_DATA + // when changing the audio output device, call addBatteryData to notify + // the change + if (mOutDevice != type) { + uint32_t params = 0; + // check whether speaker is on + if (type & AUDIO_DEVICE_OUT_SPEAKER) { + params |= IMediaPlayerService::kBatteryDataSpeakerOn; } - mOutDevice = type; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setDevice_l(mOutDevice); + + audio_devices_t deviceWithoutSpeaker + = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER; + // check if any other device (except speaker) is on + if (type & deviceWithoutSpeaker) { + params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn; + } + + if (params != 0) { + addBatteryData(params); } + } +#endif + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(type); + } + mOutDevice = type; + + if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice(); status = hwDevice->create_audio_patch(hwDevice, patch->num_sources, @@ -2956,19 +3013,71 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat patch->sinks, handle); } else { - ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL"); + char *address; + if (strcmp(patch->sinks[0].ext.device.address, "") != 0) { + //FIXME: we only support address on first sink with HAL version < 3.0 + address = audio_device_address_to_parameter( + patch->sinks[0].ext.device.type, + patch->sinks[0].ext.device.address); + } else { + address = (char *)calloc(1, 1); + } + AudioParameter param = AudioParameter(String8(address)); + free(address); + param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type); + status = mOutput->stream->common.set_parameters(&mOutput->stream->common, + param.toString().string()); + *handle = AUDIO_PATCH_HANDLE_NONE; + } + return status; +} + +status_t AudioFlinger::MixerThread::releaseAudioPatch_l(const audio_patch_handle_t handle) +{ + // if !&IDLE, holds the FastMixer state to restore after new parameters processed + FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE; + if (mFastMixer != 0) { + FastMixerStateQueue *sq = mFastMixer->sq(); + FastMixerState *state = sq->begin(); + if (!(state->mCommand & FastMixerState::IDLE)) { + previousCommand = state->mCommand; + state->mCommand = FastMixerState::HOT_IDLE; + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED); + } else { + sq->end(false /*didModify*/); + } } + + status_t status = PlaybackThread::releaseAudioPatch_l(handle); + + if (!(previousCommand & FastMixerState::IDLE)) { + ALOG_ASSERT(mFastMixer != 0); + FastMixerStateQueue *sq = mFastMixer->sq(); + FastMixerState *state = sq->begin(); + ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE); + state->mCommand = previousCommand; + sq->end(); + sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED); + } + return status; } status_t AudioFlinger::PlaybackThread::releaseAudioPatch_l(const audio_patch_handle_t handle) { status_t status = NO_ERROR; + + mOutDevice = AUDIO_DEVICE_NONE; + if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice(); status = hwDevice->release_audio_patch(hwDevice, handle); } else { - ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL"); + AudioParameter param; + param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); + status = mOutput->stream->common.set_parameters(&mOutput->stream->common, + param.toString().string()); } return status; } @@ -4052,7 +4161,7 @@ bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePa audio_devices_t deviceWithoutSpeaker = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER; // check if any other device (except speaker) is on - if (value & deviceWithoutSpeaker ) { + if (value & deviceWithoutSpeaker) { params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn; } @@ -6775,33 +6884,34 @@ status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch audio_patch_handle_t *handle) { status_t status = NO_ERROR; - if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { - // store new device and send to effects - mInDevice = patch->sources[0].ext.device.type; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setDevice_l(mInDevice); - } - - // disable AEC and NS if the device is a BT SCO headset supporting those - // pre processings - if (mTracks.size() > 0) { - bool suspend = audio_is_bluetooth_sco_device(mInDevice) && - mAudioFlinger->btNrecIsOff(); - for (size_t i = 0; i < mTracks.size(); i++) { - sp track = mTracks[i]; - setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); - setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); - } + + // store new device and send to effects + mInDevice = patch->sources[0].ext.device.type; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(mInDevice); + } + + // disable AEC and NS if the device is a BT SCO headset supporting those + // pre processings + if (mTracks.size() > 0) { + bool suspend = audio_is_bluetooth_sco_device(mInDevice) && + mAudioFlinger->btNrecIsOff(); + for (size_t i = 0; i < mTracks.size(); i++) { + sp track = mTracks[i]; + setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); } + } - // store new source and send to effects - if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) { - mAudioSource = patch->sinks[0].ext.mix.usecase.source; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setAudioSource_l(mAudioSource); - } + // store new source and send to effects + if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) { + mAudioSource = patch->sinks[0].ext.mix.usecase.source; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setAudioSource_l(mAudioSource); } + } + if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice(); status = hwDevice->create_audio_patch(hwDevice, patch->num_sources, @@ -6810,19 +6920,42 @@ status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch patch->sinks, handle); } else { - ALOG_ASSERT(false, "createAudioPatch_l() called on a pre 3.0 HAL"); + char *address; + if (strcmp(patch->sources[0].ext.device.address, "") != 0) { + address = audio_device_address_to_parameter( + patch->sources[0].ext.device.type, + patch->sources[0].ext.device.address); + } else { + address = (char *)calloc(1, 1); + } + AudioParameter param = AudioParameter(String8(address)); + free(address); + param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), + (int)patch->sources[0].ext.device.type); + param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE), + (int)patch->sinks[0].ext.mix.usecase.source); + status = mInput->stream->common.set_parameters(&mInput->stream->common, + param.toString().string()); + *handle = AUDIO_PATCH_HANDLE_NONE; } + return status; } status_t AudioFlinger::RecordThread::releaseAudioPatch_l(const audio_patch_handle_t handle) { status_t status = NO_ERROR; + + mInDevice = AUDIO_DEVICE_NONE; + if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_hw_device_t *hwDevice = mInput->audioHwDev->hwDevice(); status = hwDevice->release_audio_patch(hwDevice, handle); } else { - ALOG_ASSERT(false, "releaseAudioPatch_l() called on a pre 3.0 HAL"); + AudioParameter param; + param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), 0); + status = mInput->stream->common.set_parameters(&mInput->stream->common, + param.toString().string()); } return status; } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index b7c1ed1..2c514f8 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -865,6 +865,10 @@ protected: virtual void threadLoop_removeTracks(const Vector< sp >& tracksToRemove); virtual uint32_t correctLatency_l(uint32_t latency) const; + virtual status_t createAudioPatch_l(const struct audio_patch *patch, + audio_patch_handle_t *handle); + virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle); + AudioMixer* mAudioMixer; // normal mixer private: // one-time initialization, no locks required -- cgit v1.1