diff options
-rw-r--r-- | audio/AudioPolicyManagerBase.cpp | 95 | ||||
-rw-r--r-- | include/hardware_legacy/AudioPolicyInterface.h | 1 | ||||
-rw-r--r-- | include/hardware_legacy/AudioPolicyManagerBase.h | 7 |
3 files changed, 81 insertions, 22 deletions
diff --git a/audio/AudioPolicyManagerBase.cpp b/audio/AudioPolicyManagerBase.cpp index 0e6a1cb..bd6d0eb 100644 --- a/audio/AudioPolicyManagerBase.cpp +++ b/audio/AudioPolicyManagerBase.cpp @@ -545,8 +545,9 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device); // TODO: current implementation assumes that at most one output corresponds to a device. // this will change when supporting low power, low latency or tunneled output streams - ALOG_ASSERT(outputs.size() < 2, "getOutput(): getOutputsForDevice() " - "returned %d outputs for device %04x", outputs.size(), device); + // FIXME broken with A2DP + no wired headset + //ALOG_ASSERT(outputs.size() < 2, "getOutput(): getOutputsForDevice() " + // "returned %d outputs for device %04x", outputs.size(), device); output = outputs[0]; @@ -568,7 +569,6 @@ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, } AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); // incremenent usage count for this stream on the requested output: // NOTE that the usage count is the same for duplicated output and hardware output which is @@ -597,6 +597,9 @@ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, usleep(outputDesc->mLatency*4*1000); } + // update the outputs if starting an output with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); + return NO_ERROR; } @@ -612,7 +615,6 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, } AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index); - routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream); // handle special case for sonification while in call if (isInCall()) { @@ -630,6 +632,10 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, if (output != mPrimaryOutput) { setOutputDevice(mPrimaryOutput, getNewDevice(mPrimaryOutput), true); } + + // update the outputs if stopping one with a stream that can affect notification routing + handleNotificationRoutingForStream(stream); + return NO_ERROR; } else { ALOGW("stopOutput() refcount is already 0 for output %d", output); @@ -665,6 +671,7 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) delete mOutputs.valueAt(index); mOutputs.removeItem(output); } + } audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, @@ -1489,6 +1496,8 @@ SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audi ALOGV("getOutputsForDevice() device %04x", device); for (size_t i = 0; i < mOutputs.size(); i++) { + ALOGV("output %d isDuplicated=%d device=%04x", + i, mOutputs.valueAt(i)->isDuplicated(), mOutputs.valueAt(i)->supportedDevices()); if ((device & mOutputs.valueAt(i)->supportedDevices()) == device) { ALOGV("getOutputsForDevice() found output %d", mOutputs.keyAt(i)); outputs.add(mOutputs.keyAt(i)); @@ -1519,13 +1528,15 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy) getOutputsForDevice(getDeviceForStrategy(strategy, false)); // TODO: current implementation assumes that at most one output corresponds to a device. - // this will change when supporting low power, low latency or tunneled output streams - ALOG_ASSERT(srcOutputs.size() < 2, "checkOutputForStrategy(): " - "more than one (%d) source output for strategy %d", srcOutputs.size(), strategy); - ALOG_ASSERT(dstOutputs.size() < 2, "checkOutputForStrategy(): " - "more than one (%d) destination output for strategy %d", dstOutputs.size(), strategy); + // this will change when supporting low power, low latency or tunneled output streams. + // FIXME broken with A2DP + no wired headset. + //ALOG_ASSERT(srcOutputs.size() < 2, "checkOutputForStrategy(): " + // "more than one (%d) source output for strategy %d", srcOutputs.size(), strategy); + //ALOG_ASSERT(dstOutputs.size() < 2, "checkOutputForStrategy(): " + // "more than one (%d) destination output for strategy %d", dstOutputs.size(), strategy); if (!vectorsEqual(srcOutputs,dstOutputs)) { + // FIXME dstOutputs[0] happens to be the output to use, what guarantees it is always true? ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d", strategy, srcOutputs[0], dstOutputs[0]); // mute media strategy while moving tracks from one output to another @@ -1544,9 +1555,10 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy) desc->mIo = dstOutputs[0]; } } - // Move tracks associated to this strategy from previous output to new output + // Invalidate the output of the streams associated with this strategy for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { + //FIXME see fixme on name change mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutputs[0]); } } @@ -1558,6 +1570,7 @@ void AudioPolicyManagerBase::checkOutputForAllStrategies() checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE); checkOutputForStrategy(STRATEGY_PHONE); checkOutputForStrategy(STRATEGY_SONIFICATION); + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); checkOutputForStrategy(STRATEGY_MEDIA); checkOutputForStrategy(STRATEGY_DTMF); } @@ -1635,9 +1648,11 @@ audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, b // use device for strategy phone // 3: the strategy sonification is active on the output: // use device for strategy sonification - // 4: the strategy media is active on the output: + // 4: the strategy "respectful" sonification is active on the output: + // use device for strategy "respectful" sonification + // 5: the strategy media is active on the output: // use device for strategy media - // 5: the strategy DTMF is active on the output: + // 6: the strategy DTMF is active on the output: // use device for strategy DTMF if (outputDesc->isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) { device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache); @@ -1646,6 +1661,9 @@ audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, b device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); + } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION_RESPECTFUL)) { + // can't use the cache for this strategy as the device depends on what's currently playing + device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, false); } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { @@ -1682,9 +1700,10 @@ AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( case AudioSystem::BLUETOOTH_SCO: return STRATEGY_PHONE; case AudioSystem::RING: - case AudioSystem::NOTIFICATION: case AudioSystem::ALARM: return STRATEGY_SONIFICATION; + case AudioSystem::NOTIFICATION: + return STRATEGY_SONIFICATION_RESPECTFUL; case AudioSystem::DTMF: return STRATEGY_DTMF; default: @@ -1700,6 +1719,17 @@ AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( } } +void AudioPolicyManagerBase::handleNotificationRoutingForStream(AudioSystem::stream_type stream) { + switch(stream) { + case AudioSystem::MUSIC: + checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL); + updateDeviceForStrategy(); + break; + default: + break; + } +} + audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache) { uint32_t device = 0; @@ -1710,6 +1740,20 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy st } switch (strategy) { + + case STRATEGY_SONIFICATION_RESPECTFUL: + if (isInCall()) { + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false); + } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { + // while media is playing (or has recently played), use the same device + device = getDeviceForStrategy(STRATEGY_MEDIA, false); + } else { + // when media is not playing anymore, fall back on the sonification behavior + device = getDeviceForStrategy(STRATEGY_SONIFICATION, false); + } + + break; + case STRATEGY_DTMF: if (!isInCall()) { // when off call, DTMF strategy follows the same rules as MEDIA strategy @@ -2087,6 +2131,11 @@ const AudioPolicyManagerBase::VolumeCurvePoint sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE }, + { // STRATEGY_SONIFICATION_RESPECTFUL uses same volumes as SONIFICATION + sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET + sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER + sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + }, { // STRATEGY_DTMF sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET sDefaultVolumeCurve, // DEVICE_CATEGORY_SPEAKER @@ -2137,13 +2186,14 @@ float AudioPolicyManagerBase::computeVolume(int stream, // - always attenuate ring tones and notifications volume by 6dB // - if music is playing, always limit the volume to current music volume, // with a minimum threshold at -36dB so that notification is always perceived. - if ((device & - (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | - AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AudioSystem::DEVICE_OUT_WIRED_HEADSET | - AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && - ((getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) || - (stream == AudioSystem::SYSTEM)) && + const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream); + if ((device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP | + AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + AudioSystem::DEVICE_OUT_WIRED_HEADSET | + AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) && + ((stream_strategy == STRATEGY_SONIFICATION) + || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL) + || (stream == AudioSystem::SYSTEM)) && streamDesc.mCanBeMuted) { volume *= SONIFICATION_HEADSET_VOLUME_FACTOR; // when the phone is ringing we must consider that music could have been paused just before @@ -2297,8 +2347,9 @@ void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, // interfere with the device used for phone strategy // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as // many times as there are active tracks on the output - - if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) { + const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream); + if ((stream_strategy == STRATEGY_SONIFICATION) || + ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) { AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput); ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d", stream, starting, outputDesc->mDevice, stateChange); diff --git a/include/hardware_legacy/AudioPolicyInterface.h b/include/hardware_legacy/AudioPolicyInterface.h index d703485..0344c3b 100644 --- a/include/hardware_legacy/AudioPolicyInterface.h +++ b/include/hardware_legacy/AudioPolicyInterface.h @@ -214,6 +214,7 @@ public: // for each output (destination device) it is attached to. virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0) = 0; + // FIXME ignores output, should be renamed to invalidateStreamOuput(stream) // reroute a given stream type to the specified output virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output) = 0; diff --git a/include/hardware_legacy/AudioPolicyManagerBase.h b/include/hardware_legacy/AudioPolicyManagerBase.h index 1459e7e..d24e2a0 100644 --- a/include/hardware_legacy/AudioPolicyManagerBase.h +++ b/include/hardware_legacy/AudioPolicyManagerBase.h @@ -39,6 +39,9 @@ namespace android_audio_legacy { // Time in milliseconds during which we consider that music is still active after a music // track was stopped - see computeVolume() #define SONIFICATION_HEADSET_MUSIC_DELAY 5000 +// Time in milliseconds after media stopped playing during which we consider that the +// sonification should be as unobtrusive as during the time media was playing. +#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000 // Time in milliseconds during witch some streams are muted while the audio path // is switched #define MUTE_TIME_MS 2000 @@ -151,6 +154,7 @@ protected: STRATEGY_MEDIA, STRATEGY_PHONE, STRATEGY_SONIFICATION, + STRATEGY_SONIFICATION_RESPECTFUL, STRATEGY_DTMF, STRATEGY_ENFORCED_AUDIBLE, NUM_STRATEGIES @@ -445,6 +449,9 @@ protected: private: static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc, int indexInUi); + // updates device caching and output for streams that can influence the + // routing of notifications + void handleNotificationRoutingForStream(AudioSystem::stream_type stream); }; }; |