// A device mask for all audio input devices that are considered "virtual" when evaluating
// active inputs in getActiveInput()
#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// 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
#include <utils/Log.h>
#include <hardware_legacy/AudioPolicyManagerBase.h>
newDevice = hwOutputDesc->device();
}
- // when changing from ring tone to in call mode, mute the ringing tone
- // immediately and delay the route change to avoid sending the ring tone
- // tail into the earpiece or headset.
int delayMs = 0;
- if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) {
- // delay the device change command by twice the output latency to have some margin
- // and be sure that audio buffers not yet affected by the mute are out when
- // we actually apply the route change
- delayMs = hwOutputDesc->mLatency*2;
- setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
- }
-
if (isStateInCall(state)) {
+ nsecs_t sysTime = systemTime();
for (size_t i = 0; i < mOutputs.size(); i++) {
AudioOutputDescriptor *desc = mOutputs.valueAt(i);
- //take the biggest latency for all outputs
- if (delayMs < (int)desc->mLatency*2) {
+ // mute media and sonification strategies and delay device switch by the largest
+ // latency of any output where either strategy is active.
+ // This avoid sending the ring tone or music tail into the earpiece or headset.
+ if ((desc->isStrategyActive(STRATEGY_MEDIA,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime) ||
+ desc->isStrategyActive(STRATEGY_SONIFICATION,
+ SONIFICATION_HEADSET_MUSIC_DELAY,
+ sysTime)) &&
+ (delayMs < (int)desc->mLatency*2)) {
delayMs = desc->mLatency*2;
}
- //mute STRATEGY_MEDIA on all outputs
- if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) {
- setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
- setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
- getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
- }
+ setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+ setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
}
}
// pertaining to sonification strategy see handleIncallSonification()
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
- // unmute the ringing tone after a sufficient delay if it was muted before
- // setting output device above
- if (oldState == AudioSystem::MODE_RINGTONE) {
- setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS);
- }
for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
handleIncallSonification(stream, true, true);
}
channelMask,
(audio_output_flags_t)flags);
if (profile != NULL) {
+ AudioOutputDescriptor *outputDesc = NULL;
- ALOGV("getOutput() opening direct output device %x", device);
-
- AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(profile);
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+ outputDesc = desc;
+ // reuse direct output if currently open and configured with same parameters
+ if ((samplingRate == outputDesc->mSamplingRate) &&
+ (format == outputDesc->mFormat) &&
+ (channelMask == outputDesc->mChannelMask)) {
+ outputDesc->mDirectOpenCount++;
+ ALOGV("getOutput() reusing direct output %d", output);
+ return mOutputs.keyAt(i);
+ }
+ }
+ }
+ // close direct output if currently open and configured with different parameters
+ if (outputDesc != NULL) {
+ closeOutput(outputDesc->mId);
+ }
+ outputDesc = new AudioOutputDescriptor(profile);
outputDesc->mDevice = device;
outputDesc->mSamplingRate = samplingRate;
outputDesc->mFormat = (audio_format_t)format;
outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);;
outputDesc->mRefCount[stream] = 0;
outputDesc->mStopTime[stream] = 0;
+ outputDesc->mDirectOpenCount = 1;
output = mpClientInterface->openOutput(profile->mModule->mHandle,
&outputDesc->mDevice,
&outputDesc->mSamplingRate,
return 0;
}
addOutput(output, outputDesc);
- ALOGV("getOutput() returns direct output %d", output);
+ mPreviousOutputs = mOutputs;
+ ALOGV("getOutput() returns new direct output %d", output);
return output;
}
audio_io_handle_t curOutput = mOutputs.keyAt(i);
AudioOutputDescriptor *desc = mOutputs.valueAt(i);
if (curOutput != output &&
- desc->refCount() != 0 &&
+ desc->isActive() &&
outputDesc->sharesHwModuleWith(desc) &&
newDevice != desc->device()) {
setOutputDevice(curOutput,
int testIndex = testOutputIndex(output);
if (testIndex != 0) {
AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
- if (outputDesc->refCount() == 0) {
+ if (outputDesc->isActive()) {
mpClientInterface->closeOutput(output);
delete mOutputs.valueAt(index);
mOutputs.removeItem(output);
}
#endif //AUDIO_POLICY_TEST
- if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
- mpClientInterface->closeOutput(output);
- delete mOutputs.valueAt(index);
- mOutputs.removeItem(output);
- mPreviousOutputs = mOutputs;
+ AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+ if (desc->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
+ if (desc->mDirectOpenCount <= 0) {
+ ALOGW("releaseOutput() invalid open count %d for output %d",
+ desc->mDirectOpenCount, output);
+ return;
+ }
+ if (--desc->mDirectOpenCount == 0) {
+ closeOutput(output);
+ }
}
}
}
}
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ inputDesc->mDevice = newDevice;
+ }
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
{
nsecs_t sysTime = systemTime();
for (size_t i = 0; i < mOutputs.size(); i++) {
- if (mOutputs.valueAt(i)->mRefCount[stream] != 0 ||
- ns2ms(sysTime - mOutputs.valueAt(i)->mStopTime[stream]) < inPastMs) {
+ const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioPolicyManagerBase::isStreamActiveRemotely(int stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+ outputDesc->isStreamActive((AudioSystem::stream_type)stream, inPastMs, sysTime)) {
return true;
}
}
mpClientInterface->setParameters(output, param.toString());
mpClientInterface->closeOutput(output);
- delete mOutputs.valueFor(output);
+ delete outputDesc;
mOutputs.removeItem(output);
+ mPreviousOutputs = mOutputs;
}
SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device,
// mute strategy while moving tracks from one output to another
for (size_t i = 0; i < srcOutputs.size(); i++) {
AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
- if (desc->strategyRefCount(strategy) != 0) {
+ if (desc->isStrategyActive(strategy)) {
setStrategyMute(strategy, true, srcOutputs[i]);
setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
}
// use device for strategy media
// 6: the strategy DTMF is active on the output:
// use device for strategy DTMF
- if (outputDesc->isUsedByStrategy(STRATEGY_ENFORCED_AUDIBLE)) {
+ if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isInCall() ||
- outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
+ outputDesc->isStrategyActive(STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
- } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
- } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION_RESPECTFUL)) {
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
- } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
+ } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
- } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
+ } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}
case STRATEGY_SONIFICATION_RESPECTFUL:
if (isInCall()) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActiveRemotely(AudioSystem::MUSIC,
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing on a remote device, use the the sonification behavior.
+ // Note that we test this usecase before testing if media is playing because
+ // the isStreamActive() method only informs about the activity of a stream, not
+ // if it's for local playback. Note also that we use the same delay between both tests
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
} 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 /*fromCache*/);
uint32_t muteWaitMs = 0;
audio_devices_t device = outputDesc->device();
- bool shouldMute = (outputDesc->refCount() != 0) &&
- (AudioSystem::popCount(device) >= 2);
+ bool shouldMute = outputDesc->isActive() && (AudioSystem::popCount(device) >= 2);
// temporary mute output if device selection changes to avoid volume bursts due to
// different per device volumes
- bool tempMute = (outputDesc->refCount() != 0) && (device != prevDevice);
+ bool tempMute = outputDesc->isActive() && (device != prevDevice);
for (size_t i = 0; i < NUM_STRATEGIES; i++) {
audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
if (doMute || tempMute) {
for (size_t j = 0; j < mOutputs.size(); j++) {
AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+ // skip output if it does not share any device with current output
if ((desc->supportedDevices() & outputDesc->supportedDevices())
== AUDIO_DEVICE_NONE) {
continue;
ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
mute ? "muting" : "unmuting", i, curDevice, curOutput);
setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
- if (desc->strategyRefCount((routing_strategy)i) != 0) {
- if (tempMute) {
+ if (desc->isStrategyActive((routing_strategy)i)) {
+ // do tempMute only for current output
+ if (tempMute && (desc == outputDesc)) {
setStrategyMute((routing_strategy)i, true, curOutput);
setStrategyMute((routing_strategy)i, false, curOutput,
desc->latency() * 2, device);
}
- if (tempMute || mute) {
+ if ((tempMute && (desc == outputDesc)) || mute) {
if (muteWaitMs < desc->latency()) {
muteWaitMs = desc->latency();
}
ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
AudioParameter param;
- uint32_t muteWaitMs = 0;
+ uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
return muteWaitMs;
}
+ // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+ // output profile
+ if ((device != AUDIO_DEVICE_NONE) &&
+ ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+ return 0;
+ }
+
// filter devices according to output selected
device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
{
uint32_t device = AUDIO_DEVICE_NONE;
- switch(inputSource) {
+ switch (inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ break;
+ }
+ // FALL THROUGH
+
case AUDIO_SOURCE_DEFAULT:
case AUDIO_SOURCE_MIC:
case AUDIO_SOURCE_VOICE_RECOGNITION:
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
break;
- case AUDIO_SOURCE_VOICE_UPLINK:
case AUDIO_SOURCE_VOICE_DOWNLINK:
case AUDIO_SOURCE_VOICE_CALL:
if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
: mId(0), mSamplingRate(0), mFormat((audio_format_t)0),
mChannelMask((audio_channel_mask_t)0), mLatency(0),
mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
- mOutput1(0), mOutput2(0), mProfile(profile)
+ mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
{
// clear usage count for all stream types
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
}
}
-audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device()
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
{
if (isDuplicated()) {
return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
}
-uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount()
-{
- uint32_t refcount = 0;
- for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
- refcount += mRefCount[i];
- }
- return refcount;
-}
-
-uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy)
-{
- uint32_t refCount = 0;
- for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
- if (getStrategy((AudioSystem::stream_type)i) == strategy) {
- refCount += mRefCount[i];
- }
- }
- return refCount;
-}
-
audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices()
{
if (isDuplicated()) {
bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
{
- nsecs_t sysTime = systemTime();
+ return isStrategyActive(NUM_STRATEGIES, inPastMs);
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if ((sysTime == 0) && (inPastMs != 0)) {
+ sysTime = systemTime();
+ }
for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
- if (mRefCount[i] != 0 ||
- ns2ms(sysTime - mStopTime[i]) < inPastMs) {
+ if (((getStrategy((AudioSystem::stream_type)i) == strategy) ||
+ (NUM_STRATEGIES == strategy)) &&
+ isStreamActive((AudioSystem::stream_type)i, inPastMs, sysTime)) {
return true;
}
}
return false;
}
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isStreamActive(AudioSystem::stream_type stream,
+ uint32_t inPastMs,
+ nsecs_t sysTime) const
+{
+ if (mRefCount[stream] != 0) {
+ return true;
+ }
+ if (inPastMs == 0) {
+ return false;
+ }
+ if (sysTime == 0) {
+ sysTime = systemTime();
+ }
+ if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
+ return true;
+ }
+ return false;
+}
+
+
status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
const struct StringToEnum sInChannelsNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
};
extern void get_dhcp_info();
extern int init_module(void *, unsigned long, const char *);
extern int delete_module(const char *, unsigned int);
+void wifi_close_sockets(int index);
static char primary_iface[PROPERTY_VALUE_MAX];
// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
char *pbuf;
char *sptr;
struct stat sb;
+ int ret;
if (stat(config_file, &sb) != 0)
return -1;
} else {
strcpy(ifc, CONTROL_IFACE_PATH);
}
+ /* Assume file is invalid to begin with */
+ ret = -1;
/*
* if there is a "ctrl_interface=<value>" entry, re-write it ONLY if it is
* NOT a directory. The non-directory value option is an Android add-on
* The <value> is deemed to be a directory if the "DIR=" form is used or
* the value begins with "/".
*/
- if ((sptr = strstr(pbuf, "ctrl_interface=")) &&
- (!strstr(pbuf, "ctrl_interface=DIR=")) &&
- (!strstr(pbuf, "ctrl_interface=/"))) {
- char *iptr = sptr + strlen("ctrl_interface=");
- int ilen = 0;
- int mlen = strlen(ifc);
- int nwrite;
- if (strncmp(ifc, iptr, mlen) != 0) {
- ALOGE("ctrl_interface != %s", ifc);
- while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n'))
- ilen++;
- mlen = ((ilen >= mlen) ? ilen : mlen) + 1;
- memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf));
- memset(iptr, '\n', mlen);
- memcpy(iptr, ifc, strlen(ifc));
- destfd = TEMP_FAILURE_RETRY(open(config_file, O_RDWR, 0660));
- if (destfd < 0) {
- ALOGE("Cannot update \"%s\": %s", config_file, strerror(errno));
- free(pbuf);
- return -1;
+ if (sptr = strstr(pbuf, "ctrl_interface=")) {
+ ret = 0;
+ if ((!strstr(pbuf, "ctrl_interface=DIR=")) &&
+ (!strstr(pbuf, "ctrl_interface=/"))) {
+ char *iptr = sptr + strlen("ctrl_interface=");
+ int ilen = 0;
+ int mlen = strlen(ifc);
+ int nwrite;
+ if (strncmp(ifc, iptr, mlen) != 0) {
+ ALOGE("ctrl_interface != %s", ifc);
+ while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n'))
+ ilen++;
+ mlen = ((ilen >= mlen) ? ilen : mlen) + 1;
+ memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf));
+ memset(iptr, '\n', mlen);
+ memcpy(iptr, ifc, strlen(ifc));
+ destfd = TEMP_FAILURE_RETRY(open(config_file, O_RDWR, 0660));
+ if (destfd < 0) {
+ ALOGE("Cannot update \"%s\": %s", config_file, strerror(errno));
+ free(pbuf);
+ return -1;
+ }
+ TEMP_FAILURE_RETRY(write(destfd, pbuf, nread + mlen - ilen -1));
+ close(destfd);
}
- TEMP_FAILURE_RETRY(write(destfd, pbuf, nread + mlen - ilen -1));
- close(destfd);
}
}
free(pbuf);
- return 0;
+ return ret;
}
int ensure_config_file_exists(const char *config_file)
ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
return -1;
}
- /* return if filesize is at least 10 bytes */
- if (stat(config_file, &sb) == 0 && sb.st_size > 10) {
- return update_ctrl_interface(config_file);
+ /* return if we were able to update control interface properly */
+ if (update_ctrl_interface(config_file) >=0) {
+ return 0;
+ } else {
+ /* This handles the scenario where the file had bad data
+ * for some reason. We continue and recreate the file.
+ */
}
} else if (errno != ENOENT) {
ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
int wifi_wait_on_socket(int index, char *buf, size_t buflen)
{
size_t nread = buflen - 1;
- int fd;
- fd_set rfds;
int result;
- struct timeval tval;
- struct timeval *tptr;
if (monitor_conn[index] == NULL) {
ALOGD("Connection closed\n");