diff options
-rw-r--r-- | audio/AudioHardwareGeneric.h | 2 | ||||
-rw-r--r-- | audio/AudioHardwareStub.cpp | 4 | ||||
-rw-r--r-- | audio/AudioHardwareStub.h | 2 | ||||
-rw-r--r-- | audio/AudioPolicyCompatClient.cpp | 5 | ||||
-rw-r--r-- | audio/AudioPolicyCompatClient.h | 3 | ||||
-rw-r--r-- | audio/AudioPolicyManagerBase.cpp | 441 | ||||
-rw-r--r-- | audio/audio_policy.conf | 20 | ||||
-rw-r--r-- | audio/audio_policy_hal.cpp | 14 | ||||
-rw-r--r-- | include/hardware_legacy/AudioPolicyInterface.h | 10 | ||||
-rw-r--r-- | include/hardware_legacy/AudioPolicyManagerBase.h | 27 | ||||
-rw-r--r-- | include/hardware_legacy/driver_nl80211.h | 202 | ||||
-rw-r--r-- | include/hardware_legacy/wifi.h | 17 | ||||
-rw-r--r-- | wifi/Android.mk | 3 | ||||
-rw-r--r-- | wifi/wifi.c | 264 |
14 files changed, 694 insertions, 320 deletions
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 bf3f36a..dbca8ff 100644 --- a/audio/AudioPolicyManagerBase.cpp +++ b/audio/AudioPolicyManagerBase.cpp @@ -37,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 { @@ -161,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]); } } @@ -309,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 @@ -479,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, @@ -491,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; @@ -508,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) { @@ -537,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); @@ -550,11 +575,29 @@ 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); + //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); + } + if (profile != NULL) { AudioOutputDescriptor *outputDesc = NULL; @@ -567,7 +610,7 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str (format == outputDesc->mFormat) && (channelMask == outputDesc->mChannelMask)) { outputDesc->mDirectOpenCount++; - ALOGV("getOutput() reusing direct output %d", output); + ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i)); return mOutputs.keyAt(i); } } @@ -582,7 +625,7 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str 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; @@ -592,7 +635,8 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str &outputDesc->mFormat, &outputDesc->mChannelMask, &outputDesc->mLatency, - outputDesc->mFlags); + outputDesc->mFlags, + offloadInfo); // only accept an output with the requested parameters if (output == 0 || @@ -609,7 +653,12 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str delete outputDesc; return 0; } + audio_io_handle_t srcOutput = getOutputForEffect(); addOutput(output, outputDesc); + 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; @@ -619,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); - - output = selectOutput(outputs, flags); + // 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); - 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); @@ -787,7 +838,7 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, if (curOutput != output && desc->isActive() && outputDesc->sharesHwModuleWith(desc) && - newDevice != desc->device()) { + (newDevice != desc->device())) { setOutputDevice(curOutput, getNewDevice(curOutput, false /*fromCache*/), true, @@ -836,11 +887,17 @@ void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output) } 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, @@ -934,10 +991,19 @@ 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; + } } } @@ -945,10 +1011,20 @@ status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) 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()); @@ -971,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()); @@ -1068,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, @@ -1190,6 +1310,20 @@ 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(); @@ -1219,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; } } @@ -1228,7 +1364,6 @@ bool AudioPolicyManagerBase::isSourceActive(audio_source_t source) const } - status_t AudioPolicyManagerBase::dump(int fd) { const size_t SIZE = 256; @@ -1316,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 // ---------------------------------------------------------------------------- @@ -1359,11 +1561,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); @@ -1665,13 +1870,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; @@ -1907,26 +2118,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; } } } @@ -2492,6 +2697,7 @@ audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource) 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) { @@ -2669,8 +2875,10 @@ const AudioPolicyManagerBase::VolumeCurvePoint }; // 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} @@ -3002,17 +3210,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; @@ -3155,7 +3352,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); @@ -3323,57 +3520,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) @@ -3393,7 +3587,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" : ", "); } @@ -3401,14 +3595,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()); @@ -3455,6 +3649,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[] = { @@ -3507,6 +3703,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; } 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 1604809..0e03358 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, @@ -321,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, @@ -368,6 +377,7 @@ static int create_legacy_ap(const struct audio_policy_device *device, 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; diff --git a/include/hardware_legacy/AudioPolicyInterface.h b/include/hardware_legacy/AudioPolicyInterface.h index d2dd430..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, @@ -162,6 +165,8 @@ public: //dump state virtual status_t dump(int fd) = 0; + + virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0; }; @@ -192,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 7ba71e7..5fea77a 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, @@ -141,6 +146,8 @@ public: virtual status_t dump(int fd); + virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo); + protected: enum routing_strategy { @@ -247,6 +254,7 @@ protected: 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(); @@ -440,16 +448,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 @@ -490,6 +488,11 @@ 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) // 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..cde99d7 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 diff --git a/wifi/wifi.c b/wifi/wifi.c index 01d1d23..ff9357b 100644 --- a/wifi/wifi.c +++ b/wifi/wifi.c @@ -37,21 +37,11 @@ #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]; +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[MAX_CONNS][2]; +static int exit_sockets[2]; extern int do_dhcp(); extern int ifc_init(); @@ -60,7 +50,7 @@ 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(int index); +void wifi_close_sockets(); static char primary_iface[PROPERTY_VALUE_MAX]; // TODO: use new ANDROID_SOCKET mechanism, once support for multiple @@ -109,6 +99,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, @@ -120,16 +114,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; @@ -381,7 +365,7 @@ 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=")) { + if ((sptr = strstr(pbuf, "ctrl_interface="))) { ret = 0; if ((!strstr(pbuf, "ctrl_interface=DIR=")) && (!strstr(pbuf, "ctrl_interface=/"))) { @@ -484,45 +468,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'}; @@ -564,12 +509,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 /* @@ -647,7 +590,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'}; @@ -658,29 +601,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; } @@ -688,36 +631,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; @@ -728,16 +665,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) { @@ -745,124 +682,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 result; + 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)) { @@ -873,13 +803,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) |