summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--audio/Android.mk5
-rw-r--r--audio/AudioHardwareGeneric.h2
-rw-r--r--audio/AudioHardwareStub.cpp4
-rw-r--r--audio/AudioHardwareStub.h2
-rw-r--r--audio/AudioPolicyCompatClient.cpp5
-rw-r--r--audio/AudioPolicyCompatClient.h3
-rw-r--r--audio/AudioPolicyManagerBase.cpp707
-rw-r--r--audio/audio_policy.conf20
-rw-r--r--audio/audio_policy_hal.cpp46
-rw-r--r--include/hardware_legacy/AudioPolicyInterface.h11
-rw-r--r--include/hardware_legacy/AudioPolicyManagerBase.h52
-rw-r--r--include/hardware_legacy/audio_policy_conf.h1
-rw-r--r--include/hardware_legacy/driver_nl80211.h202
-rw-r--r--include/hardware_legacy/wifi.h17
-rw-r--r--wifi/Android.mk7
-rw-r--r--wifi/wifi.c354
17 files changed, 984 insertions, 456 deletions
diff --git a/Android.mk b/Android.mk
index 1faf6e2..0a82a1f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,7 +9,7 @@ LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SHARED_LIBRARIES := libcutils libwpa_client
+LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_INCLUDES += $(LOCAL_PATH)
diff --git a/audio/Android.mk b/audio/Android.mk
index a69b9cd..8f55cf9 100644
--- a/audio/Android.mk
+++ b/audio/Android.mk
@@ -42,7 +42,8 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libutils
+ libutils \
+ liblog
LOCAL_STATIC_LIBRARIES := \
libmedia_helper
@@ -51,7 +52,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := \
libaudiopolicy_legacy
LOCAL_MODULE := audio_policy.default
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/AudioHardwareGeneric.h b/audio/AudioHardwareGeneric.h
index 7b41e95..55498dc 100644
--- a/audio/AudioHardwareGeneric.h
+++ b/audio/AudioHardwareGeneric.h
@@ -92,6 +92,8 @@ public:
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
virtual unsigned int getInputFramesLost() const { return 0; }
+ virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+ virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
private:
AudioHardwareGeneric *mAudioHardware;
diff --git a/audio/AudioHardwareStub.cpp b/audio/AudioHardwareStub.cpp
index 70a8309..1083889 100644
--- a/audio/AudioHardwareStub.cpp
+++ b/audio/AudioHardwareStub.cpp
@@ -204,6 +204,10 @@ String8 AudioStreamInStub::getParameters(const String8& keys)
return param.toString();
}
+AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardwareStub();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/audio/AudioHardwareStub.h b/audio/AudioHardwareStub.h
index 0858f37..c5f7a80 100644
--- a/audio/AudioHardwareStub.h
+++ b/audio/AudioHardwareStub.h
@@ -58,6 +58,8 @@ public:
virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
virtual String8 getParameters(const String8& keys);
virtual unsigned int getInputFramesLost() const { return 0; }
+ virtual status_t addAudioEffect(effect_handle_t effect) { return NO_ERROR; }
+ virtual status_t removeAudioEffect(effect_handle_t effect) { return NO_ERROR; }
};
class AudioHardwareStub : public AudioHardwareBase
diff --git a/audio/AudioPolicyCompatClient.cpp b/audio/AudioPolicyCompatClient.cpp
index 4c80428..162968c 100644
--- a/audio/AudioPolicyCompatClient.cpp
+++ b/audio/AudioPolicyCompatClient.cpp
@@ -41,11 +41,12 @@ audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t modu
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask,
uint32_t *pLatencyMs,
- audio_output_flags_t flags)
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
{
return mServiceOps->open_output_on_module(mService, module, pDevices, pSamplingRate,
pFormat, pChannelMask, pLatencyMs,
- flags);
+ flags, offloadInfo);
}
audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1,
diff --git a/audio/AudioPolicyCompatClient.h b/audio/AudioPolicyCompatClient.h
index 5399c8c..494c8af 100644
--- a/audio/AudioPolicyCompatClient.h
+++ b/audio/AudioPolicyCompatClient.h
@@ -43,7 +43,8 @@ public:
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask,
uint32_t *pLatencyMs,
- audio_output_flags_t flags);
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo);
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
audio_io_handle_t output2);
virtual status_t closeOutput(audio_io_handle_t output);
diff --git a/audio/AudioPolicyManagerBase.cpp b/audio/AudioPolicyManagerBase.cpp
index 134fb3b..65e732f 100644
--- a/audio/AudioPolicyManagerBase.cpp
+++ b/audio/AudioPolicyManagerBase.cpp
@@ -27,6 +27,9 @@
// 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>
@@ -34,6 +37,7 @@
#include <hardware/audio.h>
#include <math.h>
#include <hardware_legacy/audio_policy_conf.h>
+#include <cutils/properties.h>
namespace android_audio_legacy {
@@ -158,10 +162,12 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device
// outputs must be closed after checkOutputForAllStrategies() is executed
if (!outputs.isEmpty()) {
for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
// close unused outputs after device disconnection or direct outputs that have been
// opened by checkOutputsForDevice() to query dynamic parameters
if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
- (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+ (desc->mDirectOpenCount == 0))) {
closeOutput(outputs[i]);
}
}
@@ -306,11 +312,19 @@ void AudioPolicyManagerBase::setPhoneState(int state)
// force routing command to audio hardware when starting a call
// even if no device change is needed
force = true;
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+ sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
+ }
} else if (isStateInCall(oldState) && !isStateInCall(state)) {
ALOGV(" Exiting call in setPhoneState()");
// force routing command to audio hardware when exiting a call
// even if no device change is needed
force = true;
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+ sVolumeProfiles[AUDIO_STREAM_DTMF][j];
+ }
} else if (isStateInCall(state) && (state != oldState)) {
ALOGV(" Switching between telephony and VoIP in setPhoneState()");
// force routing command to audio hardware when switching between telephony and VoIP
@@ -332,31 +346,29 @@ void AudioPolicyManagerBase::setPhoneState(int state)
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*/));
}
}
@@ -367,11 +379,6 @@ void AudioPolicyManagerBase::setPhoneState(int state)
// 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);
}
@@ -483,6 +490,8 @@ void AudioPolicyManagerBase::setSystemProperty(const char* property, const char*
ALOGV("setSystemProperty() property %s, value %s", property, value);
}
+// Find a direct output profile compatible with the parameters passed, even if the input flags do
+// not explicitly request a direct output
AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOutput(
audio_devices_t device,
uint32_t samplingRate,
@@ -495,14 +504,24 @@ AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getProfileForDirectOu
continue;
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
- IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
- if (profile->isCompatibleProfile(device, samplingRate, format,
+ IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (profile->isCompatibleProfile(device, samplingRate, format,
+ channelMask,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+ if (mAvailableOutputDevices & profile->mSupportedDevices) {
+ return mHwModules[i]->mOutputProfiles[j];
+ }
+ }
+ } else {
+ if (profile->isCompatibleProfile(device, samplingRate, format,
channelMask,
AUDIO_OUTPUT_FLAG_DIRECT)) {
- if (mAvailableOutputDevices & profile->mSupportedDevices) {
- return mHwModules[i]->mOutputProfiles[j];
- }
- }
+ if (mAvailableOutputDevices & profile->mSupportedDevices) {
+ return mHwModules[i]->mOutputProfiles[j];
+ }
+ }
+ }
}
}
return 0;
@@ -512,14 +531,15 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
uint32_t samplingRate,
uint32_t format,
uint32_t channelMask,
- AudioSystem::output_flags flags)
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t *offloadInfo)
{
audio_io_handle_t output = 0;
uint32_t latency = 0;
routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
- ALOGV("getOutput() stream %d, samplingRate %d, format %d, channelMask %x, flags %x",
- stream, samplingRate, format, channelMask, flags);
+ ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
+ device, stream, samplingRate, format, channelMask, flags);
#ifdef AUDIO_POLICY_TEST
if (mCurOutput != 0) {
@@ -541,7 +561,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
&outputDesc->mFormat,
&outputDesc->mChannelMask,
&outputDesc->mLatency,
- outputDesc->mFlags);
+ outputDesc->mFlags,
+ offloadInfo);
if (mTestOutputs[mCurOutput]) {
AudioParameter outputCmd = AudioParameter();
outputCmd.addInt(String8("set_id"),mCurOutput);
@@ -554,31 +575,68 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
#endif //AUDIO_POLICY_TEST
// open a direct output if required by specified parameters
- IOProfile *profile = getProfileForDirectOutput(device,
- samplingRate,
- format,
- channelMask,
- (audio_output_flags_t)flags);
- if (profile != NULL) {
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flags = (AudioSystem::output_flags)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+ }
+
+ // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+ // creating an offloaded track and tearing it down immediately after start when audioflinger
+ // detects there is an active non offloadable effect.
+ // FIXME: We should check the audio session here but we do not have it in this context.
+ // This may prevent offloading in rare situations where effects are left active by apps
+ // in the background.
+ IOProfile *profile = NULL;
+ if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+ !isNonOffloadableEffectEnabled()) {
+ profile = getProfileForDirectOutput(device,
+ samplingRate,
+ format,
+ channelMask,
+ (audio_output_flags_t)flags);
+ }
- ALOGV("getOutput() opening direct output device %x", device);
+ if (profile != NULL) {
+ AudioOutputDescriptor *outputDesc = NULL;
- 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", mOutputs.keyAt(i));
+ 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->mChannelMask = (audio_channel_mask_t)channelMask;
outputDesc->mLatency = 0;
- outputDesc->mFlags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);;
+ outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
outputDesc->mRefCount[stream] = 0;
outputDesc->mStopTime[stream] = 0;
+ outputDesc->mDirectOpenCount = 1;
output = mpClientInterface->openOutput(profile->mModule->mHandle,
&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannelMask,
&outputDesc->mLatency,
- outputDesc->mFlags);
+ outputDesc->mFlags,
+ offloadInfo);
// only accept an output with the requested parameters
if (output == 0 ||
@@ -595,8 +653,14 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
delete outputDesc;
return 0;
}
+ audio_io_handle_t srcOutput = getOutputForEffect();
addOutput(output, outputDesc);
- ALOGV("getOutput() returns direct output %d", output);
+ audio_io_handle_t dstOutput = getOutputForEffect();
+ if (dstOutput == output) {
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput);
+ }
+ mPreviousOutputs = mOutputs;
+ ALOGV("getOutput() returns new direct output %d", output);
return output;
}
@@ -604,13 +668,15 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str
// open a non direct output
- // get which output is suitable for the specified stream. The actual routing change will happen
- // when startOutput() will be called
- SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+ // for non direct outputs, only PCM is supported
+ if (audio_is_linear_pcm((audio_format_t)format)) {
+ // get which output is suitable for the specified stream. The actual
+ // routing change will happen when startOutput() will be called
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
- output = selectOutput(outputs, flags);
-
- ALOGW_IF((output ==0), "getOutput() could not find output for stream %d, samplingRate %d,"
+ output = selectOutput(outputs, flags);
+ }
+ ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
"format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
ALOGV("getOutput() returns output %d", output);
@@ -770,9 +836,9 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t 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()) {
+ (newDevice != desc->device())) {
setOutputDevice(curOutput,
getNewDevice(curOutput, false /*fromCache*/),
true,
@@ -802,7 +868,7 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
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);
@@ -812,15 +878,26 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t 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);
+ // If effects where present on the output, audioflinger moved them to the primary
+ // output by default: move them back to the appropriate output.
+ audio_io_handle_t dstOutput = getOutputForEffect();
+ if (dstOutput != mPrimaryOutput) {
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput);
+ }
+ }
}
-
}
+
audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,
uint32_t samplingRate,
uint32_t format,
@@ -914,17 +991,40 @@ status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)
if (mTestInput == 0)
#endif //AUDIO_POLICY_TEST
{
- // refuse 2 active AudioRecord clients at the same time
- if (getActiveInput() != 0) {
- ALOGW("startInput() input %d failed: other input already started", input);
- return INVALID_OPERATION;
+ // refuse 2 active AudioRecord clients at the same time except if the active input
+ // uses AUDIO_SOURCE_HOTWORD in which case it is closed.
+ audio_io_handle_t activeInput = getActiveInput();
+ if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) {
+ AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput);
+ if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
+ ALOGW("startInput() preempting already started low-priority input %d", activeInput);
+ stopInput(activeInput);
+ releaseInput(activeInput);
+ } else {
+ ALOGW("startInput() input %d failed: other input already started..", input);
+ return INVALID_OPERATION;
+ }
}
}
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ inputDesc->mDevice = newDevice;
+ }
+
+ // automatically enable the remote submix output when input is started
+ if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AudioSystem::DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ }
+
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
- param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource);
+ int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
+ AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
+
+ param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
mpClientInterface->setParameters(input, param.toString());
@@ -947,6 +1047,12 @@ status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
} else {
+ // automatically disable the remote submix output when input is stopped
+ if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+ setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AudioSystem::DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+ }
+
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), 0);
mpClientInterface->setParameters(input, param.toString());
@@ -1012,7 +1118,7 @@ status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type s
for (size_t i = 0; i < mOutputs.size(); i++) {
audio_devices_t curDevice =
getDeviceForVolume(mOutputs.valueAt(i)->device());
- if (device == curDevice) {
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
if (volStatus != NO_ERROR) {
status = volStatus;
@@ -1044,22 +1150,60 @@ status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type s
return NO_ERROR;
}
+audio_io_handle_t AudioPolicyManagerBase::selectOutputForEffects(
+ const SortedVector<audio_io_handle_t>& outputs)
+{
+ // select one output among several suitable for global effects.
+ // The priority is as follows:
+ // 1: An offloaded output. If the effect ends up not being offloadable,
+ // AudioFlinger will invalidate the track and the offloaded output
+ // will be closed causing the effect to be moved to a PCM output.
+ // 2: A deep buffer output
+ // 3: the first output in the list
+
+ if (outputs.size() == 0) {
+ return 0;
+ }
+
+ audio_io_handle_t outputOffloaded = 0;
+ audio_io_handle_t outputDeepBuffer = 0;
+
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+ ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags);
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ outputOffloaded = outputs[i];
+ }
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+ outputDeepBuffer = outputs[i];
+ }
+ }
+
+ ALOGV("selectOutputForEffects outputOffloaded %d outputDeepBuffer %d",
+ outputOffloaded, outputDeepBuffer);
+ if (outputOffloaded != 0) {
+ return outputOffloaded;
+ }
+ if (outputDeepBuffer != 0) {
+ return outputDeepBuffer;
+ }
+
+ return outputs[0];
+}
+
audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(const effect_descriptor_t *desc)
{
- ALOGV("getOutputForEffect()");
// apply simple rule where global effects are attached to the same output as MUSIC streams
routing_strategy strategy = getStrategy(AudioSystem::MUSIC);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs);
- int outIdx = 0;
- for (size_t i = 0; i < dstOutputs.size(); i++) {
- AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]);
- if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- outIdx = i;
- }
- }
- return dstOutputs[outIdx];
+
+ audio_io_handle_t output = selectOutputForEffects(dstOutputs);
+ ALOGV("getOutputForEffect() got output %d for fx %s flags %x",
+ output, (desc == NULL) ? "unspecified" : desc->name, (desc == NULL) ? 0 : desc->flags);
+
+ return output;
}
status_t AudioPolicyManagerBase::registerEffect(const effect_descriptor_t *desc,
@@ -1166,12 +1310,39 @@ status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool
return NO_ERROR;
}
+bool AudioPolicyManagerBase::isNonOffloadableEffectEnabled()
+{
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ const EffectDescriptor * const pDesc = mEffects.valueAt(i);
+ if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) &&
+ ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+ ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
+ pDesc->mDesc.name, pDesc->mSession);
+ return true;
+ }
+ }
+ return false;
+}
+
bool AudioPolicyManagerBase::isStreamActive(int stream, uint32_t inPastMs) const
{
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;
}
}
@@ -1182,8 +1353,10 @@ bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const
{
for (size_t i = 0; i < mInputs.size(); i++) {
const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
- if ((inputDescriptor->mInputSource == (int) source)
- && (inputDescriptor->mRefCount > 0)) {
+ if ((inputDescriptor->mInputSource == (int)source ||
+ (source == (audio_source_t)AUDIO_SOURCE_VOICE_RECOGNITION &&
+ inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
+ && (inputDescriptor->mRefCount > 0)) {
return true;
}
}
@@ -1191,7 +1364,6 @@ bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const
}
-
status_t AudioPolicyManagerBase::dump(int fd)
{
const size_t SIZE = 256;
@@ -1279,6 +1451,73 @@ status_t AudioPolicyManagerBase::dump(int fd)
return NO_ERROR;
}
+// This function checks for the parameters which can be offloaded.
+// This can be enhanced depending on the capability of the DSP and policy
+// of the system.
+bool AudioPolicyManagerBase::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",
+ offloadInfo.sample_rate, offloadInfo.channel_mask,
+ offloadInfo.format,
+ offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
+ offloadInfo.has_video);
+
+ // Check if offload has been disabled
+ char propValue[PROPERTY_VALUE_MAX];
+ if (property_get("audio.offload.disable", propValue, "0")) {
+ if (atoi(propValue) != 0) {
+ ALOGV("offload disabled by audio.offload.disable=%s", propValue );
+ return false;
+ }
+ }
+
+ // Check if stream type is music, then only allow offload as of now.
+ if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
+ {
+ ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
+ return false;
+ }
+
+ //TODO: enable audio offloading with video when ready
+ if (offloadInfo.has_video)
+ {
+ ALOGV("isOffloadSupported: has_video == true, returning false");
+ return false;
+ }
+
+ //If duration is less than minimum value defined in property, return false
+ if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
+ if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
+ ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
+ return false;
+ }
+ } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
+ ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
+ return false;
+ }
+
+ // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+ // creating an offloaded track and tearing it down immediately after start when audioflinger
+ // detects there is an active non offloadable effect.
+ // FIXME: We should check the audio session here but we do not have it in this context.
+ // This may prevent offloading in rare situations where effects are left active by apps
+ // in the background.
+ if (isNonOffloadableEffectEnabled()) {
+ return false;
+ }
+
+ // See if there is a profile to support this.
+ // AUDIO_DEVICE_NONE
+ IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+ offloadInfo.sample_rate,
+ offloadInfo.format,
+ offloadInfo.channel_mask,
+ AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
+ return (profile != NULL);
+}
+
// ----------------------------------------------------------------------------
// AudioPolicyManagerBase
// ----------------------------------------------------------------------------
@@ -1293,7 +1532,8 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
mPhoneState(AudioSystem::MODE_NORMAL),
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
- mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false)
+ mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+ mSpeakerDrcEnabled(false)
{
mpClientInterface = clientInterface;
@@ -1301,8 +1541,6 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
mForceUse[i] = AudioSystem::FORCE_NONE;
}
- initializeVolumeCurves();
-
mA2dpDeviceAddress = String8("");
mScoDeviceAddress = String8("");
mUsbCardAndDevice = String8("");
@@ -1314,6 +1552,9 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
}
}
+ // must be done after reading the policy
+ initializeVolumeCurves();
+
// open all output streams needed to access attached devices
for (size_t i = 0; i < mHwModules.size(); i++) {
mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
@@ -1322,11 +1563,14 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
continue;
}
// open all output streams needed to access attached devices
+ // except for direct output streams that are only opened when they are actually
+ // required by an app.
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
- if (outProfile->mSupportedDevices & mAttachedOutputDevices) {
+ if ((outProfile->mSupportedDevices & mAttachedOutputDevices) &&
+ ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &
outProfile->mSupportedDevices);
@@ -1628,13 +1872,19 @@ status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
ALOGV("opening output for device %08x", device);
desc = new AudioOutputDescriptor(profile);
desc->mDevice = device;
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.sample_rate = desc->mSamplingRate;
+ offloadInfo.format = desc->mFormat;
+ offloadInfo.channel_mask = desc->mChannelMask;
+
audio_io_handle_t output = mpClientInterface->openOutput(profile->mModule->mHandle,
&desc->mDevice,
&desc->mSamplingRate,
&desc->mFormat,
&desc->mChannelMask,
&desc->mLatency,
- desc->mFlags);
+ desc->mFlags,
+ &offloadInfo);
if (output != 0) {
if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
String8 reply;
@@ -1813,8 +2063,9 @@ void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
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,
@@ -1861,7 +2112,7 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
// 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);
}
@@ -1869,26 +2120,20 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
// Move effects associated to this strategy from previous output to new output
if (strategy == STRATEGY_MEDIA) {
- int outIdx = 0;
- for (size_t i = 0; i < dstOutputs.size(); i++) {
- AudioOutputDescriptor *desc = mOutputs.valueFor(dstOutputs[i]);
- if (desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- outIdx = i;
- }
- }
+ audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs);
SortedVector<audio_io_handle_t> moved;
for (size_t i = 0; i < mEffects.size(); i++) {
EffectDescriptor *desc = mEffects.valueAt(i);
if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
- desc->mIo != dstOutputs[outIdx]) {
+ desc->mIo != fxOutput) {
if (moved.indexOf(desc->mIo) < 0) {
ALOGV("checkOutputForStrategy() moving effect %d to output %d",
- mEffects.keyAt(i), dstOutputs[outIdx]);
+ mEffects.keyAt(i), fxOutput);
mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
- dstOutputs[outIdx]);
+ fxOutput);
moved.add(desc->mIo);
}
- desc->mIo = dstOutputs[outIdx];
+ desc->mIo = fxOutput;
}
}
}
@@ -1992,18 +2237,18 @@ audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, b
// 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);
}
@@ -2083,6 +2328,13 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy st
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*/);
@@ -2293,11 +2545,10 @@ uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor
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*/);
@@ -2314,6 +2565,7 @@ uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor
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;
@@ -2322,13 +2574,14 @@ uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor
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();
}
@@ -2360,13 +2613,20 @@ uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
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);
@@ -2428,10 +2688,18 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
{
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:
+ case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_VOICE_COMMUNICATION:
if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
@@ -2449,7 +2717,6 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
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) {
@@ -2609,15 +2876,27 @@ const AudioPolicyManagerBase::VolumeCurvePoint
{1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
};
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
-// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets (See AudioService.java).
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
};
const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
AudioPolicyManagerBase::sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
{1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
};
@@ -2695,6 +2974,18 @@ void AudioPolicyManagerBase::initializeVolumeCurves()
sVolumeProfiles[i][j];
}
}
+
+ // Check availability of DRC on speaker path: if available, override some of the speaker curves
+ if (mSpeakerDrcEnabled) {
+ mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sDefaultSystemVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+ sSpeakerSonificationVolumeCurveDrc;
+ }
}
float AudioPolicyManagerBase::computeVolume(int stream,
@@ -2943,17 +3234,6 @@ bool AudioPolicyManagerBase::isStateInCall(int state) {
(state == AudioSystem::MODE_IN_COMMUNICATION));
}
-bool AudioPolicyManagerBase::needsDirectOuput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- audio_devices_t device)
-{
- return ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
- (format != 0 && !AudioSystem::isLinearPCM(format)));
-}
-
uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
{
return MAX_EFFECTS_CPU_LOAD;
@@ -2971,7 +3251,7 @@ AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
: 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++) {
@@ -2991,7 +3271,7 @@ AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
}
}
-audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device()
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
{
if (isDuplicated()) {
return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
@@ -3037,26 +3317,6 @@ void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::
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()) {
@@ -3068,16 +3328,46 @@ audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices(
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;
@@ -3086,7 +3376,7 @@ status_t AudioPolicyManagerBase::AudioOutputDescriptor::dump(int fd)
snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
result.append(buffer);
- snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
result.append(buffer);
snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
result.append(buffer);
@@ -3254,57 +3544,54 @@ AudioPolicyManagerBase::IOProfile::~IOProfile()
{
}
-// checks if the IO profile is compatible with specified parameters. By convention a value of 0
-// means a parameter is don't care
+// checks if the IO profile is compatible with specified parameters.
+// Sampling rate, format and channel mask must be specified in order to
+// get a valid a match
bool AudioPolicyManagerBase::IOProfile::isCompatibleProfile(audio_devices_t device,
uint32_t samplingRate,
uint32_t format,
uint32_t channelMask,
audio_output_flags_t flags) const
{
- if ((mSupportedDevices & device) != device) {
- return false;
- }
- if ((mFlags & flags) != flags) {
- return false;
- }
- if (samplingRate != 0) {
- size_t i;
- for (i = 0; i < mSamplingRates.size(); i++)
- {
- if (mSamplingRates[i] == samplingRate) {
- break;
- }
- }
- if (i == mSamplingRates.size()) {
- return false;
- }
- }
- if (format != 0) {
- size_t i;
- for (i = 0; i < mFormats.size(); i++)
- {
- if (mFormats[i] == format) {
- break;
- }
- }
- if (i == mFormats.size()) {
- return false;
- }
- }
- if (channelMask != 0) {
- size_t i;
- for (i = 0; i < mChannelMasks.size(); i++)
- {
- if (mChannelMasks[i] == channelMask) {
- break;
- }
- }
- if (i == mChannelMasks.size()) {
- return false;
- }
- }
- return true;
+ if (samplingRate == 0 || format == 0 || channelMask == 0) {
+ return false;
+ }
+
+ if ((mSupportedDevices & device) != device) {
+ return false;
+ }
+ if ((mFlags & flags) != flags) {
+ return false;
+ }
+ size_t i;
+ for (i = 0; i < mSamplingRates.size(); i++)
+ {
+ if (mSamplingRates[i] == samplingRate) {
+ break;
+ }
+ }
+ if (i == mSamplingRates.size()) {
+ return false;
+ }
+ for (i = 0; i < mFormats.size(); i++)
+ {
+ if (mFormats[i] == format) {
+ break;
+ }
+ }
+ if (i == mFormats.size()) {
+ return false;
+ }
+ for (i = 0; i < mChannelMasks.size(); i++)
+ {
+ if (mChannelMasks[i] == channelMask) {
+ break;
+ }
+ }
+ if (i == mChannelMasks.size()) {
+ return false;
+ }
+ return true;
}
void AudioPolicyManagerBase::IOProfile::dump(int fd)
@@ -3324,7 +3611,7 @@ void AudioPolicyManagerBase::IOProfile::dump(int fd)
snprintf(buffer, SIZE, " - channel masks: ");
result.append(buffer);
for (size_t i = 0; i < mChannelMasks.size(); i++) {
- snprintf(buffer, SIZE, "%04x", mChannelMasks[i]);
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
result.append(buffer);
result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", ");
}
@@ -3332,14 +3619,14 @@ void AudioPolicyManagerBase::IOProfile::dump(int fd)
snprintf(buffer, SIZE, " - formats: ");
result.append(buffer);
for (size_t i = 0; i < mFormats.size(); i++) {
- snprintf(buffer, SIZE, "%d", mFormats[i]);
+ snprintf(buffer, SIZE, "0x%08x", mFormats[i]);
result.append(buffer);
result.append(i == (mFormats.size() - 1) ? "\n" : ", ");
}
- snprintf(buffer, SIZE, " - devices: %04x\n", mSupportedDevices);
+ snprintf(buffer, SIZE, " - devices: 0x%04x\n", mSupportedDevices);
result.append(buffer);
- snprintf(buffer, SIZE, " - flags: %04x\n", mFlags);
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
result.append(buffer);
write(fd, result.string(), result.size());
@@ -3386,6 +3673,8 @@ const struct StringToEnum sFlagNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
};
const struct StringToEnum sFormatNameToEnumTable[] = {
@@ -3406,6 +3695,7 @@ const struct StringToEnum sOutChannelsNameToEnumTable[] = {
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),
};
@@ -3422,6 +3712,11 @@ uint32_t AudioPolicyManagerBase::stringToEnum(const struct StringToEnum *table,
return 0;
}
+bool AudioPolicyManagerBase::stringToBool(const char *value)
+{
+ return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name)
{
uint32_t flag = 0;
@@ -3437,6 +3732,13 @@ audio_output_flags_t AudioPolicyManagerBase::parseFlagNames(char *name)
}
flagName = strtok(NULL, "|");
}
+ //force direct flag if offload flag is set: offloading implies a direct output stream
+ // and all common behaviors are driven by checking only the direct flag
+ // this should normally be set appropriately in the policy configuration file
+ if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+ }
+
return (audio_output_flags_t)flag;
}
@@ -3720,6 +4022,9 @@ void AudioPolicyManagerBase::loadGlobalConfig(cnode *root)
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
+ } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ mSpeakerDrcEnabled = stringToBool((char *)node->value);
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
}
node = node->next;
}
diff --git a/audio/audio_policy.conf b/audio/audio_policy.conf
index d4e7844..3e29976 100644
--- a/audio/audio_policy.conf
+++ b/audio/audio_policy.conf
@@ -9,7 +9,7 @@
global_configuration {
attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
default_output_device AUDIO_DEVICE_OUT_SPEAKER
- attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
+ attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX
}
# audio hardware module section: contains descriptors for all audio hw modules present on the
@@ -43,4 +43,22 @@ audio_hw_modules {
}
}
}
+ r_submix {
+ outputs {
+ submix {
+ sampling_rates 48000
+ channel_masks AUDIO_CHANNEL_OUT_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ }
+ }
+ inputs {
+ submix {
+ sampling_rates 48000
+ channel_masks AUDIO_CHANNEL_IN_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
+ }
+ }
+ }
}
diff --git a/audio/audio_policy_hal.cpp b/audio/audio_policy_hal.cpp
index bff6b74..e44bc48 100644
--- a/audio/audio_policy_hal.cpp
+++ b/audio/audio_policy_hal.cpp
@@ -138,14 +138,16 @@ static audio_io_handle_t ap_get_output(struct audio_policy *pol,
uint32_t sampling_rate,
audio_format_t format,
audio_channel_mask_t channelMask,
- audio_output_flags_t flags)
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
{
struct legacy_audio_policy *lap = to_lap(pol);
ALOGV("%s: tid %d", __func__, gettid());
return lap->apm->getOutput((AudioSystem::stream_type)stream,
sampling_rate, (int) format, channelMask,
- (AudioSystem::output_flags)flags);
+ (AudioSystem::output_flags)flags,
+ offloadInfo);
}
static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
@@ -302,6 +304,13 @@ static bool ap_is_stream_active(const struct audio_policy *pol, audio_stream_typ
return lap->apm->isStreamActive((int) stream, in_past_ms);
}
+static bool ap_is_stream_active_remotely(const struct audio_policy *pol, audio_stream_type_t stream,
+ uint32_t in_past_ms)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isStreamActiveRemotely((int) stream, in_past_ms);
+}
+
static bool ap_is_source_active(const struct audio_policy *pol, audio_source_t source)
{
const struct legacy_audio_policy *lap = to_clap(pol);
@@ -314,6 +323,13 @@ static int ap_dump(const struct audio_policy *pol, int fd)
return lap->apm->dump(fd);
}
+static bool ap_is_offload_supported(const struct audio_policy *pol,
+ const audio_offload_info_t *info)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->isOffloadSupported(*info);
+}
+
static int create_legacy_ap(const struct audio_policy_device *device,
struct audio_policy_service_ops *aps_ops,
void *service,
@@ -358,8 +374,10 @@ static int create_legacy_ap(const struct audio_policy_device *device,
lap->policy.unregister_effect = ap_unregister_effect;
lap->policy.set_effect_enabled = ap_set_effect_enabled;
lap->policy.is_stream_active = ap_is_stream_active;
+ lap->policy.is_stream_active_remotely = ap_is_stream_active_remotely;
lap->policy.is_source_active = ap_is_source_active;
lap->policy.dump = ap_dump;
+ lap->policy.is_offload_supported = ap_is_offload_supported;
lap->service = service;
lap->aps_ops = aps_ops;
@@ -435,21 +453,21 @@ static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
}
static struct hw_module_methods_t legacy_ap_module_methods = {
- open: legacy_ap_dev_open
+ .open = legacy_ap_dev_open
};
struct legacy_ap_module HAL_MODULE_INFO_SYM = {
- module: {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: AUDIO_POLICY_HARDWARE_MODULE_ID,
- name: "LEGACY Audio Policy HAL",
- author: "The Android Open Source Project",
- methods: &legacy_ap_module_methods,
- dso : NULL,
- reserved : {0},
+ .module = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = AUDIO_POLICY_HARDWARE_MODULE_ID,
+ .name = "LEGACY Audio Policy HAL",
+ .author = "The Android Open Source Project",
+ .methods = &legacy_ap_module_methods,
+ .dso = NULL,
+ .reserved = {0},
},
},
};
diff --git a/include/hardware_legacy/AudioPolicyInterface.h b/include/hardware_legacy/AudioPolicyInterface.h
index 51f4822..7847bdd 100644
--- a/include/hardware_legacy/AudioPolicyInterface.h
+++ b/include/hardware_legacy/AudioPolicyInterface.h
@@ -22,6 +22,7 @@
#include <utils/String8.h>
#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware/audio_policy.h>
namespace android_audio_legacy {
using android::Vector;
@@ -92,7 +93,9 @@ public:
uint32_t samplingRate = 0,
uint32_t format = AudioSystem::FORMAT_DEFAULT,
uint32_t channels = 0,
- AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
+ AudioSystem::output_flags flags =
+ AudioSystem::OUTPUT_FLAG_INDIRECT,
+ const audio_offload_info_t *offloadInfo = NULL) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding stream.
virtual status_t startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream,
@@ -157,10 +160,13 @@ public:
virtual status_t setEffectEnabled(int id, bool enabled) = 0;
virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
+ virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const = 0;
virtual bool isSourceActive(audio_source_t source) const = 0;
//dump state
virtual status_t dump(int fd) = 0;
+
+ virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
};
@@ -191,7 +197,8 @@ public:
audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask,
uint32_t *pLatencyMs,
- audio_output_flags_t flags) = 0;
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo = NULL) = 0;
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
// a special mixer thread in the AudioFlinger.
virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) = 0;
diff --git a/include/hardware_legacy/AudioPolicyManagerBase.h b/include/hardware_legacy/AudioPolicyManagerBase.h
index b175670..8343f2b 100644
--- a/include/hardware_legacy/AudioPolicyManagerBase.h
+++ b/include/hardware_legacy/AudioPolicyManagerBase.h
@@ -52,6 +52,10 @@ namespace android_audio_legacy {
#define NUM_VOL_CURVE_KNEES 2
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
// ----------------------------------------------------------------------------
// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms.
// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase
@@ -87,7 +91,8 @@ public:
uint32_t format = AudioSystem::FORMAT_DEFAULT,
uint32_t channels = 0,
AudioSystem::output_flags flags =
- AudioSystem::OUTPUT_FLAG_INDIRECT);
+ AudioSystem::OUTPUT_FLAG_INDIRECT,
+ const audio_offload_info_t *offloadInfo = NULL);
virtual status_t startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream,
int session = 0);
@@ -123,7 +128,7 @@ public:
// return the enabled output devices for the given stream type
virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream);
- virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
virtual status_t registerEffect(const effect_descriptor_t *desc,
audio_io_handle_t io,
uint32_t strategy,
@@ -133,10 +138,16 @@ public:
virtual status_t setEffectEnabled(int id, bool enabled);
virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const;
+ // return whether a stream is playing remotely, override to change the definition of
+ // local/remote playback, used for instance by notification manager to not make
+ // media players lose audio focus when not playing locally
+ virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const;
virtual bool isSourceActive(audio_source_t source) const;
virtual status_t dump(int fd);
+ virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
protected:
enum routing_strategy {
@@ -225,7 +236,9 @@ protected:
static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
// volume curve for sonification strategy on speakers
static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
@@ -241,16 +254,20 @@ protected:
status_t dump(int fd);
- audio_devices_t device();
- void changeRefCount(AudioSystem::stream_type, int delta);
- uint32_t refCount();
- uint32_t strategyRefCount(routing_strategy strategy);
- bool isUsedByStrategy(routing_strategy strategy) { return (strategyRefCount(strategy) != 0);}
+ audio_devices_t device() const;
+ void changeRefCount(AudioSystem::stream_type stream, int delta);
+
bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
audio_devices_t supportedDevices();
uint32_t latency();
bool sharesHwModuleWith(const AudioOutputDescriptor *outputDesc);
- bool isActive(uint32_t inPastMs) const;
+ bool isActive(uint32_t inPastMs = 0) const;
+ bool isStreamActive(AudioSystem::stream_type stream,
+ uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
+ bool isStrategyActive(routing_strategy strategy,
+ uint32_t inPastMs = 0,
+ nsecs_t sysTime = 0) const;
audio_io_handle_t mId; // output handle
uint32_t mSamplingRate; //
@@ -268,6 +285,7 @@ protected:
const IOProfile *mProfile; // I/O profile this output derives from
bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
// device selection. See checkDeviceMuteStrategies()
+ uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
};
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
@@ -432,16 +450,6 @@ protected:
void updateDevicesAndOutputs();
- // true if current platform requires a specific output to be opened for this particular
- // set of parameters. This function is called by getOutput() and is implemented by platform
- // specific audio policy manager.
- virtual bool needsDirectOuput(audio_stream_type_t stream,
- uint32_t samplingRate,
- audio_format_t format,
- audio_channel_mask_t channelMask,
- audio_output_flags_t flags,
- audio_devices_t device);
-
virtual uint32_t getMaxEffectsCpuLoad();
virtual uint32_t getMaxEffectsMemory();
#ifdef AUDIO_POLICY_TEST
@@ -482,12 +490,18 @@ protected:
uint32_t format,
uint32_t channelMask,
audio_output_flags_t flags);
+
+ audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+ bool isNonOffloadableEffectEnabled();
+
//
// Audio policy configuration file parsing (audio_policy.conf)
//
static uint32_t stringToEnum(const struct StringToEnum *table,
size_t size,
const char *name);
+ static bool stringToBool(const char *value);
static audio_output_flags_t parseFlagNames(char *name);
static audio_devices_t parseDeviceNames(char *name);
void loadSamplingRates(char *name, IOProfile *profile);
@@ -541,6 +555,8 @@ protected:
audio_devices_t mAttachedOutputDevices; // output devices always available on the platform
audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time
// (must be in mAttachedOutputDevices)
+ bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
+ // to boost soft sounds, used to adjust volume curves accordingly
Vector <HwModule *> mHwModules;
diff --git a/include/hardware_legacy/audio_policy_conf.h b/include/hardware_legacy/audio_policy_conf.h
index fa58c36..3ec2c94 100644
--- a/include/hardware_legacy/audio_policy_conf.h
+++ b/include/hardware_legacy/audio_policy_conf.h
@@ -34,6 +34,7 @@
#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices"
#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
+#define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
// hw modules descriptions
#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
diff --git a/include/hardware_legacy/driver_nl80211.h b/include/hardware_legacy/driver_nl80211.h
new file mode 100644
index 0000000..eac0879
--- /dev/null
+++ b/include/hardware_legacy/driver_nl80211.h
@@ -0,0 +1,202 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef _DRIVER_NL80211_H_
+#define _DRIVER_NL80211_H_
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+#include "nl80211_copy.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "utils/list.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#include "rfkill.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+struct nl80211_global {
+ struct dl_list interfaces;
+ int if_add_ifindex;
+ u64 if_add_wdevid;
+ int if_add_wdevid_set;
+ struct netlink_data *netlink;
+ struct nl_cb *nl_cb;
+ struct nl_handle *nl;
+ int nl80211_id;
+ int ioctl_sock; /* socket for ioctl() use */
+
+ struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+ struct dl_list list;
+ struct dl_list bsss;
+ struct dl_list drvs;
+
+ struct nl_handle *nl_beacons;
+ struct nl_cb *nl_cb;
+
+ int wiphy_idx;
+};
+
+struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *next;
+ int ifindex;
+ u64 wdev_id;
+ char ifname[IFNAMSIZ + 1];
+ char brname[IFNAMSIZ];
+ unsigned int beacon_set:1;
+ unsigned int added_if_into_bridge:1;
+ unsigned int added_bridge:1;
+ unsigned int in_deinit:1;
+ unsigned int wdev_id_set:1;
+
+ u8 addr[ETH_ALEN];
+
+ int freq;
+
+ void *ctx;
+ struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_cb *nl_cb;
+
+ struct nl80211_wiphy_data *wiphy_data;
+ struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+ struct nl80211_global *global;
+ struct dl_list list;
+ struct dl_list wiphy_list;
+ char phyname[32];
+ void *ctx;
+ int ifindex;
+ int if_removed;
+ int if_disabled;
+ int ignore_if_down_event;
+ struct rfkill_data *rfkill;
+ struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+ int has_capability;
+
+ int operstate;
+
+ int scan_complete_events;
+
+ struct nl_cb *nl_cb;
+
+ u8 auth_bssid[ETH_ALEN];
+ u8 auth_attempt_bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 prev_bssid[ETH_ALEN];
+ int associated;
+ u8 ssid[32];
+ size_t ssid_len;
+ enum nl80211_iftype nlmode;
+ enum nl80211_iftype ap_scan_as_station;
+ unsigned int assoc_freq;
+
+ int monitor_sock;
+ int monitor_ifidx;
+ int monitor_refcount;
+
+ unsigned int disabled_11b_rates:1;
+ unsigned int pending_remain_on_chan:1;
+ unsigned int in_interface_list:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int scan_for_auth:1;
+ unsigned int retry_auth:1;
+ unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
+ unsigned int allow_p2p_device:1;
+
+ u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ unsigned int last_mgmt_freq;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss first_bss;
+
+ int eapol_tx_sock;
+
+#ifdef HOSTAPD
+ int eapol_sock; /* socket for EAPOL frames */
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ int last_freq;
+ int last_freq_ht;
+#endif /* HOSTAPD */
+
+ /* From failed authentication command */
+ int auth_freq;
+ u8 auth_bssid_[ETH_ALEN];
+ u8 auth_ssid[32];
+ size_t auth_ssid_len;
+ int auth_alg;
+ u8 *auth_ie;
+ size_t auth_ie_len;
+ u8 auth_wep_key[4][16];
+ size_t auth_wep_key_len[4];
+ int auth_wep_tx_keyidx;
+ int auth_local_state_change;
+ int auth_p2p;
+};
+
+#endif
diff --git a/include/hardware_legacy/wifi.h b/include/hardware_legacy/wifi.h
index be6a83e..7a64d52 100644
--- a/include/hardware_legacy/wifi.h
+++ b/include/hardware_legacy/wifi.h
@@ -58,25 +58,24 @@ int wifi_start_supplicant(int p2pSupported);
int wifi_stop_supplicant(int p2pSupported);
/**
- * Open a connection to supplicant on interface
+ * Open a connection to supplicant
*
* @return 0 on success, < 0 on failure.
*/
-int wifi_connect_to_supplicant(const char *ifname);
+int wifi_connect_to_supplicant();
/**
- * Close connection to supplicant on interface
+ * Close connection to supplicant
*
* @return 0 on success, < 0 on failure.
*/
-void wifi_close_supplicant_connection(const char *ifname);
+void wifi_close_supplicant_connection();
/**
* wifi_wait_for_event() performs a blocking call to
* get a Wi-Fi event and returns a string representing
* a Wi-Fi event when it occurs.
*
- * @param iface is the interface on which event is received
* @param buf is the buffer that receives the event
* @param len is the maximum length of the buffer
*
@@ -84,7 +83,7 @@ void wifi_close_supplicant_connection(const char *ifname);
* event (for instance, no connection), and less than 0
* if there is an error.
*/
-int wifi_wait_for_event(const char *iface, char *buf, size_t len);
+int wifi_wait_for_event(char *buf, size_t len);
/**
* wifi_command() issues a command to the Wi-Fi driver.
@@ -96,8 +95,8 @@ int wifi_wait_for_event(const char *iface, char *buf, size_t len);
* See wifi/java/android/net/wifi/WifiNative.java for the details of
* driver commands that are supported
*
- * @param iface is the interface on which command is sent
- * @param command is the string command
+ * @param command is the string command (preallocated with 32 bytes)
+ * @param commandlen is command buffer length
* @param reply is a buffer to receive a reply string
* @param reply_len on entry, this is the maximum length of
* the reply buffer. On exit, the number of
@@ -105,7 +104,7 @@ int wifi_wait_for_event(const char *iface, char *buf, size_t len);
*
* @return 0 if successful, < 0 if an error.
*/
-int wifi_command(const char *iface, const char *command, char *reply, size_t *reply_len);
+int wifi_command(const char *command, char *reply, size_t *reply_len);
/**
* do_dhcp_request() issues a dhcp request and returns the acquired
diff --git a/wifi/Android.mk b/wifi/Android.mk
index b4a6a7c..99a4b0e 100644
--- a/wifi/Android.mk
+++ b/wifi/Android.mk
@@ -1,8 +1,5 @@
# Copyright 2006 The Android Open Source Project
-LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
-LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_PREFIX=\"wpa_ctrl_\"
-
ifdef WIFI_DRIVER_MODULE_PATH
LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\"
endif
@@ -30,4 +27,8 @@ endif
LOCAL_SRC_FILES += wifi/wifi.c
+ifdef WPA_SUPPLICANT_VERSION
+LOCAL_CFLAGS += -DLIBWPA_CLIENT_EXISTS
+LOCAL_SHARED_LIBRARIES += libwpa_client
+endif
LOCAL_SHARED_LIBRARIES += libnetutils
diff --git a/wifi/wifi.c b/wifi/wifi.c
index 493c469..f11c1ab 100644
--- a/wifi/wifi.c
+++ b/wifi/wifi.c
@@ -24,7 +24,9 @@
#include <poll.h>
#include "hardware_legacy/wifi.h"
+#ifdef LIBWPA_CLIENT_EXISTS
#include "libwpa_client/wpa_ctrl.h"
+#endif
#define LOG_TAG "WifiHW"
#include "cutils/log.h"
@@ -37,22 +39,6 @@
#include <sys/_system_properties.h>
#endif
-/* PRIMARY refers to the connection on the primary interface
- * SECONDARY refers to an optional connection on a p2p interface
- *
- * For concurrency, we only support one active p2p connection and
- * one active STA connection at a time
- */
-#define PRIMARY 0
-#define SECONDARY 1
-#define MAX_CONNS 2
-
-static struct wpa_ctrl *ctrl_conn[MAX_CONNS];
-static struct wpa_ctrl *monitor_conn[MAX_CONNS];
-
-/* socket pair used to exit from a blocking read */
-static int exit_sockets[MAX_CONNS][2];
-
extern int do_dhcp();
extern int ifc_init();
extern void ifc_close();
@@ -60,6 +46,29 @@ extern char *dhcp_lasterror();
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();
+
+#ifndef LIBWPA_CLIENT_EXISTS
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+struct wpa_ctrl {};
+void wpa_ctrl_cleanup(void) {}
+struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path) { return NULL; }
+void wpa_ctrl_close(struct wpa_ctrl *ctrl) {}
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
+ { return 0; }
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl) { return 0; }
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl) { return 0; }
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+ { return 0; }
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return 0; }
+#endif
+
+static struct wpa_ctrl *ctrl_conn;
+static struct wpa_ctrl *monitor_conn;
+
+/* socket pair used to exit from a blocking read */
+static int exit_sockets[2];
static char primary_iface[PROPERTY_VALUE_MAX];
// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
@@ -108,6 +117,10 @@ static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf";
static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets";
static const char MODULE_FILE[] = "/proc/modules";
+static const char IFNAME[] = "IFNAME=";
+#define IFNAMELEN (sizeof(IFNAME) - 1)
+static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE ";
+
static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE;
static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b,
@@ -119,16 +132,6 @@ static char supplicant_name[PROPERTY_VALUE_MAX];
/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */
static char supplicant_prop_name[PROPERTY_KEY_MAX];
-static int is_primary_interface(const char *ifname)
-{
- //Treat NULL as primary interface to allow control
- //on STA without an interface
- if (ifname == NULL || !strncmp(ifname, primary_iface, strlen(primary_iface))) {
- return 1;
- }
- return 0;
-}
-
static int insmod(const char *filename, const char *args)
{
void *module;
@@ -341,6 +344,7 @@ int update_ctrl_interface(const char *config_file) {
char *pbuf;
char *sptr;
struct stat sb;
+ int ret;
if (stat(config_file, &sb) != 0)
return -1;
@@ -367,6 +371,8 @@ int update_ctrl_interface(const char *config_file) {
} 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
@@ -377,33 +383,35 @@ int update_ctrl_interface(const char *config_file) {
* 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)
@@ -421,9 +429,13 @@ 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));
@@ -474,45 +486,6 @@ int ensure_config_file_exists(const char *config_file)
return update_ctrl_interface(config_file);
}
-/**
- * wifi_wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
- * may be left over from clients that were previously connected to
- * wpa_supplicant. This keeps these files from being orphaned in the
- * event of crashes that prevented them from being removed as part
- * of the normal orderly shutdown.
- */
-void wifi_wpa_ctrl_cleanup(void)
-{
- DIR *dir;
- struct dirent entry;
- struct dirent *result;
- size_t dirnamelen;
- size_t maxcopy;
- char pathname[PATH_MAX];
- char *namep;
- char *local_socket_dir = CONFIG_CTRL_IFACE_CLIENT_DIR;
- char *local_socket_prefix = CONFIG_CTRL_IFACE_CLIENT_PREFIX;
-
- if ((dir = opendir(local_socket_dir)) == NULL)
- return;
-
- dirnamelen = (size_t)snprintf(pathname, sizeof(pathname), "%s/", local_socket_dir);
- if (dirnamelen >= sizeof(pathname)) {
- closedir(dir);
- return;
- }
- namep = pathname + dirnamelen;
- maxcopy = PATH_MAX - dirnamelen;
- while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
- if (strncmp(entry.d_name, local_socket_prefix, strlen(local_socket_prefix)) == 0) {
- if (strlcpy(namep, entry.d_name, maxcopy) < maxcopy) {
- unlink(pathname);
- }
- }
- }
- closedir(dir);
-}
-
int wifi_start_supplicant(int p2p_supported)
{
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
@@ -554,12 +527,10 @@ int wifi_start_supplicant(int p2p_supported)
}
/* Clear out any stale socket files that might be left over. */
- wifi_wpa_ctrl_cleanup();
+ wpa_ctrl_cleanup();
/* Reset sockets used for exiting from hung state */
- for (i=0; i<MAX_CONNS; i++) {
- exit_sockets[i][0] = exit_sockets[i][1] = -1;
- }
+ exit_sockets[0] = exit_sockets[1] = -1;
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
/*
@@ -571,7 +542,7 @@ int wifi_start_supplicant(int p2p_supported)
*/
pi = __system_property_find(supplicant_prop_name);
if (pi != NULL) {
- serial = pi->serial;
+ serial = __system_property_serial(pi);
}
#endif
property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
@@ -588,7 +559,7 @@ int wifi_start_supplicant(int p2p_supported)
__system_property_read(pi, NULL, supp_status);
if (strcmp(supp_status, "running") == 0) {
return 0;
- } else if (pi->serial != serial &&
+ } else if (__system_property_serial(pi) != serial &&
strcmp(supp_status, "stopped") == 0) {
return -1;
}
@@ -637,7 +608,7 @@ int wifi_stop_supplicant(int p2p_supported)
return -1;
}
-int wifi_connect_on_socket_path(int index, const char *path)
+int wifi_connect_on_socket_path(const char *path)
{
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
@@ -648,29 +619,29 @@ int wifi_connect_on_socket_path(int index, const char *path)
return -1;
}
- ctrl_conn[index] = wpa_ctrl_open(path);
- if (ctrl_conn[index] == NULL) {
+ ctrl_conn = wpa_ctrl_open(path);
+ if (ctrl_conn == NULL) {
ALOGE("Unable to open connection to supplicant on \"%s\": %s",
path, strerror(errno));
return -1;
}
- monitor_conn[index] = wpa_ctrl_open(path);
- if (monitor_conn[index] == NULL) {
- wpa_ctrl_close(ctrl_conn[index]);
- ctrl_conn[index] = NULL;
+ monitor_conn = wpa_ctrl_open(path);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
return -1;
}
- if (wpa_ctrl_attach(monitor_conn[index]) != 0) {
- wpa_ctrl_close(monitor_conn[index]);
- wpa_ctrl_close(ctrl_conn[index]);
- ctrl_conn[index] = monitor_conn[index] = NULL;
+ if (wpa_ctrl_attach(monitor_conn) != 0) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
return -1;
}
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets[index]) == -1) {
- wpa_ctrl_close(monitor_conn[index]);
- wpa_ctrl_close(ctrl_conn[index]);
- ctrl_conn[index] = monitor_conn[index] = NULL;
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
return -1;
}
@@ -678,36 +649,30 @@ int wifi_connect_on_socket_path(int index, const char *path)
}
/* Establishes the control and monitor socket connections on the interface */
-int wifi_connect_to_supplicant(const char *ifname)
+int wifi_connect_to_supplicant()
{
- char path[256];
+ static char path[PATH_MAX];
- if (is_primary_interface(ifname)) {
- if (access(IFACE_DIR, F_OK) == 0) {
- snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
- } else {
- strlcpy(path, primary_iface, sizeof(path));
- }
- return wifi_connect_on_socket_path(PRIMARY, path);
+ if (access(IFACE_DIR, F_OK) == 0) {
+ snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
} else {
- sprintf(path, "%s/%s", CONTROL_IFACE_PATH, ifname);
- return wifi_connect_on_socket_path(SECONDARY, path);
+ snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
}
+ return wifi_connect_on_socket_path(path);
}
-int wifi_send_command(int index, const char *cmd, char *reply, size_t *reply_len)
+int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
{
int ret;
-
- if (ctrl_conn[index] == NULL) {
+ if (ctrl_conn == NULL) {
ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
- ret = wpa_ctrl_request(ctrl_conn[index], cmd, strlen(cmd), reply, reply_len, NULL);
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
ALOGD("'%s' command timed out.\n", cmd);
/* unblocks the monitor receive socket for termination */
- TEMP_FAILURE_RETRY(write(exit_sockets[index][0], "T", 1));
+ TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
@@ -718,16 +683,16 @@ int wifi_send_command(int index, const char *cmd, char *reply, size_t *reply_len
return 0;
}
-int wifi_ctrl_recv(int index, char *reply, size_t *reply_len)
+int wifi_ctrl_recv(char *reply, size_t *reply_len)
{
int res;
- int ctrlfd = wpa_ctrl_get_fd(monitor_conn[index]);
+ int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
struct pollfd rfds[2];
memset(rfds, 0, 2 * sizeof(struct pollfd));
rfds[0].fd = ctrlfd;
rfds[0].events |= POLLIN;
- rfds[1].fd = exit_sockets[index][1];
+ rfds[1].fd = exit_sockets[1];
rfds[1].events |= POLLIN;
res = TEMP_FAILURE_RETRY(poll(rfds, 2, -1));
if (res < 0) {
@@ -735,128 +700,117 @@ int wifi_ctrl_recv(int index, char *reply, size_t *reply_len)
return res;
}
if (rfds[0].revents & POLLIN) {
- return wpa_ctrl_recv(monitor_conn[index], reply, reply_len);
- } else if (rfds[1].revents & POLLIN) {
- /* Close only the p2p sockets on receive side
- * see wifi_close_supplicant_connection()
- */
- if (index == SECONDARY) {
- ALOGD("close sockets %d", index);
- wifi_close_sockets(index);
- }
+ return wpa_ctrl_recv(monitor_conn, reply, reply_len);
}
+
+ /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
+ * or we timed out. In either case, this call has failed ..
+ */
return -2;
}
-int wifi_wait_on_socket(int index, char *buf, size_t buflen)
+int wifi_wait_on_socket(char *buf, size_t buflen)
{
size_t nread = buflen - 1;
- int fd;
- fd_set rfds;
int result;
- struct timeval tval;
- struct timeval *tptr;
+ char *match, *match2;
- if (monitor_conn[index] == NULL) {
- ALOGD("Connection closed\n");
- strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
- buf[buflen-1] = '\0';
- return strlen(buf);
+ if (monitor_conn == NULL) {
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed");
}
- result = wifi_ctrl_recv(index, buf, &nread);
+ result = wifi_ctrl_recv(buf, &nread);
/* Terminate reception on exit socket */
if (result == -2) {
- strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
- buf[buflen-1] = '\0';
- return strlen(buf);
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed");
}
if (result < 0) {
ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
- strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
- buf[buflen-1] = '\0';
- return strlen(buf);
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - recv error");
}
buf[nread] = '\0';
/* Check for EOF on the socket */
if (result == 0 && nread == 0) {
/* Fabricate an event to pass up */
ALOGD("Received EOF on supplicant socket\n");
- strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
- buf[buflen-1] = '\0';
- return strlen(buf);
+ return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - signal 0 received");
}
/*
* Events strings are in the format
*
+ * IFNAME=iface <N>CTRL-EVENT-XXX
+ * or
* <N>CTRL-EVENT-XXX
*
* where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
* etc.) and XXX is the event name. The level information is not useful
* to us, so strip it off.
*/
- if (buf[0] == '<') {
- char *match = strchr(buf, '>');
+
+ if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
+ match = strchr(buf, ' ');
+ if (match != NULL) {
+ if (match[1] == '<') {
+ match2 = strchr(match + 2, '>');
+ if (match2 != NULL) {
+ nread -= (match2 - match);
+ memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
+ }
+ }
+ } else {
+ return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
+ }
+ } else if (buf[0] == '<') {
+ match = strchr(buf, '>');
if (match != NULL) {
- nread -= (match+1-buf);
- memmove(buf, match+1, nread+1);
+ nread -= (match + 1 - buf);
+ memmove(buf, match + 1, nread + 1);
+ ALOGV("supplicant generated event without interface - %s\n", buf);
}
+ } else {
+ /* let the event go as is! */
+ ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
}
return nread;
}
-int wifi_wait_for_event(const char *ifname, char *buf, size_t buflen)
+int wifi_wait_for_event(char *buf, size_t buflen)
{
- if (is_primary_interface(ifname)) {
- return wifi_wait_on_socket(PRIMARY, buf, buflen);
- } else {
- return wifi_wait_on_socket(SECONDARY, buf, buflen);
- }
+ return wifi_wait_on_socket(buf, buflen);
}
-void wifi_close_sockets(int index)
+void wifi_close_sockets()
{
- if (ctrl_conn[index] != NULL) {
- wpa_ctrl_close(ctrl_conn[index]);
- ctrl_conn[index] = NULL;
+ if (ctrl_conn != NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
}
- if (monitor_conn[index] != NULL) {
- wpa_ctrl_close(monitor_conn[index]);
- monitor_conn[index] = NULL;
+ if (monitor_conn != NULL) {
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
}
- if (exit_sockets[index][0] >= 0) {
- close(exit_sockets[index][0]);
- exit_sockets[index][0] = -1;
+ if (exit_sockets[0] >= 0) {
+ close(exit_sockets[0]);
+ exit_sockets[0] = -1;
}
- if (exit_sockets[index][1] >= 0) {
- close(exit_sockets[index][1]);
- exit_sockets[index][1] = -1;
+ if (exit_sockets[1] >= 0) {
+ close(exit_sockets[1]);
+ exit_sockets[1] = -1;
}
}
-void wifi_close_supplicant_connection(const char *ifname)
+void wifi_close_supplicant_connection()
{
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
- if (is_primary_interface(ifname)) {
- wifi_close_sockets(PRIMARY);
- } else {
- /* p2p socket termination needs unblocking the monitor socket
- * STA connection does not need it since supplicant gets shutdown
- */
- TEMP_FAILURE_RETRY(write(exit_sockets[SECONDARY][0], "T", 1));
- /* p2p sockets are closed after the monitor thread
- * receives the terminate on the exit socket
- */
- return;
- }
+ wifi_close_sockets();
while (count-- > 0) {
if (property_get(supplicant_prop_name, supp_status, NULL)) {
@@ -867,13 +821,9 @@ void wifi_close_supplicant_connection(const char *ifname)
}
}
-int wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len)
+int wifi_command(const char *command, char *reply, size_t *reply_len)
{
- if (is_primary_interface(ifname)) {
- return wifi_send_command(PRIMARY, command, reply, reply_len);
- } else {
- return wifi_send_command(SECONDARY, command, reply, reply_len);
- }
+ return wifi_send_command(command, reply, reply_len);
}
const char *wifi_get_fw_path(int fw_type)