Project import
diff --git a/libhardware_legacy/Android.mk b/libhardware_legacy/Android.mk
new file mode 100644
index 0000000..b0254f5
--- /dev/null
+++ b/libhardware_legacy/Android.mk
@@ -0,0 +1,54 @@
+# Copyright 2006 The Android Open Source Project
+
+# Setting LOCAL_PATH will mess up all-subdir-makefiles, so do it beforehand.
+legacy_modules := power uevent wifi
+
+SAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules))
+LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := libcutils liblog libmedia
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS += -DQEMU_HARDWARE -Wno-unused-parameter -Wno-gnu-designator
+QEMU_HARDWARE := true
+
+LOCAL_SHARED_LIBRARIES += libdl
+
+include $(SAVE_MAKEFILES)
+
+LOCAL_MODULE:= libhardware_legacy
+
+include $(BUILD_SHARED_LIBRARY)
+
+# static library for librpc
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libpower
+
+LOCAL_SRC_FILES += power/power.c
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+include $(BUILD_STATIC_LIBRARY)
+
+# shared library for various HALs
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libpower
+
+LOCAL_SRC_FILES := power/power.c
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_SHARED_LIBRARY)
+
+# legacy_audio builds it's own set of libraries that aren't linked into
+# hardware_legacy
+include $(LEGACY_AUDIO_MAKEFILES)
diff --git a/libhardware_legacy/CleanSpec.mk b/libhardware_legacy/CleanSpec.mk
new file mode 100644
index 0000000..56193a9
--- /dev/null
+++ b/libhardware_legacy/CleanSpec.mk
@@ -0,0 +1,51 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhardware_legacy_intermediates/)
\ No newline at end of file
diff --git a/libhardware_legacy/MODULE_LICENSE_APACHE2 b/libhardware_legacy/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libhardware_legacy/MODULE_LICENSE_APACHE2
diff --git a/libhardware_legacy/NOTICE b/libhardware_legacy/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libhardware_legacy/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/libhardware_legacy/audio/A2dpAudioInterface.cpp b/libhardware_legacy/audio/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..50708ba
--- /dev/null
+++ b/libhardware_legacy/audio/A2dpAudioInterface.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+#include <hardware_legacy/power.h>
+
+
+namespace android_audio_legacy {
+
+static const char *sA2dpWakeLock = "A2dpOutputStream";
+#define MAX_WRITE_RETRIES 5
+
+// ----------------------------------------------------------------------------
+
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+// AudioHardwareInterface* hw = 0;
+//
+// hw = AudioHardwareInterface::create();
+// ALOGD("new A2dpAudioInterface(hw: %p)", hw);
+// hw = new A2dpAudioInterface(hw);
+// return hw;
+//}
+
+A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
+ mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true), mSuspended(false)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+ closeOutputStream((AudioStreamOut *)mOutput);
+ delete mHardwareInterface;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+ if (mHardwareInterface == 0) return NO_INIT;
+ return mHardwareInterface->initCheck();
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ if (!audio_is_a2dp_out_device(devices)) {
+ ALOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
+ return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ }
+
+ status_t err = 0;
+
+ // only one output stream allowed
+ if (mOutput) {
+ if (status)
+ *status = -1;
+ return NULL;
+ }
+
+ // create new output stream
+ A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+ if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
+ mOutput = out;
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
+ mOutput->setSuspended(mSuspended);
+ } else {
+ delete out;
+ }
+
+ if (status)
+ *status = err;
+ return mOutput;
+}
+
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput == 0 || mOutput != out) {
+ mHardwareInterface->closeOutputStream(out);
+ }
+ else {
+ delete mOutput;
+ mOutput = 0;
+ }
+}
+
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+}
+
+void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
+{
+ return mHardwareInterface->closeInputStream(in);
+}
+
+status_t A2dpAudioInterface::setMode(int mode)
+{
+ return mHardwareInterface->setMode(mode);
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+ return mHardwareInterface->setMicMute(state);
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+ return mHardwareInterface->getMicMute(state);
+}
+
+status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ status_t status = NO_ERROR;
+
+ ALOGV("setParameters() %s", keyValuePairs.string());
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ mBluetoothEnabled = (value == "true");
+ if (mOutput) {
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
+ }
+ param.remove(key);
+ }
+ key = String8("A2dpSuspended");
+ if (param.get(key, value) == NO_ERROR) {
+ mSuspended = (value == "true");
+ if (mOutput) {
+ mOutput->setSuspended(mSuspended);
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status_t hwStatus = mHardwareInterface->setParameters(param.toString());
+ if (status == NO_ERROR) {
+ status = hwStatus;
+ }
+ }
+
+ return status;
+}
+
+String8 A2dpAudioInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter a2dpParam = AudioParameter();
+ String8 value;
+ String8 key;
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mBluetoothEnabled ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
+ }
+ key = "A2dpSuspended";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mSuspended ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
+ }
+
+ String8 keyValuePairs = a2dpParam.toString();
+
+ if (param.size()) {
+ if (keyValuePairs != "") {
+ keyValuePairs += ";";
+ }
+ keyValuePairs += mHardwareInterface->getParameters(param.toString());
+ }
+
+ ALOGV("getParameters() %s", keyValuePairs.string());
+ return keyValuePairs;
+}
+
+size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+ return mHardwareInterface->setVoiceVolume(v);
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+ return mHardwareInterface->setMasterVolume(v);
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+ return mHardwareInterface->dumpState(fd, args);
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+ mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
+ // assume BT enabled to start, this is safe because its only the
+ // enabled->disabled transition we are worried about
+ mBluetoothEnabled(true), mDevice(0), mClosing(false), mSuspended(false)
+{
+ // use any address by default
+ strcpy(mA2dpAddress, "00:00:00:00:00:00");
+ init();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+ uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ ALOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
+
+ // fix up defaults
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
+
+ // check values
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())){
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+ return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mDevice = device;
+ mBufferDurationUs = ((bufferSize() * 1000 )/ frameSize() / sampleRate()) * 1000;
+ return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+ ALOGV("A2dpAudioStreamOut destructor");
+ close();
+ ALOGV("A2dpAudioStreamOut destructor returning from close()");
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{
+ status_t status = -1;
+ {
+ Mutex::Autolock lock(mLock);
+
+ size_t remaining = bytes;
+
+ if (!mBluetoothEnabled || mClosing || mSuspended) {
+ ALOGV("A2dpAudioStreamOut::write(), but bluetooth disabled \
+ mBluetoothEnabled %d, mClosing %d, mSuspended %d",
+ mBluetoothEnabled, mClosing, mSuspended);
+ goto Error;
+ }
+
+ if (mStandby) {
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, sA2dpWakeLock);
+ mStandby = false;
+ mLastWriteTime = systemTime();
+ }
+
+ status = init();
+ if (status < 0)
+ goto Error;
+
+ int retries = MAX_WRITE_RETRIES;
+ while (remaining > 0 && retries) {
+ status = a2dp_write(mData, buffer, remaining);
+ if (status < 0) {
+ ALOGE("a2dp_write failed err: %d\n", status);
+ goto Error;
+ }
+ if (status == 0) {
+ retries--;
+ }
+ remaining -= status;
+ buffer = (char *)buffer + status;
+ }
+
+ // if A2DP sink runs abnormally fast, sleep a little so that audioflinger mixer thread
+ // does no spin and starve other threads.
+ // NOTE: It is likely that the A2DP headset is being disconnected
+ nsecs_t now = systemTime();
+ if ((uint32_t)ns2us(now - mLastWriteTime) < (mBufferDurationUs >> 2)) {
+ ALOGV("A2DP sink runs too fast");
+ usleep(mBufferDurationUs - (uint32_t)ns2us(now - mLastWriteTime));
+ }
+ mLastWriteTime = now;
+ return bytes;
+
+ }
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep(mBufferDurationUs);
+
+ return status;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+ if (!mData) {
+ status_t status = a2dp_init(44100, 2, &mData);
+ if (status < 0) {
+ ALOGE("a2dp_init failed err: %d\n", status);
+ mData = NULL;
+ return status;
+ }
+ a2dp_set_sink(mData, mA2dpAddress);
+ }
+
+ return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+ Mutex::Autolock lock(mLock);
+ return standby_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby_l()
+{
+ int result = NO_ERROR;
+
+ if (!mStandby) {
+ ALOGV_IF(mClosing || !mBluetoothEnabled, "Standby skip stop: closing %d enabled %d",
+ mClosing, mBluetoothEnabled);
+ if (!mClosing && mBluetoothEnabled) {
+ result = a2dp_stop(mData);
+ }
+ release_wake_lock(sA2dpWakeLock);
+ mStandby = true;
+ }
+
+ return result;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
+
+ if (param.get(key, value) == NO_ERROR) {
+ if (value.length() != strlen("00:00:00:00:00:00")) {
+ status = BAD_VALUE;
+ } else {
+ setAddress(value.string());
+ }
+ param.remove(key);
+ }
+ key = String8("closing");
+ if (param.get(key, value) == NO_ERROR) {
+ mClosing = (value == "true");
+ if (mClosing) {
+ standby();
+ }
+ param.remove(key);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if (audio_is_a2dp_out_device(device)) {
+ mDevice = device;
+ status = NO_ERROR;
+ } else {
+ status = BAD_VALUE;
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+
+ if (param.get(key, value) == NO_ERROR) {
+ value = mA2dpAddress;
+ param.add(key, value);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ ALOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
+{
+ Mutex::Autolock lock(mLock);
+
+ if (strlen(address) != strlen("00:00:00:00:00:00"))
+ return -EINVAL;
+
+ strcpy(mA2dpAddress, address);
+ if (mData)
+ a2dp_set_sink(mData, mA2dpAddress);
+
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enabled)
+{
+ ALOGD("setBluetoothEnabled %d", enabled);
+
+ Mutex::Autolock lock(mLock);
+
+ mBluetoothEnabled = enabled;
+ if (!enabled) {
+ return close_l();
+ }
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setSuspended(bool onOff)
+{
+ ALOGV("setSuspended %d", onOff);
+ mSuspended = onOff;
+ standby();
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+ Mutex::Autolock lock(mLock);
+ ALOGV("A2dpAudioStreamOut::close() calling close_l()");
+ return close_l();
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
+{
+ standby_l();
+ if (mData) {
+ ALOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
+ a2dp_cleanup(mData);
+ mData = NULL;
+ }
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::getRenderPosition(uint32_t *driverFrames)
+{
+ //TODO: enable when supported by driver
+ return INVALID_OPERATION;
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/A2dpAudioInterface.h b/libhardware_legacy/audio/A2dpAudioInterface.h
new file mode 100644
index 0000000..8fe9745
--- /dev/null
+++ b/libhardware_legacy/audio/A2dpAudioInterface.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+
+namespace android_audio_legacy {
+ using android::Mutex;
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+ class A2dpAudioStreamOut;
+
+public:
+ A2dpAudioInterface(AudioHardwareInterface* hw);
+ virtual ~A2dpAudioInterface();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+// static AudioHardwareInterface* createA2dpInterface();
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ class A2dpAudioStreamOut : public AudioStreamOut {
+ public:
+ A2dpAudioStreamOut();
+ virtual ~A2dpAudioStreamOut();
+ status_t set(uint32_t device,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ // SBC codec wants a multiple of 512
+ virtual size_t bufferSize() const { return 512 * 20; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ friend class A2dpAudioInterface;
+ status_t init();
+ status_t close();
+ status_t close_l();
+ status_t setAddress(const char* address);
+ status_t setBluetoothEnabled(bool enabled);
+ status_t setSuspended(bool onOff);
+ status_t standby_l();
+
+ private:
+ int mFd;
+ bool mStandby;
+ int mStartCount;
+ int mRetryCount;
+ char mA2dpAddress[20];
+ void* mData;
+ Mutex mLock;
+ bool mBluetoothEnabled;
+ uint32_t mDevice;
+ bool mClosing;
+ bool mSuspended;
+ nsecs_t mLastWriteTime;
+ uint32_t mBufferDurationUs;
+ };
+
+ friend class A2dpAudioStreamOut;
+
+ A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
+ bool mSuspended;
+};
+
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libhardware_legacy/audio/Android.mk b/libhardware_legacy/audio/Android.mk
new file mode 100644
index 0000000..d9d2d6a
--- /dev/null
+++ b/libhardware_legacy/audio/Android.mk
@@ -0,0 +1,89 @@
+# Copyright 2011 The Android Open Source Project
+
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioHardwareInterface.cpp \
+ audio_hw_hal.cpp
+
+LOCAL_MODULE := libaudiohw_legacy
+LOCAL_SHARED_LIBRARIES := libmedia
+LOCAL_STATIC_LIBRARIES := libmedia_helper
+LOCAL_CFLAGS := -Wno-unused-parameter -Wno-gnu-designator
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManagerBase.cpp \
+ AudioPolicyCompatClient.cpp \
+ audio_policy_hal.cpp
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+LOCAL_SHARED_LIBRARIES := libmedia
+LOCAL_STATIC_LIBRARIES := libmedia_helper
+LOCAL_MODULE := libaudiopolicy_legacy
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../include
+
+include $(BUILD_STATIC_LIBRARY)
+
+# The default audio policy, for now still implemented on top of legacy
+# policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManagerDefault.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libmedia \
+ libutils \
+ liblog
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.default
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
+
+include $(BUILD_SHARED_LIBRARY)
+
+#ifeq ($(ENABLE_AUDIO_DUMP),true)
+# LOCAL_SRC_FILES += AudioDumpInterface.cpp
+# LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
+#endif
+#
+#ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+# LOCAL_CFLAGS += -D GENERIC_AUDIO
+#endif
+
+#ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+# LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+# LOCAL_SHARED_LIBRARIES += liba2dp
+# LOCAL_C_INCLUDES += $(call include-path-for, bluez)
+#
+# LOCAL_CFLAGS += \
+# -DWITH_BLUETOOTH \
+#endif
+#
+#include $(BUILD_SHARED_LIBRARY)
+
+# AudioHardwareGeneric.cpp \
+# AudioHardwareStub.cpp \
diff --git a/libhardware_legacy/audio/AudioDumpInterface.cpp b/libhardware_legacy/audio/AudioDumpInterface.cpp
new file mode 100644
index 0000000..62fdbd6
--- /dev/null
+++ b/libhardware_legacy/audio/AudioDumpInterface.cpp
@@ -0,0 +1,573 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "AudioFlingerDump"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+ : mPolicyCommands(String8("")), mFileName(String8(""))
+{
+ if(hw == 0) {
+ ALOGE("Dump construct hw = 0");
+ }
+ mFinalInterface = hw;
+ ALOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
+}
+
+
+AudioDumpInterface::~AudioDumpInterface()
+{
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ closeOutputStream((AudioStreamOut *)mOutputs[i]);
+ }
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ closeInputStream((AudioStreamIn *)mInputs[i]);
+ }
+
+ if(mFinalInterface) delete mFinalInterface;
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AudioStreamOut* outFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ uint32_t lRate = 44100;
+
+
+ outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ if (outFinal != 0) {
+ lFormat = outFinal->format();
+ lChannels = outFinal->channels();
+ lRate = outFinal->sampleRate();
+ } else {
+ if (format != 0) {
+ if (*format != 0) {
+ lFormat = *format;
+ } else {
+ *format = lFormat;
+ }
+ }
+ if (channels != 0) {
+ if (*channels != 0) {
+ lChannels = *channels;
+ } else {
+ *channels = lChannels;
+ }
+ }
+ if (sampleRate != 0) {
+ if (*sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ *sampleRate = lRate;
+ }
+ }
+ if (status) *status = NO_ERROR;
+ }
+ ALOGV("openOutputStream(), outFinal %p", outFinal);
+
+ AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal,
+ devices, lFormat, lChannels, lRate);
+ mOutputs.add(dumOutput);
+
+ return dumOutput;
+}
+
+void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)
+{
+ AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out;
+
+ if (mOutputs.indexOf(dumpOut) < 0) {
+ ALOGW("Attempt to close invalid output stream");
+ return;
+ }
+
+ ALOGV("closeOutputStream() output %p", out);
+
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ }
+
+ mOutputs.remove(dumpOut);
+ delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+ AudioStreamIn* inFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+ uint32_t lRate = 8000;
+
+ inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ if (inFinal != 0) {
+ lFormat = inFinal->format();
+ lChannels = inFinal->channels();
+ lRate = inFinal->sampleRate();
+ } else {
+ if (format != 0) {
+ if (*format != 0) {
+ lFormat = *format;
+ } else {
+ *format = lFormat;
+ }
+ }
+ if (channels != 0) {
+ if (*channels != 0) {
+ lChannels = *channels;
+ } else {
+ *channels = lChannels;
+ }
+ }
+ if (sampleRate != 0) {
+ if (*sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ *sampleRate = lRate;
+ }
+ }
+ if (status) *status = NO_ERROR;
+ }
+ ALOGV("openInputStream(), inFinal %p", inFinal);
+
+ AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal,
+ devices, lFormat, lChannels, lRate);
+ mInputs.add(dumInput);
+
+ return dumInput;
+}
+void AudioDumpInterface::closeInputStream(AudioStreamIn* in)
+{
+ AudioStreamInDump *dumpIn = (AudioStreamInDump *)in;
+
+ if (mInputs.indexOf(dumpIn) < 0) {
+ ALOGW("Attempt to close invalid input stream");
+ return;
+ }
+ dumpIn->standby();
+ if (dumpIn->finalStream() != NULL) {
+ mFinalInterface->closeInputStream(dumpIn->finalStream());
+ }
+
+ mInputs.remove(dumpIn);
+ delete dumpIn;
+}
+
+
+status_t AudioDumpInterface::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ ALOGV("setParameters %s", keyValuePairs.string());
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ mFileName = value;
+ param.remove(String8("test_cmd_file_name"));
+ }
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ param.remove(String8("test_cmd_policy"));
+ mPolicyCommands = param.toString();
+ ALOGV("test_cmd_policy command %s written", mPolicyCommands.string());
+ return NO_ERROR;
+ }
+
+ if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioDumpInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter response;
+ String8 value;
+
+// ALOGV("getParameters %s", keys.string());
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ if (mPolicyCommands.length() != 0) {
+ response = AudioParameter(mPolicyCommands);
+ response.addInt(String8("test_cmd_policy"), 1);
+ } else {
+ response.addInt(String8("test_cmd_policy"), 0);
+ }
+ param.remove(String8("test_cmd_policy"));
+// ALOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ }
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ response.add(String8("test_cmd_file_name"), mFileName);
+ param.remove(String8("test_cmd_file_name"));
+ }
+
+ String8 keyValuePairs = response.toString();
+
+ if (param.size() && mFinalInterface != 0 ) {
+ keyValuePairs += ";";
+ keyValuePairs += mFinalInterface->getParameters(param.toString());
+ }
+
+ return keyValuePairs;
+}
+
+status_t AudioDumpInterface::setMode(int mode)
+{
+ return mFinalInterface->setMode(mode);
+}
+
+size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+ ALOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+ ALOGV("AudioStreamOutDump destructor");
+ Close();
+}
+
+ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
+{
+ ssize_t ret;
+
+ if (mFinalStream) {
+ ret = mFinalStream->write(buffer, bytes);
+ } else {
+ usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+ ret = bytes;
+ }
+ if(!mFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_out_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mFile = fopen(name, "wb");
+ ALOGV("Opening dump file %s, fh %p", name, mFile);
+ }
+ }
+ if (mFile) {
+ fwrite(buffer, bytes, 1, mFile);
+ }
+ return ret;
+}
+
+status_t AudioStreamOutDump::standby()
+{
+ ALOGV("AudioStreamOutDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamOutDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->latency();
+ return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+ return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+ ALOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+ if (mFinalStream != 0 ) {
+ return mFinalStream->setParameters(keyValuePairs);
+ }
+
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ status_t status = NO_ERROR;
+
+ if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+ mId = valueInt;
+ }
+
+ if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+ if (mFile == 0) {
+ mFormat = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ }
+ if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+ if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+ mChannels = valueInt;
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+ if (valueInt > 0 && valueInt <= 48000) {
+ if (mFile == 0) {
+ mSampleRate = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ return status;
+}
+
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
+{
+ if(mFile) {
+ fclose(mFile);
+ mFile = 0;
+ }
+}
+
+status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames);
+ return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mFile(0), mFileCount(0)
+{
+ ALOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+ Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+ ssize_t ret;
+
+ if (mFinalStream) {
+ ret = mFinalStream->read(buffer, bytes);
+ if(!mFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_in_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mFile = fopen(name, "wb");
+ ALOGV("Opening input dump file %s, fh %p", name, mFile);
+ }
+ }
+ if (mFile) {
+ fwrite(buffer, bytes, 1, mFile);
+ }
+ } else {
+ usleep((((bytes * 1000) / frameSize()) / sampleRate()) * 1000);
+ ret = bytes;
+ if(!mFile) {
+ char name[255];
+ strcpy(name, "/sdcard/music/sine440");
+ if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+ strcat(name, "_mo");
+ } else {
+ strcat(name, "_st");
+ }
+ if (format() == AudioSystem::PCM_16_BIT) {
+ strcat(name, "_16b");
+ } else {
+ strcat(name, "_8b");
+ }
+ if (sampleRate() < 16000) {
+ strcat(name, "_8k");
+ } else if (sampleRate() < 32000) {
+ strcat(name, "_22k");
+ } else if (sampleRate() < 48000) {
+ strcat(name, "_44k");
+ } else {
+ strcat(name, "_48k");
+ }
+ strcat(name, ".wav");
+ mFile = fopen(name, "rb");
+ ALOGV("Opening input read file %s, fh %p", name, mFile);
+ if (mFile) {
+ fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ }
+ }
+ if (mFile) {
+ ssize_t bytesRead = fread(buffer, bytes, 1, mFile);
+ if (bytesRead >=0 && bytesRead < bytes) {
+ fseek(mFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mFile);
+ }
+ }
+ }
+
+ return ret;
+}
+
+status_t AudioStreamInDump::standby()
+{
+ ALOGV("AudioStreamInDump standby(), mFile %p, mFinalStream %p", mFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+ ALOGV("AudioStreamInDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+unsigned int AudioStreamInDump::getInputFramesLost() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost();
+ return 0;
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+ if(mFile) {
+ fclose(mFile);
+ mFile = 0;
+ }
+}
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioDumpInterface.h b/libhardware_legacy/audio/AudioDumpInterface.h
new file mode 100644
index 0000000..814ce5f
--- /dev/null
+++ b/libhardware_legacy/audio/AudioDumpInterface.h
@@ -0,0 +1,170 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android {
+
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+ AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamOutDump();
+
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+ virtual uint32_t latency() const;
+ virtual status_t setVolume(float left, float right);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamOut* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+ int getId() { return mId; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamOut *mFinalStream;
+ FILE *mFile; // output file
+ int mFileCount;
+};
+
+class AudioStreamInDump : public AudioStreamIn {
+public:
+ AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamInDump();
+
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+
+ virtual status_t setGain(float gain);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const;
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamIn* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamIn *mFinalStream;
+ FILE *mFile; // output file
+ int mFileCount;
+};
+
+class AudioDumpInterface : public AudioHardwareBase
+{
+
+public:
+ AudioDumpInterface(AudioHardwareInterface* hw);
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
+ virtual ~AudioDumpInterface();
+
+ virtual status_t initCheck()
+ {return mFinalInterface->initCheck();}
+ virtual status_t setVoiceVolume(float volume)
+ {return mFinalInterface->setVoiceVolume(volume);}
+ virtual status_t setMasterVolume(float volume)
+ {return mFinalInterface->setMasterVolume(volume);}
+
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state)
+ {return mFinalInterface->setMicMute(state);}
+ virtual status_t getMicMute(bool* state)
+ {return mFinalInterface->getMicMute(state);}
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+ String8 fileName() const { return mFileName; }
+protected:
+
+ AudioHardwareInterface *mFinalInterface;
+ SortedVector<AudioStreamOutDump *> mOutputs;
+ SortedVector<AudioStreamInDump *> mInputs;
+ Mutex mLock;
+ String8 mPolicyCommands;
+ String8 mFileName;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libhardware_legacy/audio/AudioHardwareGeneric.cpp b/libhardware_legacy/audio/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..a2b00f8
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareGeneric.cpp
@@ -0,0 +1,413 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+#include <media/AudioRecord.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+ : mOutput(0), mInput(0), mFd(-1), mMicMute(false)
+{
+ mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+ if (mFd >= 0) ::close(mFd);
+ closeOutputStream((AudioStreamOut *)mOutput);
+ closeInputStream((AudioStreamIn *)mInput);
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+ if (mFd >= 0) {
+ if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AutoMutex lock(mLock);
+
+ // only one output stream allowed
+ if (mOutput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return 0;
+ }
+
+ // create new output stream
+ AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+ status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
+ mOutput = out;
+ } else {
+ delete out;
+ }
+ return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput && out == mOutput) {
+ delete mOutput;
+ mOutput = 0;
+ }
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+ // check for valid input source
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+ return 0;
+ }
+
+ AutoMutex lock(mLock);
+
+ // only one input stream allowed
+ if (mInput) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return 0;
+ }
+
+ // create new output stream
+ AudioStreamInGeneric* in = new AudioStreamInGeneric();
+ status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR) {
+ mInput = in;
+ } else {
+ delete in;
+ }
+ return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
+ if (mInput && in == mInput) {
+ delete mInput;
+ mInput = 0;
+ }
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+ // Implement: set voice volume
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+ // Implement: set master volume
+ // return error - software mixer will handle it
+ return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+ mMicMute = state;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareGeneric::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n", mFd, mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ if (mInput) {
+ mInput->dump(fd, args);
+ }
+ if (mOutput) {
+ mOutput->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate)
+{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ // fix up defaults
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
+
+ // check values
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+ return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+
+ mAudioHardware = hw;
+ mFd = fd;
+ mDevice = devices;
+ return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+ Mutex::Autolock _l(mLock);
+ return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::standby()
+{
+ // Implement: audio hardware to standby mode
+ return NO_ERROR;
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamOutGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ ALOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioStreamOutGeneric::getRenderPosition(uint32_t *dspFrames)
+{
+ return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+ AudioHardwareGeneric *hw,
+ int fd,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
+ ALOGV("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
+ // check values
+ if ((*pFormat != format()) ||
+ (*pChannels != channels()) ||
+ (*pRate != sampleRate())) {
+ ALOGE("Error opening input channel");
+ *pFormat = format();
+ *pChannels = channels();
+ *pRate = sampleRate();
+ return BAD_VALUE;
+ }
+
+ mAudioHardware = hw;
+ mFd = fd;
+ mDevice = devices;
+ return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+ AutoMutex lock(mLock);
+ if (mFd < 0) {
+ ALOGE("Attempt to read from unopened device");
+ return NO_INIT;
+ }
+ return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ ALOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamInGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ ALOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareGeneric.h b/libhardware_legacy/audio/AudioHardwareGeneric.h
new file mode 100644
index 0000000..55498dc
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareGeneric.h
@@ -0,0 +1,156 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android_audio_legacy {
+ using android::Mutex;
+ using android::AutoMutex;
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+ AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamOutGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return 20; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+private:
+ AudioHardwareGeneric *mAudioHardware;
+ Mutex mLock;
+ int mFd;
+ uint32_t mDevice;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+ AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+ virtual ~AudioStreamInGeneric();
+
+ virtual status_t set(
+ AudioHardwareGeneric *hw,
+ int mFd,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby() { return NO_ERROR; }
+ 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;
+ Mutex mLock;
+ int mFd;
+ uint32_t mDevice;
+};
+
+
+class AudioHardwareGeneric : public AudioHardwareBase
+{
+public:
+ AudioHardwareGeneric();
+ virtual ~AudioHardwareGeneric();
+ virtual status_t initCheck();
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ void closeOutputStream(AudioStreamOutGeneric* out);
+ void closeInputStream(AudioStreamInGeneric* in);
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ Mutex mLock;
+ AudioStreamOutGeneric *mOutput;
+ AudioStreamInGeneric *mInput;
+ int mFd;
+ bool mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libhardware_legacy/audio/AudioHardwareInterface.cpp b/libhardware_legacy/audio/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..dbf6f33
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareInterface.cpp
@@ -0,0 +1,164 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+#ifdef ENABLE_AUDIO_DUMP
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 1
+
+namespace android_audio_legacy {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+ "OUT OF RANGE",
+ "INVALID",
+ "CURRENT",
+ "NORMAL",
+ "RINGTONE",
+ "IN_CALL",
+ "IN_COMMUNICATION"
+};
+
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+ if ((mode < AudioSystem::MODE_INVALID) || (mode >= AudioSystem::NUM_MODES))
+ return routingModeStrings[0];
+ return routingModeStrings[mode+3];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+ return NULL;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+// default implementation is unsupported
+status_t AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp)
+{
+ return INVALID_OPERATION;
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareBase::AudioHardwareBase()
+{
+ mMode = 0;
+}
+
+status_t AudioHardwareBase::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+ ALOGD("setMode(%s)", displayMode(mode));
+#endif
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+ return BAD_VALUE;
+ if (mMode == mode)
+ return ALREADY_EXISTS;
+ mMode = mode;
+ return NO_ERROR;
+}
+
+// default implementation
+status_t AudioHardwareBase::setParameters(const String8& keyValuePairs)
+{
+ return NO_ERROR;
+}
+
+// default implementation
+String8 AudioHardwareBase::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (sampleRate != 8000) {
+ ALOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+ return 0;
+ }
+ if (format != AudioSystem::PCM_16_BIT) {
+ ALOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount != 1) {
+ ALOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+
+ return 320;
+}
+
+// default implementation is unsupported
+status_t AudioHardwareBase::getMasterVolume(float *volume)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ dump(fd, args); // Dump the state of the concrete child.
+ return NO_ERROR;
+}
+
+// default implementation calls its "without flags" counterpart
+AudioStreamOut* AudioHardwareInterface::openOutputStreamWithFlags(uint32_t devices,
+ audio_output_flags_t flags,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status)
+{
+ return openOutputStream(devices, format, channels, sampleRate, status);
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareStub.cpp b/libhardware_legacy/audio/AudioHardwareStub.cpp
new file mode 100644
index 0000000..fd647d5
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareStub.cpp
@@ -0,0 +1,215 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include <media/AudioRecord.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+ return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AudioStreamOutStub* out = new AudioStreamOutStub();
+ status_t lStatus = out->set(format, channels, sampleRate);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR)
+ return out;
+ delete out;
+ return 0;
+}
+
+void AudioHardwareStub::closeOutputStream(AudioStreamOut* out)
+{
+ delete out;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
+{
+ // check for valid input source
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+ return 0;
+ }
+
+ AudioStreamInStub* in = new AudioStreamInStub();
+ status_t lStatus = in->set(format, channels, sampleRate, acoustics);
+ if (status) {
+ *status = lStatus;
+ }
+ if (lStatus == NO_ERROR)
+ return in;
+ delete in;
+ return 0;
+}
+
+void AudioHardwareStub::closeInputStream(AudioStreamIn* in)
+{
+ delete in;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append("AudioHardwareStub::dumpInternals\n");
+ snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate)
+{
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
+
+ return NO_ERROR;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+ // fake timing for audio output
+ usleep(bytes * 1000000 / sizeof(int16_t) /
+ audio_channel_count_from_out_mask(channels()) / sampleRate());
+ return bytes;
+}
+
+status_t AudioStreamOutStub::standby()
+{
+ return NO_ERROR;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamOutStub::getRenderPosition(uint32_t *dspFrames)
+{
+ return INVALID_OPERATION;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ return NO_ERROR;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+ // fake timing for audio input
+ usleep(bytes * 1000000 / sizeof(int16_t) /
+ audio_channel_count_from_in_mask(channels()) / sampleRate());
+ memset(buffer, 0, bytes);
+ return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tformat: %d\n", format());
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardwareStub();
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioHardwareStub.h b/libhardware_legacy/audio/AudioHardwareStub.h
new file mode 100644
index 0000000..c5f7a80
--- /dev/null
+++ b/libhardware_legacy/audio/AudioHardwareStub.h
@@ -0,0 +1,108 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ virtual size_t bufferSize() const { return 4096; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return 0; }
+ virtual status_t setVolume(float left, float right) { return NO_ERROR; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics);
+ virtual uint32_t sampleRate() const { return 8000; }
+ virtual size_t bufferSize() const { return 320; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual status_t setGain(float gain) { return NO_ERROR; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby() { return NO_ERROR; }
+ 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
+{
+public:
+ AudioHardwareStub();
+ virtual ~AudioHardwareStub();
+ virtual status_t initCheck();
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ // mic mute
+ virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
+ virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ bool mMicMute;
+private:
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libhardware_legacy/audio/AudioPolicyCompatClient.cpp b/libhardware_legacy/audio/AudioPolicyCompatClient.cpp
new file mode 100644
index 0000000..9d02d98
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyCompatClient.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyCompatClient"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+audio_module_handle_t AudioPolicyCompatClient::loadHwModule(const char *moduleName)
+{
+ return mServiceOps->load_hw_module(mService, moduleName);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ 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, offloadInfo);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openDuplicateOutput(audio_io_handle_t output1,
+ audio_io_handle_t output2)
+{
+ return mServiceOps->open_duplicate_output(mService, output1, output2);
+}
+
+status_t AudioPolicyCompatClient::closeOutput(audio_io_handle_t output)
+{
+ return mServiceOps->close_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::suspendOutput(audio_io_handle_t output)
+{
+ return mServiceOps->suspend_output(mService, output);
+}
+
+status_t AudioPolicyCompatClient::restoreOutput(audio_io_handle_t output)
+{
+ return mServiceOps->restore_output(mService, output);
+}
+
+audio_io_handle_t AudioPolicyCompatClient::openInput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask)
+{
+ return mServiceOps->open_input_on_module(mService, module, pDevices,
+ pSamplingRate, pFormat, pChannelMask);
+}
+
+status_t AudioPolicyCompatClient::closeInput(audio_io_handle_t input)
+{
+ return mServiceOps->close_input(mService, input);
+}
+
+status_t AudioPolicyCompatClient::invalidateStream(AudioSystem::stream_type stream)
+{
+ return mServiceOps->invalidate_stream(mService, (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::moveEffects(int session, audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
+{
+ return mServiceOps->move_effects(mService, session, srcOutput, dstOutput);
+}
+
+String8 AudioPolicyCompatClient::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+ char *str;
+ String8 out_str8;
+
+ str = mServiceOps->get_parameters(mService, ioHandle, keys.string());
+ out_str8 = String8(str);
+ free(str);
+
+ return out_str8;
+}
+
+void AudioPolicyCompatClient::setParameters(audio_io_handle_t ioHandle,
+ const String8& keyValuePairs,
+ int delayMs)
+{
+ mServiceOps->set_parameters(mService, ioHandle, keyValuePairs.string(),
+ delayMs);
+}
+
+status_t AudioPolicyCompatClient::setStreamVolume(
+ AudioSystem::stream_type stream,
+ float volume,
+ audio_io_handle_t output,
+ int delayMs)
+{
+ return mServiceOps->set_stream_volume(mService, (audio_stream_type_t)stream,
+ volume, output, delayMs);
+}
+
+status_t AudioPolicyCompatClient::startTone(ToneGenerator::tone_type tone,
+ AudioSystem::stream_type stream)
+{
+ return mServiceOps->start_tone(mService,
+ AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION,
+ (audio_stream_type_t)stream);
+}
+
+status_t AudioPolicyCompatClient::stopTone()
+{
+ return mServiceOps->stop_tone(mService);
+}
+
+status_t AudioPolicyCompatClient::setVoiceVolume(float volume, int delayMs)
+{
+ return mServiceOps->set_voice_volume(mService, volume, delayMs);
+}
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/audio/AudioPolicyCompatClient.h b/libhardware_legacy/audio/AudioPolicyCompatClient.h
new file mode 100644
index 0000000..19f76e1
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyCompatClient.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYCLIENTLEGACY_H
+#define ANDROID_AUDIOPOLICYCLIENTLEGACY_H
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+/************************************/
+/* FOR BACKWARDS COMPATIBILITY ONLY */
+/************************************/
+namespace android_audio_legacy {
+
+class AudioPolicyCompatClient : public AudioPolicyClientInterface {
+public:
+ AudioPolicyCompatClient(struct audio_policy_service_ops *serviceOps,
+ void *service) :
+ mServiceOps(serviceOps) , mService(service) {}
+
+ virtual audio_module_handle_t loadHwModule(const char *moduleName);
+
+ virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ 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);
+ virtual status_t suspendOutput(audio_io_handle_t output);
+ virtual status_t restoreOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t openInput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask);
+ virtual status_t closeInput(audio_io_handle_t input);
+ virtual status_t invalidateStream(AudioSystem::stream_type stream);
+ virtual status_t moveEffects(int session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput);
+
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+ virtual void setParameters(audio_io_handle_t ioHandle,
+ const String8& keyValuePairs,
+ int delayMs = 0);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream,
+ float volume,
+ audio_io_handle_t output,
+ int delayMs = 0);
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
+ virtual status_t stopTone();
+ virtual status_t setVoiceVolume(float volume, int delayMs = 0);
+
+private:
+ struct audio_policy_service_ops* mServiceOps;
+ void* mService;
+};
+
+}; // namespace android_audio_legacy
+
+#endif // ANDROID_AUDIOPOLICYCLIENTLEGACY_H
diff --git a/libhardware_legacy/audio/AudioPolicyManagerBase.cpp b/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
new file mode 100644
index 0000000..60790b7
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerBase.cpp
@@ -0,0 +1,4368 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyManagerBase"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// 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 <inttypes.h>
+#include <math.h>
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerBase::setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ // device_address can be NULL and should be handled as an empty string in this case,
+ // and it is not checked by AudioPolicyInterfaceImpl.cpp
+ if (device_address == NULL) {
+ device_address = "";
+ }
+ ALOGV("setDeviceConnectionState() device: 0x%X, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (audio_is_output_device(device)) {
+ SortedVector <audio_io_handle_t> outputs;
+
+ if (!mHasA2dp && audio_is_a2dp_out_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasUsb && audio_is_usb_out_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+ return BAD_VALUE;
+ }
+
+ // save a copy of the opened output descriptors before any output is opened or closed
+ // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+ mPreviousOutputs = mOutputs;
+ String8 paramStr;
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device connection
+ paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ }
+
+ if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+ outputs.size());
+ // register new device as available
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device connection
+ mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device connection
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device connection
+ mUsbOutCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ }
+
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableOutputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+ checkOutputsForDevice(device, state, outputs, paramStr);
+
+ if (mHasA2dp && audio_is_a2dp_out_device(device)) {
+ // handle A2DP device disconnection
+ mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device disconnection
+ mScoDeviceAddress = "";
+ } else if (mHasUsb && audio_is_usb_out_device(device)) {
+ // handle USB device disconnection
+ mUsbOutCardAndDevice = "";
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ // 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) ||
+ (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+ (desc->mDirectOpenCount == 0))) {
+ closeOutput(outputs[i]);
+ }
+ }
+ }
+
+ updateDevicesAndOutputs();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ // do not force device change on duplicated output because if device is 0, it will
+ // also force a device 0 for the two outputs it is duplicated to which may override
+ // a valid device selection on those outputs.
+ setOutputDevice(mOutputs.keyAt(i),
+ getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ !mOutputs.valueAt(i)->isDuplicated(),
+ 0);
+ }
+
+ return NO_ERROR;
+ } // end if is output device
+
+ // handle input devices
+ if (audio_is_input_device(device)) {
+ SortedVector <audio_io_handle_t> inputs;
+
+ String8 paramStr;
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+
+ if (mHasUsb && audio_is_usb_in_device(device)) {
+ // handle USB device connection
+ paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasA2dp && audio_is_a2dp_in_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SOURCE_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ }
+
+ if (checkInputsForDevice(device, state, inputs, paramStr) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ checkInputsForDevice(device, state, inputs, paramStr);
+ mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ closeAllInputs();
+
+ return NO_ERROR;
+ } // end if is input device
+
+ ALOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerBase::getDeviceConnectionState(audio_devices_t device,
+ const char *device_address)
+{
+ // similar to setDeviceConnectionState
+ if (device_address == NULL) {
+ device_address = "";
+ }
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (audio_is_output_device(device)) {
+ if (device & mAvailableOutputDevices) {
+ if (audio_is_a2dp_out_device(device) &&
+ (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
+ return state;
+ }
+ if (audio_is_bluetooth_sco_device(device) &&
+ address != "" && mScoDeviceAddress != address) {
+ return state;
+ }
+ if (audio_is_usb_out_device(device) &&
+ (!mHasUsb || (address != "" && mUsbOutCardAndDevice != address))) {
+ ALOGE("getDeviceConnectionState() invalid device: %x", device);
+ return state;
+ }
+ if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+ return state;
+ }
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (audio_is_input_device(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+void AudioPolicyManagerBase::setPhoneState(int state)
+{
+ ALOGV("setPhoneState() state %d", state);
+ audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ ALOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ ALOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+
+ // if leaving call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isInCall()) {
+ ALOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, false, true);
+ }
+ }
+
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+ bool force = false;
+
+ // are we entering or starting a call
+ if (!isStateInCall(oldState) && isStateInCall(state)) {
+ ALOGV(" Entering call in setPhoneState()");
+ // 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
+ // even if no device change is needed
+ force = true;
+ }
+
+ // check for device and output changes triggered by new phone state
+ newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+
+ AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+ // force routing command to audio hardware when ending call
+ // even if no device change is needed
+ if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+ newDevice = hwOutputDesc->device();
+ }
+
+ int delayMs = 0;
+ if (isStateInCall(state)) {
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ // 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;
+ }
+ 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*/));
+ }
+ }
+
+ // change routing is necessary
+ setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+ // if entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isStateInCall(state)) {
+ ALOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, true, true);
+ }
+ }
+
+ // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+ if (state == AudioSystem::MODE_RINGTONE &&
+ isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+ mLimitRingtoneVolume = true;
+ } else {
+ mLimitRingtoneVolume = false;
+ }
+}
+
+void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+ bool forceVolumeReeval = false;
+ switch(usage) {
+ case AudioSystem::FOR_COMMUNICATION:
+ if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_MEDIA:
+ if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_NO_BT_A2DP) {
+ ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_RECORD:
+ if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_DOCK:
+ if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_SYSTEM:
+ if (config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new force usage
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t output = mOutputs.keyAt(i);
+ audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+ if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+ applyStreamVolumes(output, newDevice, 0, true);
+ }
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setForceUse() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+}
+
+AudioSystem::forced_config AudioPolicyManagerBase::getForceUse(AudioSystem::force_use usage)
+{
+ return mForceUse[usage];
+}
+
+void AudioPolicyManagerBase::setSystemProperty(const char* property, const char* value)
+{
+ 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,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags)
+{
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
+ 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];
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ 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() 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) {
+ ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+ if (mTestOutputs[mCurOutput] == 0) {
+ ALOGV("getOutput() opening test output");
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+ outputDesc->mDevice = mTestDevice;
+ outputDesc->mSamplingRate = mTestSamplingRate;
+ outputDesc->mFormat = mTestFormat;
+ outputDesc->mChannelMask = mTestChannels;
+ outputDesc->mLatency = mTestLatencyMs;
+ outputDesc->mFlags = (audio_output_flags_t)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+ outputDesc->mRefCount[stream] = 0;
+ mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags,
+ offloadInfo);
+ if (mTestOutputs[mCurOutput]) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"),mCurOutput);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+ addOutput(mTestOutputs[mCurOutput], outputDesc);
+ }
+ }
+ return mTestOutputs[mCurOutput];
+ }
+#endif //AUDIO_POLICY_TEST
+
+ // open a direct output if required by specified parameters
+ //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;
+
+ 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 = format;
+ outputDesc->mChannelMask = channelMask;
+ outputDesc->mLatency = 0;
+ 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,
+ offloadInfo);
+
+ // only accept an output with the requested parameters
+ if (output == 0 ||
+ (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+ (format != AUDIO_FORMAT_DEFAULT && format != outputDesc->mFormat) ||
+ (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+ ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+ "format %d %d, channelMask %04x %04x", output, samplingRate,
+ outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
+ outputDesc->mChannelMask);
+ if (output != 0) {
+ mpClientInterface->closeOutput(output);
+ }
+ 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;
+ }
+
+ // ignoring channel mask due to downmix capability in mixer
+
+ // open a non direct output
+
+ // for non direct outputs, only PCM is supported
+ if (audio_is_linear_pcm(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,"
+ "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+
+ ALOGV("getOutput() returns output %d", output);
+
+ return output;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+ AudioSystem::output_flags flags)
+{
+ // select one output among several that provide a path to a particular device or set of
+ // devices (the list was previously build by getOutputsForDevice()).
+ // The priority is as follows:
+ // 1: the output with the highest number of requested policy flags
+ // 2: the primary output
+ // 3: the first output in the list
+
+ if (outputs.size() == 0) {
+ return 0;
+ }
+ if (outputs.size() == 1) {
+ return outputs[0];
+ }
+
+ int maxCommonFlags = 0;
+ audio_io_handle_t outputFlags = 0;
+ audio_io_handle_t outputPrimary = 0;
+
+ for (size_t i = 0; i < outputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+ if (!outputDesc->isDuplicated()) {
+ int commonFlags = (int)AudioSystem::popCount(outputDesc->mProfile->mFlags & flags);
+ if (commonFlags > maxCommonFlags) {
+ outputFlags = outputs[i];
+ maxCommonFlags = commonFlags;
+ ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
+ }
+ if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ outputPrimary = outputs[i];
+ }
+ }
+ }
+
+ if (outputFlags != 0) {
+ return outputFlags;
+ }
+ if (outputPrimary != 0) {
+ return outputPrimary;
+ }
+
+ return outputs[0];
+}
+
+status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("startOutput() unknown output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // increment usage count for this stream on the requested output:
+ // NOTE that the usage count is the same for duplicated output and hardware output which is
+ // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+ outputDesc->changeRefCount(stream, 1);
+
+ if (outputDesc->mRefCount[stream] == 1) {
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ routing_strategy strategy = getStrategy(stream);
+ bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+ uint32_t waitMs = 0;
+ bool force = false;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (desc != outputDesc) {
+ // force a device change if any other output is managed by the same hw
+ // module and has a current device selection that differs from selected device.
+ // In this case, the audio HAL must receive the new device selection so that it can
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
+ desc->device() != newDevice) {
+ force = true;
+ }
+ // wait for audio on other active outputs to be presented when starting
+ // a notification so that audio focus effect can propagate.
+ uint32_t latency = desc->latency();
+ if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+ waitMs = latency;
+ }
+ }
+ }
+ uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, true, false);
+ }
+
+ // apply volume rules for current stream and device if necessary
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex(newDevice),
+ output,
+ newDevice);
+
+ // update the outputs if starting an output with a stream that can affect notification
+ // routing
+ handleNotificationRoutingForStream(stream);
+ if (waitMs > muteWaitMs) {
+ usleep((waitMs - muteWaitMs) * 2 * 1000);
+ }
+ }
+ return NO_ERROR;
+}
+
+
+status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("stopOutput() unknown output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, false, false);
+ }
+
+ if (outputDesc->mRefCount[stream] > 0) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ // store time at which the stream was stopped - see isStreamActive()
+ if (outputDesc->mRefCount[stream] == 0) {
+ outputDesc->mStopTime[stream] = systemTime();
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ // delay the device switch by twice the latency because stopOutput() is executed when
+ // the track stop() command is received and at that time the audio track buffer can
+ // still contain data that needs to be drained. The latency only covers the audio HAL
+ // and kernel buffers. Also the latency does not always include additional delay in the
+ // audio path (audio DSP, CODEC ...)
+ setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+ // force restoring the device selection on other active outputs if it differs from the
+ // one being selected for this output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t curOutput = mOutputs.keyAt(i);
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (curOutput != output &&
+ desc->isActive() &&
+ outputDesc->sharesHwModuleWith(desc) &&
+ (newDevice != desc->device())) {
+ setOutputDevice(curOutput,
+ getNewDevice(curOutput, false /*fromCache*/),
+ true,
+ outputDesc->mLatency*2);
+ }
+ }
+ // update the outputs if stopping one with a stream that can affect notification routing
+ handleNotificationRoutingForStream(stream);
+ }
+ return NO_ERROR;
+ } else {
+ ALOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
+{
+ ALOGV("releaseOutput() %d", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("releaseOutput() releasing unknown output %d", output);
+ return;
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ int testIndex = testOutputIndex(output);
+ if (testIndex != 0) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ if (outputDesc->isActive()) {
+ mpClientInterface->closeOutput(output);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mTestOutputs[testIndex] = 0;
+ }
+ return;
+ }
+#endif //AUDIO_POLICY_TEST
+
+ 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,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ audio_devices_t device = getDeviceForInputSource(inputSource);
+
+ ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+ inputSource, samplingRate, format, channelMask, acoustics);
+
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGW("getInput() could not find device for inputSource %d", inputSource);
+ return 0;
+ }
+
+ // adapt channel selection to input source
+ switch(inputSource) {
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ case AUDIO_SOURCE_VOICE_CALL:
+ channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+ break;
+ default:
+ break;
+ }
+
+ IOProfile *profile = getInputProfile(device,
+ samplingRate,
+ format,
+ channelMask);
+ if (profile == NULL) {
+ ALOGW("getInput() could not find profile for device 0x%X, samplingRate %d, format %d, "
+ "channelMask 0x%X",
+ device, samplingRate, format, channelMask);
+ return 0;
+ }
+
+ if (profile->mModule->mHandle == 0) {
+ ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+ return 0;
+ }
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+ inputDesc->mInputSource = inputSource;
+ inputDesc->mDevice = device;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = format;
+ inputDesc->mChannelMask = channelMask;
+ inputDesc->mRefCount = 0;
+
+ input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannelMask);
+
+ // only accept input with the exact requested set of parameters
+ if (input == 0 ||
+ (samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channelMask != inputDesc->mChannelMask)) {
+ ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask 0x%X",
+ samplingRate, format, channelMask);
+ if (input != 0) {
+ mpClientInterface->closeInput(input);
+ }
+ delete inputDesc;
+ return 0;
+ }
+ addInput(input, inputDesc);
+
+ return input;
+}
+
+status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)
+{
+ ALOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("startInput() unknown input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+ {
+ // 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);
+
+ 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());
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)
+{
+ ALOGV("stopInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("stopInput() unknown input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ 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());
+ inputDesc->mRefCount = 0;
+ return NO_ERROR;
+ }
+}
+
+void AudioPolicyManagerBase::releaseInput(audio_io_handle_t input)
+{
+ ALOGV("releaseInput() %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("releaseInput() releasing unknown input %d", input);
+ return;
+ }
+ mpClientInterface->closeInput(input);
+ delete mInputs.valueAt(index);
+ mInputs.removeItem(input);
+
+ ALOGV("releaseInput() exit");
+}
+
+void AudioPolicyManagerBase::closeAllInputs() {
+ for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ mpClientInterface->closeInput(mInputs.keyAt(input_index));
+ }
+ mInputs.clear();
+}
+
+void AudioPolicyManagerBase::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ if (indexMin < 0 || indexMin >= indexMax) {
+ ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax);
+ return;
+ }
+ mStreams[stream].mIndexMin = indexMin;
+ mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream,
+ int index,
+ audio_devices_t device)
+{
+
+ if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ return BAD_VALUE;
+ }
+ if (!audio_is_output_device(device)) {
+ return BAD_VALUE;
+ }
+
+ // Force max volume if stream cannot be muted
+ if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+ ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+ stream, device, index);
+
+ // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
+ // clear all device specific values
+ if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+ mStreams[stream].mIndexCur.clear();
+ }
+ mStreams[stream].mIndexCur.add(device, index);
+
+ // compute and apply stream volume on all outputs according to connected device
+ status_t status = NO_ERROR;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_devices_t curDevice =
+ getDeviceForVolume(mOutputs.valueAt(i)->device());
+ if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+ status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
+ if (volStatus != NO_ERROR) {
+ status = volStatus;
+ }
+ }
+ }
+ return status;
+}
+
+status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type stream,
+ int *index,
+ audio_devices_t device)
+{
+ if (index == NULL) {
+ return BAD_VALUE;
+ }
+ if (!audio_is_output_device(device)) {
+ return BAD_VALUE;
+ }
+ // if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to
+ // the strategy the stream belongs to.
+ if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+ device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+ }
+ device = getDeviceForVolume(device);
+
+ *index = mStreams[stream].getVolumeIndex(device);
+ ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
+ 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[%zu] 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)
+{
+ // 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);
+
+ 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,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ ssize_t index = mOutputs.indexOfKey(io);
+ if (index < 0) {
+ index = mInputs.indexOfKey(io);
+ if (index < 0) {
+ ALOGW("registerEffect() unknown io %d", io);
+ return INVALID_OPERATION;
+ }
+ }
+
+ if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+ ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+ desc->name, desc->memoryUsage);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsMemory += desc->memoryUsage;
+ ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
+ desc->name, io, strategy, session, id);
+ ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
+
+ EffectDescriptor *pDesc = new EffectDescriptor();
+ memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
+ pDesc->mIo = io;
+ pDesc->mStrategy = (routing_strategy)strategy;
+ pDesc->mSession = session;
+ pDesc->mEnabled = false;
+
+ mEffects.add(id, pDesc);
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::unregisterEffect(int id)
+{
+ ssize_t index = mEffects.indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ EffectDescriptor *pDesc = mEffects.valueAt(index);
+
+ setEffectEnabled(pDesc, false);
+
+ if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+ ALOGW("unregisterEffect() memory %d too big for total %d",
+ pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+ pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+ }
+ mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+ ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
+ pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+
+ mEffects.removeItem(id);
+ delete pDesc;
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(int id, bool enabled)
+{
+ ssize_t index = mEffects.indexOfKey(id);
+ if (index < 0) {
+ ALOGW("unregisterEffect() unknown effect ID %d", id);
+ return INVALID_OPERATION;
+ }
+
+ return setEffectEnabled(mEffects.valueAt(index), enabled);
+}
+
+status_t AudioPolicyManagerBase::setEffectEnabled(EffectDescriptor *pDesc, bool enabled)
+{
+ if (enabled == pDesc->mEnabled) {
+ ALOGV("setEffectEnabled(%s) effect already %s",
+ enabled?"true":"false", enabled?"enabled":"disabled");
+ return INVALID_OPERATION;
+ }
+
+ if (enabled) {
+ if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+ ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+ pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10);
+ return INVALID_OPERATION;
+ }
+ mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
+ } else {
+ if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+ ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
+ pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+ pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+ }
+ mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+ ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
+ }
+ pDesc->mEnabled = enabled;
+ 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++) {
+ 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;
+ }
+ }
+ return false;
+}
+
+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 ||
+ (source == (audio_source_t)AUDIO_SOURCE_VOICE_RECOGNITION &&
+ inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
+ && (inputDescriptor->mRefCount > 0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+status_t AudioPolicyManagerBase::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbOutCardAndDevice.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for communications %d\n", mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AudioSystem::FOR_MEDIA]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AudioSystem::FOR_RECORD]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AudioSystem::FOR_DOCK]);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AudioSystem::FOR_SYSTEM]);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+
+ snprintf(buffer, SIZE, "\nHW Modules dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
+ write(fd, buffer, strlen(buffer));
+ mHwModules[i]->dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mOutputs.valueAt(i)->dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nInputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mInputs.valueAt(i)->dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nStreams dump:\n");
+ write(fd, buffer, strlen(buffer));
+ snprintf(buffer, SIZE,
+ " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ snprintf(buffer, SIZE, " %02zu ", i);
+ write(fd, buffer, strlen(buffer));
+ mStreams[i].dump(fd);
+ }
+
+ snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
+ (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
+ write(fd, buffer, strlen(buffer));
+
+ snprintf(buffer, SIZE, "Registered effects:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ mEffects.valueAt(i)->dump(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=%" PRId64 " 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
+// ----------------------------------------------------------------------------
+
+AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
+ :
+#ifdef AUDIO_POLICY_TEST
+ Thread(false),
+#endif //AUDIO_POLICY_TEST
+ mPrimaryOutput((audio_io_handle_t)0),
+ mAvailableOutputDevices(AUDIO_DEVICE_NONE),
+ mPhoneState(AudioSystem::MODE_NORMAL),
+ mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
+ mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
+ mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+ mSpeakerDrcEnabled(false)
+{
+ mpClientInterface = clientInterface;
+
+ for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+ mForceUse[i] = AudioSystem::FORCE_NONE;
+ }
+
+ mA2dpDeviceAddress = String8("");
+ mScoDeviceAddress = String8("");
+ mUsbOutCardAndDevice = String8("");
+
+ if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
+ if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
+ ALOGE("could not load audio policy configuration file, setting defaults");
+ defaultAudioPolicyConfig();
+ }
+ }
+
+ // 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);
+ if (mHwModules[i]->mHandle == 0) {
+ ALOGW("could not open HW module %s", mHwModules[i]->mName);
+ 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) &&
+ ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
+ outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &
+ outProfile->mSupportedDevices);
+ audio_io_handle_t output = mpClientInterface->openOutput(
+ outProfile->mModule->mHandle,
+ &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (output == 0) {
+ delete outputDesc;
+ } else {
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices |
+ (outProfile->mSupportedDevices & mAttachedOutputDevices));
+ if (mPrimaryOutput == 0 &&
+ outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ mPrimaryOutput = output;
+ }
+ addOutput(output, outputDesc);
+ setOutputDevice(output,
+ (audio_devices_t)(mDefaultOutputDevice &
+ outProfile->mSupportedDevices),
+ true);
+ }
+ }
+ }
+ }
+
+ ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices),
+ "Not output found for attached devices %08x",
+ (mAttachedOutputDevices & ~mAvailableOutputDevices));
+
+ ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
+
+ updateDevicesAndOutputs();
+
+#ifdef AUDIO_POLICY_TEST
+ if (mPrimaryOutput != 0) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+
+ mTestDevice = AUDIO_DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ mTestLatencyMs = 0;
+ mCurOutput = 0;
+ mDirectOutput = false;
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ mTestOutputs[i] = 0;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+ }
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerBase::~AudioPolicyManagerBase()
+{
+#ifdef AUDIO_POLICY_TEST
+ exit();
+#endif //AUDIO_POLICY_TEST
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ mpClientInterface->closeOutput(mOutputs.keyAt(i));
+ delete mOutputs.valueAt(i);
+ }
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mpClientInterface->closeInput(mInputs.keyAt(i));
+ delete mInputs.valueAt(i);
+ }
+ for (size_t i = 0; i < mHwModules.size(); i++) {
+ delete mHwModules[i];
+ }
+}
+
+status_t AudioPolicyManagerBase::initCheck()
+{
+ return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerBase::threadLoop()
+{
+ ALOGV("entering threadLoop()");
+ while (!exitPending())
+ {
+ String8 command;
+ int valueInt;
+ String8 value;
+
+ Mutex::Autolock _l(mLock);
+ mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+ command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+ AudioParameter param = AudioParameter(command);
+
+ if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+ valueInt != 0) {
+ ALOGV("Test command %s received", command.string());
+ String8 target;
+ if (param.get(String8("target"), target) != NO_ERROR) {
+ target = "Manager";
+ }
+ if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_output"));
+ mCurOutput = valueInt;
+ }
+ if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_direct"));
+ if (value == "false") {
+ mDirectOutput = false;
+ } else if (value == "true") {
+ mDirectOutput = true;
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_input"));
+ mTestInput = valueInt;
+ }
+
+ if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_format"));
+ int format = AudioSystem::INVALID_FORMAT;
+ if (value == "PCM 16 bits") {
+ format = AudioSystem::PCM_16_BIT;
+ } else if (value == "PCM 8 bits") {
+ format = AudioSystem::PCM_8_BIT;
+ } else if (value == "Compressed MP3") {
+ format = AudioSystem::MP3;
+ }
+ if (format != AudioSystem::INVALID_FORMAT) {
+ if (target == "Manager") {
+ mTestFormat = format;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("format"), format);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_channels"));
+ int channels = 0;
+
+ if (value == "Channels Stereo") {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
+ } else if (value == "Channels Mono") {
+ channels = AudioSystem::CHANNEL_OUT_MONO;
+ }
+ if (channels != 0) {
+ if (target == "Manager") {
+ mTestChannels = channels;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("channels"), channels);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_sampleRate"));
+ if (valueInt >= 0 && valueInt <= 96000) {
+ int samplingRate = valueInt;
+ if (target == "Manager") {
+ mTestSamplingRate = samplingRate;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("sampling_rate"), samplingRate);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+
+ if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_reopen"));
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+ mpClientInterface->closeOutput(mPrimaryOutput);
+
+ audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
+
+ delete mOutputs.valueFor(mPrimaryOutput);
+ mOutputs.removeItem(mPrimaryOutput);
+
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+ outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
+ mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
+ &outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannelMask,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mPrimaryOutput == 0) {
+ ALOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask);
+ } else {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+ addOutput(mPrimaryOutput, outputDesc);
+ }
+ }
+
+
+ mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+ }
+ }
+ return false;
+}
+
+void AudioPolicyManagerBase::exit()
+{
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+int AudioPolicyManagerBase::testOutputIndex(audio_io_handle_t output)
+{
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ if (output == mTestOutputs[i]) return i;
+ }
+ return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+void AudioPolicyManagerBase::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+{
+ outputDesc->mId = id;
+ mOutputs.add(id, outputDesc);
+}
+
+void AudioPolicyManagerBase::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc)
+{
+ inputDesc->mId = id;
+ mInputs.add(id, inputDesc);
+}
+
+status_t AudioPolicyManagerBase::checkOutputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 paramStr)
+{
+ AudioOutputDescriptor *desc;
+
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ // first list already open outputs that can be routed to this device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // then look for output profiles that can be routed to this device
+ SortedVector<IOProfile *> profiles;
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+ {
+ if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
+ ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
+ profiles.add(mHwModules[i]->mOutputProfiles[j]);
+ }
+ }
+ }
+
+ if (profiles.isEmpty() && outputs.isEmpty()) {
+ ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+ return BAD_VALUE;
+ }
+
+ // open outputs for matching profiles if needed. Direct outputs are also opened to
+ // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+ for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+ IOProfile *profile = profiles[profile_index];
+
+ // nothing to do if one output is already opened for this profile
+ size_t j;
+ for (j = 0; j < mOutputs.size(); j++) {
+ desc = mOutputs.valueAt(j);
+ if (!desc->isDuplicated() && desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (j != mOutputs.size()) {
+ continue;
+ }
+
+ ALOGV("opening output for device %08x with params %s", device, paramStr.string());
+ 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,
+ &offloadInfo);
+ if (output != 0) {
+ if (!paramStr.isEmpty()) {
+ // Here is where the out_set_parameters() for card & device gets called
+ mpClientInterface->setParameters(output, paramStr);
+ }
+
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
+ }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkOutputsForDevice() direct output sup formats %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
+ }
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(output,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadOutChannels(value + 1, profile);
+ }
+ }
+ if (((profile->mSamplingRates[0] == 0) &&
+ (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) &&
+ (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) &&
+ (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkOutputsForDevice() direct output missing param");
+ mpClientInterface->closeOutput(output);
+ output = 0;
+ } else if (profile->mSamplingRates[0] == 0) {
+ mpClientInterface->closeOutput(output);
+ desc->mSamplingRate = profile->mSamplingRates[1];
+ offloadInfo.sample_rate = desc->mSamplingRate;
+ output = mpClientInterface->openOutput(
+ profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask,
+ &desc->mLatency,
+ desc->mFlags,
+ &offloadInfo);
+ }
+
+ if (output != 0) {
+ addOutput(output, desc);
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
+ audio_io_handle_t duplicatedOutput = 0;
+
+ // set initial stream volume for device
+ applyStreamVolumes(output, device, 0, true);
+
+ //TODO: configure audio effect output stage here
+
+ // open a duplicating output thread for the new output and the primary output
+ duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+ mPrimaryOutput);
+ if (duplicatedOutput != 0) {
+ // add duplicated output descriptor
+ AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+ dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+ dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+ dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+ dupOutputDesc->mFormat = desc->mFormat;
+ dupOutputDesc->mChannelMask = desc->mChannelMask;
+ dupOutputDesc->mLatency = desc->mLatency;
+ addOutput(duplicatedOutput, dupOutputDesc);
+ applyStreamVolumes(duplicatedOutput, device, 0, true);
+ } else {
+ ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+ mPrimaryOutput, output);
+ mpClientInterface->closeOutput(output);
+ mOutputs.removeItem(output);
+ output = 0;
+ }
+ }
+ }
+ }
+ if (output == 0) {
+ ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+ delete desc;
+ profiles.removeAt(profile_index);
+ profile_index--;
+ } else {
+ outputs.add(output);
+ ALOGV("checkOutputsForDevice(): adding output %d", output);
+ }
+ }
+
+ if (profiles.isEmpty()) {
+ ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+ return BAD_VALUE;
+ }
+ } else { // Disconnect
+ // check if one opened output is not needed any more after disconnecting one device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() &&
+ !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) {
+ ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // Clear any profiles associated with the disconnected device.
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+ {
+ IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkOutputsForDevice(): clearing direct output profile %zu on module %zu",
+ j, i);
+ if (profile->mSamplingRates[0] == 0) {
+ profile->mSamplingRates.clear();
+ profile->mSamplingRates.add(0);
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.clear();
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ profile->mChannelMasks.clear();
+ profile->mChannelMasks.add(0);
+ }
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerBase::checkInputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 paramStr)
+{
+ AudioInputDescriptor *desc;
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ // first list already open inputs that can be routed to this device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile->mSupportedDevices & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+
+ // then look for input profiles that can be routed to this device
+ SortedVector<IOProfile *> profiles;
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ if (mHwModules[module_index]->mInputProfiles[profile_index]->mSupportedDevices
+ & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
+ profile_index, module_index);
+ profiles.add(mHwModules[module_index]->mInputProfiles[profile_index]);
+ }
+ }
+ }
+
+ if (profiles.isEmpty() && inputs.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+
+ // open inputs for matching profiles if needed. Direct inputs are also opened to
+ // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+ for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+
+ IOProfile *profile = profiles[profile_index];
+ // nothing to do if one input is already opened for this profile
+ size_t input_index;
+ for (input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (input_index != mInputs.size()) {
+ continue;
+ }
+
+ ALOGV("opening input for device 0x%X with params %s", device, paramStr.string());
+ desc = new AudioInputDescriptor(profile);
+ desc->mDevice = device;
+
+ audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle,
+ &desc->mDevice,
+ &desc->mSamplingRate,
+ &desc->mFormat,
+ &desc->mChannelMask);
+
+ if (input != 0) {
+ if (!paramStr.isEmpty()) {
+ mpClientInterface->setParameters(input, paramStr);
+ }
+
+ // Here is where we step through and resolve any "dynamic" fields
+ String8 reply;
+ char *value;
+ if (profile->mSamplingRates[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+ ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadSamplingRates(value + 1, profile);
+ }
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadFormats(value + 1, profile);
+ }
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ reply = mpClientInterface->getParameters(input,
+ String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+ ALOGV("checkInputsForDevice() direct input sup channel masks %s",
+ reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ loadInChannels(value + 1, profile);
+ }
+ }
+ if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
+ ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
+ ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ ALOGW("checkInputsForDevice() direct input missing param");
+ mpClientInterface->closeInput(input);
+ input = 0;
+ }
+
+ if (input != 0) {
+ addInput(input, desc);
+ }
+ } // endif input != 0
+
+ if (input == 0) {
+ ALOGW("checkInputsForDevice() could not open input for device 0x%X", device);
+ delete desc;
+ profiles.removeAt(profile_index);
+ profile_index--;
+ } else {
+ inputs.add(input);
+ ALOGV("checkInputsForDevice(): adding input %d", input);
+ }
+ } // end scan profiles
+
+ if (profiles.isEmpty()) {
+ ALOGW("checkInputsForDevice(): No input available for device 0x%X", device);
+ return BAD_VALUE;
+ }
+ } else {
+ // Disconnect
+ // check if one opened input is not needed any more after disconnecting one device
+ for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+ desc = mInputs.valueAt(input_index);
+ if (!(desc->mProfile->mSupportedDevices & mAvailableInputDevices)) {
+ ALOGV("checkInputsForDevice(): disconnecting adding input %d",
+ mInputs.keyAt(input_index));
+ inputs.add(mInputs.keyAt(input_index));
+ }
+ }
+ // Clear any profiles associated with the disconnected device.
+ for (size_t module_index = 0; module_index < mHwModules.size(); module_index++)
+ {
+ if (mHwModules[module_index]->mHandle == 0) {
+ continue;
+ }
+ for (size_t profile_index = 0;
+ profile_index < mHwModules[module_index]->mInputProfiles.size();
+ profile_index++)
+ {
+ IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index];
+ if (profile->mSupportedDevices & device) {
+ ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
+ profile_index, module_index);
+ if (profile->mSamplingRates[0] == 0) {
+ profile->mSamplingRates.clear();
+ profile->mSamplingRates.add(0);
+ }
+ if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.clear();
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ }
+ if (profile->mChannelMasks[0] == 0) {
+ profile->mChannelMasks.clear();
+ profile->mChannelMasks.add(0);
+ }
+ }
+ }
+ }
+ } // end disconnect
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::closeOutput(audio_io_handle_t output)
+{
+ ALOGV("closeOutput(%d)", output);
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (outputDesc == NULL) {
+ ALOGW("closeOutput() unknown output %d", output);
+ return;
+ }
+
+ // look for duplicated outputs connected to the output being removed.
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i);
+ if (dupOutputDesc->isDuplicated() &&
+ (dupOutputDesc->mOutput1 == outputDesc ||
+ dupOutputDesc->mOutput2 == outputDesc)) {
+ AudioOutputDescriptor *outputDesc2;
+ if (dupOutputDesc->mOutput1 == outputDesc) {
+ outputDesc2 = dupOutputDesc->mOutput2;
+ } else {
+ outputDesc2 = dupOutputDesc->mOutput1;
+ }
+ // As all active tracks on duplicated output will be deleted,
+ // and as they were also referenced on the other output, the reference
+ // count for their stream type must be adjusted accordingly on
+ // the other output.
+ for (int j = 0; j < (int)AudioSystem::NUM_STREAM_TYPES; j++) {
+ int refCount = dupOutputDesc->mRefCount[j];
+ outputDesc2->changeRefCount((AudioSystem::stream_type)j,-refCount);
+ }
+ audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i);
+ ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
+
+ mpClientInterface->closeOutput(duplicatedOutput);
+ delete mOutputs.valueFor(duplicatedOutput);
+ mOutputs.removeItem(duplicatedOutput);
+ }
+ }
+
+ AudioParameter param;
+ param.add(String8("closing"), String8("true"));
+ mpClientInterface->setParameters(output, param.toString());
+
+ mpClientInterface->closeOutput(output);
+ delete outputDesc;
+ mOutputs.removeItem(output);
+ mPreviousOutputs = mOutputs;
+}
+
+SortedVector<audio_io_handle_t> AudioPolicyManagerBase::getOutputsForDevice(audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
+{
+ SortedVector<audio_io_handle_t> outputs;
+
+ ALOGVV("getOutputsForDevice() device %04x", device);
+ for (size_t i = 0; i < openOutputs.size(); i++) {
+ ALOGVV("output %d isDuplicated=%d device=%04x",
+ i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+ if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
+ ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+ outputs.add(openOutputs.keyAt(i));
+ }
+ }
+ return outputs;
+}
+
+bool AudioPolicyManagerBase::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+ SortedVector<audio_io_handle_t>& outputs2)
+{
+ if (outputs1.size() != outputs2.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < outputs1.size(); i++) {
+ if (outputs1[i] != outputs2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy)
+{
+ audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
+ audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
+ SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+ SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
+
+ if (!vectorsEqual(srcOutputs,dstOutputs)) {
+ ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
+ strategy, srcOutputs[0], dstOutputs[0]);
+ // 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->isStrategyActive(strategy)) {
+ setStrategyMute(strategy, true, srcOutputs[i]);
+ setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+ }
+ }
+
+ // Move effects associated to this strategy from previous output to new output
+ if (strategy == STRATEGY_MEDIA) {
+ 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 != fxOutput) {
+ if (moved.indexOf(desc->mIo) < 0) {
+ ALOGV("checkOutputForStrategy() moving effect %d to output %d",
+ mEffects.keyAt(i), fxOutput);
+ mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
+ fxOutput);
+ moved.add(desc->mIo);
+ }
+ desc->mIo = fxOutput;
+ }
+ }
+ }
+ // Move tracks associated to this strategy from previous output to new output
+ for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+ if (getStrategy((AudioSystem::stream_type)i) == strategy) {
+ mpClientInterface->invalidateStream((AudioSystem::stream_type)i);
+ }
+ }
+ }
+}
+
+void AudioPolicyManagerBase::checkOutputForAllStrategies()
+{
+ checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+ checkOutputForStrategy(STRATEGY_PHONE);
+ checkOutputForStrategy(STRATEGY_SONIFICATION);
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ checkOutputForStrategy(STRATEGY_MEDIA);
+ checkOutputForStrategy(STRATEGY_DTMF);
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getA2dpOutput()
+{
+ if (!mHasA2dp) {
+ return 0;
+ }
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+ return mOutputs.keyAt(i);
+ }
+ }
+
+ return 0;
+}
+
+void AudioPolicyManagerBase::checkA2dpSuspend()
+{
+ if (!mHasA2dp) {
+ return;
+ }
+ audio_io_handle_t a2dpOutput = getA2dpOutput();
+ if (a2dpOutput == 0) {
+ return;
+ }
+
+ // suspend A2DP output if:
+ // (NOT already suspended) &&
+ // ((SCO device is connected &&
+ // (forced usage for communication || for record is SCO))) ||
+ // (phone state is ringing || in call)
+ //
+ // restore A2DP output if:
+ // (Already suspended) &&
+ // ((SCO device is NOT connected ||
+ // (forced usage NOT for communication && NOT for record is SCO))) &&
+ // (phone state is NOT ringing && NOT in call)
+ //
+ if (mA2dpSuspended) {
+ if (((mScoDeviceAddress == "") ||
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+ (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) &&
+ ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+ (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->restoreOutput(a2dpOutput);
+ mA2dpSuspended = false;
+ }
+ } else {
+ if (((mScoDeviceAddress != "") &&
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) ||
+ ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+ (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->suspendOutput(a2dpOutput);
+ mA2dpSuspended = true;
+ }
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ // check the following by order of priority to request a routing change if necessary:
+ // 1: the strategy enforced audible is active on the output:
+ // use device for strategy enforced audible
+ // 2: we are in call or the strategy phone is active on the output:
+ // use device for strategy phone
+ // 3: the strategy sonification is active on the output:
+ // use device for strategy sonification
+ // 4: the strategy "respectful" sonification is active on the output:
+ // use device for strategy "respectful" sonification
+ // 5: the strategy media is active on the output:
+ // use device for strategy media
+ // 6: the strategy DTMF is active on the output:
+ // use device for strategy DTMF
+ if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+ device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+ } else if (isInCall() ||
+ outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+ device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+ } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+ device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+ }
+
+ ALOGV("getNewDevice() selected device %x", device);
+ return device;
+}
+
+uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) {
+ return (uint32_t)getStrategy(stream);
+}
+
+audio_devices_t AudioPolicyManagerBase::getDevicesForStream(AudioSystem::stream_type stream) {
+ audio_devices_t devices;
+ // By checking the range of stream before calling getStrategy, we avoid
+ // getStrategy's behavior for invalid streams. getStrategy would do a ALOGE
+ // and then return STRATEGY_MEDIA, but we want to return the empty set.
+ if (stream < (AudioSystem::stream_type) 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ devices = AUDIO_DEVICE_NONE;
+ } else {
+ AudioPolicyManagerBase::routing_strategy strategy = getStrategy(stream);
+ devices = getDeviceForStrategy(strategy, true /*fromCache*/);
+ }
+ return devices;
+}
+
+AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(
+ AudioSystem::stream_type stream) {
+ // stream to strategy mapping
+ switch (stream) {
+ case AudioSystem::VOICE_CALL:
+ case AudioSystem::BLUETOOTH_SCO:
+ return STRATEGY_PHONE;
+ case AudioSystem::RING:
+ case AudioSystem::ALARM:
+ return STRATEGY_SONIFICATION;
+ case AudioSystem::NOTIFICATION:
+ return STRATEGY_SONIFICATION_RESPECTFUL;
+ case AudioSystem::DTMF:
+ return STRATEGY_DTMF;
+ default:
+ ALOGE("unknown stream type");
+ case AudioSystem::SYSTEM:
+ // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+ // while key clicks are played produces a poor result
+ case AudioSystem::TTS:
+ case AudioSystem::MUSIC:
+ return STRATEGY_MEDIA;
+ case AudioSystem::ENFORCED_AUDIBLE:
+ return STRATEGY_ENFORCED_AUDIBLE;
+ }
+}
+
+void AudioPolicyManagerBase::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+ switch(stream) {
+ case AudioSystem::MUSIC:
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ updateDevicesAndOutputs();
+ break;
+ default:
+ break;
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ if (fromCache) {
+ ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+ strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+
+ 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*/);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ }
+
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+ case AudioSystem::FORCE_BT_SCO:
+ if (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (mHasA2dp && !isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ case STRATEGY_MEDIA: {
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ mHasA2dp && (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ (getA2dpOutput() != 0) && !mA2dpSuspended) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+ device |= device2;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+void AudioPolicyManagerBase::updateDevicesAndOutputs()
+{
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ }
+ mPreviousOutputs = mOutputs;
+}
+
+uint32_t AudioPolicyManagerBase::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+ audio_devices_t prevDevice,
+ uint32_t delayMs)
+{
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ if (outputDesc->isDuplicated()) {
+ return 0;
+ }
+
+ uint32_t muteWaitMs = 0;
+ audio_devices_t device = outputDesc->device();
+ 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->isActive() && (device != prevDevice);
+
+ for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+ audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+ bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+ bool doMute = false;
+
+ if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
+ doMute = true;
+ outputDesc->mStrategyMutedByDevice[i] = true;
+ } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){
+ doMute = true;
+ outputDesc->mStrategyMutedByDevice[i] = false;
+ }
+ 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;
+ }
+ audio_io_handle_t curOutput = mOutputs.keyAt(j);
+ 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->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 && (desc == outputDesc)) || mute) {
+ if (muteWaitMs < desc->latency()) {
+ muteWaitMs = desc->latency();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // FIXME: should not need to double latency if volume could be applied immediately by the
+ // audioflinger mixer. We must account for the delay between now and the next time
+ // the audioflinger thread for this output will process a buffer (which corresponds to
+ // one buffer size, usually 1/2 or 1/4 of the latency).
+ muteWaitMs *= 2;
+ // wait for the PCM output buffers to empty before proceeding with the rest of the command
+ if (muteWaitMs > delayMs) {
+ muteWaitMs -= delayMs;
+ usleep(muteWaitMs * 1000);
+ return muteWaitMs;
+ }
+ return 0;
+}
+
+uint32_t AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force,
+ int delayMs)
+{
+ ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ AudioParameter param;
+ 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);
+
+ audio_devices_t prevDevice = outputDesc->mDevice;
+
+ ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+ if (device != AUDIO_DEVICE_NONE) {
+ outputDesc->mDevice = device;
+
+ // Force routing if previously asked for this output
+ if (outputDesc->mForceRouting) {
+ ALOGV("Force routing to current device as previous device was null for this output");
+ force = true;
+
+ // Request consumed. Reset mForceRouting to false
+ outputDesc->mForceRouting = false;
+ }
+ }
+ else {
+ // Device is null and does not reflect the routing. Save the necessity to force
+ // re-routing upon next attempt to select a non-null device for this output
+ outputDesc->mForceRouting = true;
+ }
+
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // Do not change the routing if:
+ // - the requested device is AUDIO_DEVICE_NONE
+ // - the requested device is the same as current device and force is not specified.
+ // Doing this check here allows the caller to call setOutputDevice() without conditions
+ if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ return muteWaitMs;
+ }
+
+ ALOGV("setOutputDevice() changing device");
+ // do the routing
+ param.addInt(String8(AudioParameter::keyRouting), (int)device);
+ mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+ // update stream volumes according to new device
+ applyStreamVolumes(output, device, delayMs);
+
+ return muteWaitMs;
+}
+
+AudioPolicyManagerBase::IOProfile *AudioPolicyManagerBase::getInputProfile(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask)
+{
+ // Choose an input profile based on the requested capture parameters: select the first available
+ // profile supporting all requested parameters.
+ for (size_t i = 0; i < mHwModules.size(); i++)
+ {
+ if (mHwModules[i]->mHandle == 0) {
+ continue;
+ }
+ for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
+ {
+ IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+ // profile->log();
+ if (profile->isCompatibleProfile(device, samplingRate, format,
+ channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+ return profile;
+ }
+ }
+ }
+ return NULL;
+}
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ 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:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ break;
+ }
+ // FALL THROUGH
+
+ 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) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_USB_DEVICE) {
+ device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+bool AudioPolicyManagerBase::isVirtualInputDevice(audio_devices_t device)
+{
+ if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+ return true;
+ }
+ return false;
+}
+
+audio_io_handle_t AudioPolicyManagerBase::getActiveInput(bool ignoreVirtualInputs)
+{
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+ if ((input_descriptor->mRefCount > 0)
+ && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
+ return mInputs.keyAt(i);
+ }
+ }
+ return 0;
+}
+
+
+audio_devices_t AudioPolicyManagerBase::getDeviceForVolume(audio_devices_t device)
+{
+ if (device == AUDIO_DEVICE_NONE) {
+ // this happens when forcing a route update and no track is active on an output.
+ // In this case the returned category is not important.
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (AudioSystem::popCount(device) > 1) {
+ // Multiple device selection is either:
+ // - speaker + one other device: give priority to speaker in this case.
+ // - one A2DP device + another device: happens with duplicated output. In this case
+ // retain the device on the A2DP output as the other must not correspond to an active
+ // selection if not the speaker.
+ if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else {
+ device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+ }
+ }
+
+ ALOGW_IF(AudioSystem::popCount(device) != 1,
+ "getDeviceForVolume() invalid device combination: %08x",
+ device);
+
+ return device;
+}
+
+AudioPolicyManagerBase::device_category AudioPolicyManagerBase::getDeviceCategory(audio_devices_t device)
+{
+ switch(getDeviceForVolume(device)) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ return DEVICE_CATEGORY_EARPIECE;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ return DEVICE_CATEGORY_HEADSET;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+ case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
+ case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+ default:
+ return DEVICE_CATEGORY_SPEAKER;
+ }
+}
+
+float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi)
+{
+ device_category deviceCategory = getDeviceCategory(device);
+ const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
+
+ // the volume index in the UI is relative to the min and max volume indices for this stream type
+ int nbSteps = 1 + curve[VOLMAX].mIndex -
+ curve[VOLMIN].mIndex;
+ int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+ (streamDesc.mIndexMax - streamDesc.mIndexMin);
+
+ // find what part of the curve this index volume belongs to, or if it's out of bounds
+ int segment = 0;
+ if (volIdx < curve[VOLMIN].mIndex) { // out of bounds
+ return 0.0f;
+ } else if (volIdx < curve[VOLKNEE1].mIndex) {
+ segment = 0;
+ } else if (volIdx < curve[VOLKNEE2].mIndex) {
+ segment = 1;
+ } else if (volIdx <= curve[VOLMAX].mIndex) {
+ segment = 2;
+ } else { // out of bounds
+ return 1.0f;
+ }
+
+ // linear interpolation in the attenuation table in dB
+ float decibels = curve[segment].mDBAttenuation +
+ ((float)(volIdx - curve[segment].mIndex)) *
+ ( (curve[segment+1].mDBAttenuation -
+ curve[segment].mDBAttenuation) /
+ ((float)(curve[segment+1].mIndex -
+ curve[segment].mIndex)) );
+
+ float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+ ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+ curve[segment].mIndex, volIdx,
+ curve[segment+1].mIndex,
+ curve[segment].mDBAttenuation,
+ decibels,
+ curve[segment+1].mDBAttenuation,
+ amplification);
+
+ return amplification;
+}
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {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.
+// 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}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ AudioPolicyManagerBase::sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
+ {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManagerBase::VolumeCurvePoint
+ *AudioPolicyManagerBase::sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
+ [AudioPolicyManagerBase::DEVICE_CATEGORY_CNT] = {
+ { // AUDIO_STREAM_VOICE_CALL
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_SYSTEM
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_RING
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_MUSIC
+ sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_ALARM
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_NOTIFICATION
+ sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_BLUETOOTH_SCO
+ sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_ENFORCED_AUDIBLE
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_DTMF
+ sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+ { // AUDIO_STREAM_TTS
+ sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+ sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+ sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE
+ },
+};
+
+void AudioPolicyManagerBase::initializeVolumeCurves()
+{
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ mStreams[i].mVolumeCurve[j] =
+ 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,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device)
+{
+ float volume = 1.0;
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ if (device == AUDIO_DEVICE_NONE) {
+ device = outputDesc->device();
+ }
+
+ // if volume is not 0 (not muted), force media volume to max on digital output
+ if (stream == AudioSystem::MUSIC &&
+ index != mStreams[stream].mIndexMin &&
+ (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+ device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
+ return 1.0;
+ }
+
+ volume = volIndexToAmpl(device, streamDesc, index);
+
+ // if a headset is connected, apply the following rules to ring tones and notifications
+ // to avoid sound level bursts in user's ears:
+ // - always attenuate ring tones and notifications volume by 6dB
+ // - if music is playing, always limit the volume to current music volume,
+ // with a minimum threshold at -36dB so that notification is always perceived.
+ const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+ if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+ ((stream_strategy == STRATEGY_SONIFICATION)
+ || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
+ || (stream == AudioSystem::SYSTEM)
+ || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) &&
+ streamDesc.mCanBeMuted) {
+ volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
+ // when the phone is ringing we must consider that music could have been paused just before
+ // by the music application and behave as if music was active if the last music track was
+ // just stopped
+ if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
+ mLimitRingtoneVolume) {
+ audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
+ float musicVol = computeVolume(AudioSystem::MUSIC,
+ mStreams[AudioSystem::MUSIC].getVolumeIndex(musicDevice),
+ output,
+ musicDevice);
+ float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ?
+ musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
+ if (volume > minVol) {
+ volume = minVol;
+ ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
+ }
+ }
+ }
+
+ return volume;
+}
+
+status_t AudioPolicyManagerBase::checkAndSetVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+
+ // do not change actual stream volume if the stream is muted
+ if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+ ALOGVV("checkAndSetVolume() stream %d muted count %d",
+ stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+ return NO_ERROR;
+ }
+
+ // do not change in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ float volume = computeVolume(stream, index, output, device);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+ // enabled
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ voiceVolume = 1.0;
+ }
+
+ if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::applyStreamVolumes(audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+ ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
+
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex(device),
+ output,
+ device,
+ delayMs,
+ force);
+ }
+}
+
+void AudioPolicyManagerBase::setStrategyMute(routing_strategy strategy,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
+{
+ ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ if (getStrategy((AudioSystem::stream_type)stream) == strategy) {
+ setStreamMute(stream, on, output, delayMs, device);
+ }
+ }
+}
+
+void AudioPolicyManagerBase::setStreamMute(int stream,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs,
+ audio_devices_t device)
+{
+ StreamDescriptor &streamDesc = mStreams[stream];
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ if (device == AUDIO_DEVICE_NONE) {
+ device = outputDesc->device();
+ }
+
+ ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x",
+ stream, on, output, outputDesc->mMuteCount[stream], device);
+
+ if (on) {
+ if (outputDesc->mMuteCount[stream] == 0) {
+ if (streamDesc.mCanBeMuted &&
+ ((stream != AudioSystem::ENFORCED_AUDIBLE) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_NONE))) {
+ checkAndSetVolume(stream, 0, output, device, delayMs);
+ }
+ }
+ // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+ outputDesc->mMuteCount[stream]++;
+ } else {
+ if (outputDesc->mMuteCount[stream] == 0) {
+ ALOGV("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if (--outputDesc->mMuteCount[stream] == 0) {
+ checkAndSetVolume(stream,
+ streamDesc.getVolumeIndex(device),
+ output,
+ device,
+ delayMs);
+ }
+ }
+}
+
+void AudioPolicyManagerBase::handleIncallSonification(int stream, bool starting, bool stateChange)
+{
+ // if the stream pertains to sonification strategy and we are in call we must
+ // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+ // in the device used for phone strategy and play the tone if the selected device does not
+ // interfere with the device used for phone strategy
+ // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
+ // many times as there are active tracks on the output
+ const routing_strategy stream_strategy = getStrategy((AudioSystem::stream_type)stream);
+ if ((stream_strategy == STRATEGY_SONIFICATION) ||
+ ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+ ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
+ stream, starting, outputDesc->mDevice, stateChange);
+ if (outputDesc->mRefCount[stream]) {
+ int muteCount = 1;
+ if (stateChange) {
+ muteCount = outputDesc->mRefCount[stream];
+ }
+ if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+ ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
+ for (int i = 0; i < muteCount; i++) {
+ setStreamMute(stream, starting, mPrimaryOutput);
+ }
+ } else {
+ ALOGV("handleIncallSonification() high visibility");
+ if (outputDesc->device() &
+ getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) {
+ ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
+ for (int i = 0; i < muteCount; i++) {
+ setStreamMute(stream, starting, mPrimaryOutput);
+ }
+ }
+ if (starting) {
+ mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+ } else {
+ mpClientInterface->stopTone();
+ }
+ }
+ }
+ }
+}
+
+bool AudioPolicyManagerBase::isInCall()
+{
+ return isStateInCall(mPhoneState);
+}
+
+bool AudioPolicyManagerBase::isStateInCall(int state) {
+ return ((state == AudioSystem::MODE_IN_CALL) ||
+ (state == AudioSystem::MODE_IN_COMMUNICATION));
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad()
+{
+ return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t AudioPolicyManagerBase::getMaxEffectsMemory()
+{
+ return MAX_EFFECTS_MEMORY;
+}
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor(
+ const IOProfile *profile)
+ : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+ mChannelMask(0), mLatency(0),
+ mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+ mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0),
+ mForceRouting(false)
+{
+ // clear usage count for all stream types
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ mRefCount[i] = 0;
+ mCurVolume[i] = -1.0;
+ mMuteCount[i] = 0;
+ mStopTime[i] = 0;
+ }
+ for (int i = 0; i < NUM_STRATEGIES; i++) {
+ mStrategyMutedByDevice[i] = false;
+ }
+ if (profile != NULL) {
+ mSamplingRate = profile->mSamplingRates[0];
+ mFormat = profile->mFormats[0];
+ mChannelMask = profile->mChannelMasks[0];
+ mFlags = profile->mFlags;
+ }
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::device() const
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
+ } else {
+ return mDevice;
+ }
+}
+
+uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::latency()
+{
+ if (isDuplicated()) {
+ return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
+ } else {
+ return mLatency;
+ }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::sharesHwModuleWith(
+ const AudioOutputDescriptor *outputDesc)
+{
+ if (isDuplicated()) {
+ return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
+ } else if (outputDesc->isDuplicated()){
+ return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
+ } else {
+ return (mProfile->mModule == outputDesc->mProfile->mModule);
+ }
+}
+
+void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+ // forward usage count change to attached outputs
+ if (isDuplicated()) {
+ mOutput1->changeRefCount(stream, delta);
+ mOutput2->changeRefCount(stream, delta);
+ }
+ if ((delta + (int)mRefCount[stream]) < 0) {
+ ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+audio_devices_t AudioPolicyManagerBase::AudioOutputDescriptor::supportedDevices()
+{
+ if (isDuplicated()) {
+ return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
+ } else {
+ return mProfile->mSupportedDevices ;
+ }
+}
+
+bool AudioPolicyManagerBase::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+ 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 (((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;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", device());
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+ result.append(buffer);
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n", i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerBase::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
+ : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+ mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+ mInputSource(0), mProfile(profile)
+{
+ if (profile != NULL) {
+ mSamplingRate = profile->mSamplingRates[0];
+ mFormat = profile->mFormats[0];
+ mChannelMask = profile->mChannelMasks[0];
+ }
+}
+
+status_t AudioPolicyManagerBase::AudioInputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- StreamDescriptor class implementation
+
+AudioPolicyManagerBase::StreamDescriptor::StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+ mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int AudioPolicyManagerBase::StreamDescriptor::getVolumeIndex(audio_devices_t device)
+{
+ device = AudioPolicyManagerBase::getDeviceForVolume(device);
+ // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+ if (mIndexCur.indexOfKey(device) < 0) {
+ device = AUDIO_DEVICE_OUT_DEFAULT;
+ }
+ return mIndexCur.valueFor(device);
+}
+
+void AudioPolicyManagerBase::StreamDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s %02d %02d ",
+ mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+ result.append(buffer);
+ for (size_t i = 0; i < mIndexCur.size(); i++) {
+ snprintf(buffer, SIZE, "%04x : %02d, ",
+ mIndexCur.keyAt(i),
+ mIndexCur.valueAt(i));
+ result.append(buffer);
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+// --- EffectDescriptor class implementation
+
+status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " I/O: %d\n", mIo);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Session: %d\n", mSession);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " Name: %s\n", mDesc.name);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManagerBase::HwModule::HwModule(const char *name)
+ : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
+{
+}
+
+AudioPolicyManagerBase::HwModule::~HwModule()
+{
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ delete mOutputProfiles[i];
+ }
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ delete mInputProfiles[i];
+ }
+ free((void *)mName);
+}
+
+void AudioPolicyManagerBase::HwModule::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " - name: %s\n", mName);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mOutputProfiles.size()) {
+ write(fd, " - outputs:\n", strlen(" - outputs:\n"));
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " output %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mOutputProfiles[i]->dump(fd);
+ }
+ }
+ if (mInputProfiles.size()) {
+ write(fd, " - inputs:\n", strlen(" - inputs:\n"));
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ snprintf(buffer, SIZE, " input %zu:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mInputProfiles[i]->dump(fd);
+ }
+ }
+}
+
+AudioPolicyManagerBase::IOProfile::IOProfile(HwModule *module)
+ : mFlags((audio_output_flags_t)0), mModule(module)
+{
+}
+
+AudioPolicyManagerBase::IOProfile::~IOProfile()
+{
+}
+
+// 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,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags) const
+{
+ if (samplingRate == 0 || !audio_is_valid_format(format) || 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)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, " - sampling rates: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ result.append(buffer);
+ result.append(i == (mSamplingRates.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - channel masks: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+ result.append(buffer);
+ result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - formats: ");
+ result.append(buffer);
+ for (size_t i = 0; i < mFormats.size(); i++) {
+ snprintf(buffer, SIZE, "0x%08x", mFormats[i]);
+ result.append(buffer);
+ result.append(i == (mFormats.size() - 1) ? "\n" : ", ");
+ }
+
+ snprintf(buffer, SIZE, " - devices: 0x%04x\n", mSupportedDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+}
+
+void AudioPolicyManagerBase::IOProfile::log()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ ALOGV(" - sampling rates: ");
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ ALOGV(" %d", mSamplingRates[i]);
+ }
+
+ ALOGV(" - channel masks: ");
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ ALOGV(" 0x%04x", mChannelMasks[i]);
+ }
+
+ ALOGV(" - formats: ");
+ for (size_t i = 0; i < mFormats.size(); i++) {
+ ALOGV(" 0x%08x", mFormats[i]);
+ }
+
+ ALOGV(" - devices: 0x%04x\n", mSupportedDevices);
+ ALOGV(" - flags: 0x%04x\n", mFlags);
+}
+
+// --- audio_policy.conf file parsing
+
+struct StringToEnum {
+ const char *name;
+ uint32_t value;
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+const struct StringToEnum sDeviceNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+};
+
+const struct StringToEnum sFlagNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ 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[] = {
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+ STRING_TO_ENUM(AUDIO_FORMAT_MP3),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC),
+ STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
+ STRING_TO_ENUM(AUDIO_FORMAT_AC3),
+ STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
+};
+
+const struct StringToEnum sOutChannelsNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+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),
+};
+
+
+uint32_t AudioPolicyManagerBase::stringToEnum(const struct StringToEnum *table,
+ size_t size,
+ const char *name)
+{
+ for (size_t i = 0; i < size; i++) {
+ if (strcmp(table[i].name, name) == 0) {
+ ALOGV("stringToEnum() found %s", table[i].name);
+ return table[i].value;
+ }
+ }
+ 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;
+
+ // it is OK to cast name to non const here as we are not going to use it after
+ // strtok() modifies it
+ char *flagName = strtok(name, "|");
+ while (flagName != NULL) {
+ if (strlen(flagName) != 0) {
+ flag |= stringToEnum(sFlagNameToEnumTable,
+ ARRAY_SIZE(sFlagNameToEnumTable),
+ flagName);
+ }
+ 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;
+}
+
+audio_devices_t AudioPolicyManagerBase::parseDeviceNames(char *name)
+{
+ uint32_t device = 0;
+
+ char *devName = strtok(name, "|");
+ while (devName != NULL) {
+ if (strlen(devName) != 0) {
+ device |= stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ devName);
+ }
+ devName = strtok(NULL, "|");
+ }
+ return device;
+}
+
+void AudioPolicyManagerBase::loadSamplingRates(char *name, IOProfile *profile)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+ // rates should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mSamplingRates.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ uint32_t rate = atoi(str);
+ if (rate != 0) {
+ ALOGV("loadSamplingRates() adding rate %d", rate);
+ profile->mSamplingRates.add(rate);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadFormats(char *name, IOProfile *profile)
+{
+ char *str = strtok(name, "|");
+
+ // by convention, "0' in the first entry in mFormats indicates the supported formats
+ // should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+ ARRAY_SIZE(sFormatNameToEnumTable),
+ str);
+ if (format != AUDIO_FORMAT_DEFAULT) {
+ profile->mFormats.add(format);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadInChannels(char *name, IOProfile *profile)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadInChannels() %s", name);
+
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+ ARRAY_SIZE(sInChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+ profile->mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+void AudioPolicyManagerBase::loadOutChannels(char *name, IOProfile *profile)
+{
+ const char *str = strtok(name, "|");
+
+ ALOGV("loadOutChannels() %s", name);
+
+ // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+ // masks should be read from the output stream after it is opened for the first time
+ if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+ profile->mChannelMasks.add(0);
+ return;
+ }
+
+ while (str != NULL) {
+ audio_channel_mask_t channelMask =
+ (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+ ARRAY_SIZE(sOutChannelsNameToEnumTable),
+ str);
+ if (channelMask != 0) {
+ profile->mChannelMasks.add(channelMask);
+ }
+ str = strtok(NULL, "|");
+ }
+ return;
+}
+
+status_t AudioPolicyManagerBase::loadInput(cnode *root, HwModule *module)
+{
+ cnode *node = root->first_child;
+
+ IOProfile *profile = new IOProfile(module);
+
+ while (node) {
+ if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+ loadSamplingRates((char *)node->value, profile);
+ } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+ loadFormats((char *)node->value, profile);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ loadInChannels((char *)node->value, profile);
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+ }
+ node = node->next;
+ }
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+ "loadInput() invalid supported devices");
+ ALOGW_IF(profile->mChannelMasks.size() == 0,
+ "loadInput() invalid supported channel masks");
+ ALOGW_IF(profile->mSamplingRates.size() == 0,
+ "loadInput() invalid supported sampling rates");
+ ALOGW_IF(profile->mFormats.size() == 0,
+ "loadInput() invalid supported formats");
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+ (profile->mChannelMasks.size() != 0) &&
+ (profile->mSamplingRates.size() != 0) &&
+ (profile->mFormats.size() != 0)) {
+
+ ALOGV("loadInput() adding input mSupportedDevices 0x%X", profile->mSupportedDevices);
+
+ module->mInputProfiles.add(profile);
+ return NO_ERROR;
+ } else {
+ delete profile;
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioPolicyManagerBase::loadOutput(cnode *root, HwModule *module)
+{
+ cnode *node = root->first_child;
+
+ IOProfile *profile = new IOProfile(module);
+
+ while (node) {
+ if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+ loadSamplingRates((char *)node->value, profile);
+ } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+ loadFormats((char *)node->value, profile);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ loadOutChannels((char *)node->value, profile);
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+ } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+ profile->mFlags = parseFlagNames((char *)node->value);
+ }
+ node = node->next;
+ }
+ ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+ "loadOutput() invalid supported devices");
+ ALOGW_IF(profile->mChannelMasks.size() == 0,
+ "loadOutput() invalid supported channel masks");
+ ALOGW_IF(profile->mSamplingRates.size() == 0,
+ "loadOutput() invalid supported sampling rates");
+ ALOGW_IF(profile->mFormats.size() == 0,
+ "loadOutput() invalid supported formats");
+ if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+ (profile->mChannelMasks.size() != 0) &&
+ (profile->mSamplingRates.size() != 0) &&
+ (profile->mFormats.size() != 0)) {
+
+ ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x",
+ profile->mSupportedDevices, profile->mFlags);
+
+ module->mOutputProfiles.add(profile);
+ return NO_ERROR;
+ } else {
+ delete profile;
+ return BAD_VALUE;
+ }
+}
+
+void AudioPolicyManagerBase::loadHwModule(cnode *root)
+{
+ cnode *node = config_find(root, OUTPUTS_TAG);
+ status_t status = NAME_NOT_FOUND;
+
+ HwModule *module = new HwModule(root->name);
+
+ if (node != NULL) {
+ if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+ mHasA2dp = true;
+ } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+ mHasUsb = true;
+ } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+ mHasRemoteSubmix = true;
+ }
+
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading output %s", node->name);
+ status_t tmpStatus = loadOutput(node, module);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ node = config_find(root, INPUTS_TAG);
+ if (node != NULL) {
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModule() loading input %s", node->name);
+ status_t tmpStatus = loadInput(node, module);
+ if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+ status = tmpStatus;
+ }
+ node = node->next;
+ }
+ }
+ if (status == NO_ERROR) {
+ mHwModules.add(module);
+ } else {
+ delete module;
+ }
+}
+
+void AudioPolicyManagerBase::loadHwModules(cnode *root)
+{
+ cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
+ if (node == NULL) {
+ return;
+ }
+
+ node = node->first_child;
+ while (node) {
+ ALOGV("loadHwModules() loading module %s", node->name);
+ loadHwModule(node);
+ node = node->next;
+ }
+}
+
+void AudioPolicyManagerBase::loadGlobalConfig(cnode *root)
+{
+ cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+ if (node == NULL) {
+ return;
+ }
+ node = node->first_child;
+ while (node) {
+ if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
+ mAttachedOutputDevices = parseDeviceNames((char *)node->value);
+ ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() no attached output devices");
+ ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices);
+ } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
+ mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
+ ARRAY_SIZE(sDeviceNameToEnumTable),
+ (char *)node->value);
+ ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE,
+ "loadGlobalConfig() default device not specified");
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice);
+ } 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;
+ }
+}
+
+status_t AudioPolicyManagerBase::loadAudioPolicyConfig(const char *path)
+{
+ cnode *root;
+ char *data;
+
+ data = (char *)load_file(path, NULL);
+ if (data == NULL) {
+ return -ENODEV;
+ }
+ root = config_node("", "");
+ config_load(root, data);
+
+ loadGlobalConfig(root);
+ loadHwModules(root);
+
+ config_free(root);
+ free(root);
+ free(data);
+
+ ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+
+ return NO_ERROR;
+}
+
+void AudioPolicyManagerBase::defaultAudioPolicyConfig(void)
+{
+ HwModule *module;
+ IOProfile *profile;
+
+ mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER;
+ mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER;
+ mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+
+ module = new HwModule("primary");
+
+ profile = new IOProfile(module);
+ profile->mSamplingRates.add(44100);
+ profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+ profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+ profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER;
+ profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
+ module->mOutputProfiles.add(profile);
+
+ profile = new IOProfile(module);
+ profile->mSamplingRates.add(8000);
+ profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+ profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+ profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ module->mInputProfiles.add(profile);
+
+ mHwModules.add(module);
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp b/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp
new file mode 100644
index 0000000..9083638
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerDefault.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyManagerDefault"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyManagerDefault.h"
+
+namespace android_audio_legacy {
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManagerDefault(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+}; // namespace android
diff --git a/libhardware_legacy/audio/AudioPolicyManagerDefault.h b/libhardware_legacy/audio/AudioPolicyManagerDefault.h
new file mode 100644
index 0000000..987fdf0
--- /dev/null
+++ b/libhardware_legacy/audio/AudioPolicyManagerDefault.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+namespace android_audio_legacy {
+
+class AudioPolicyManagerDefault: public AudioPolicyManagerBase
+{
+
+public:
+ explicit AudioPolicyManagerDefault(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface) {}
+
+ virtual ~AudioPolicyManagerDefault() {}
+
+};
+};
diff --git a/libhardware_legacy/audio/audio_hw_hal.cpp b/libhardware_legacy/audio/audio_hw_hal.cpp
new file mode 100644
index 0000000..d15044a
--- /dev/null
+++ b/libhardware_legacy/audio/audio_hw_hal.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "legacy_audio_hw_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+class AudioHardwareInterface;
+
+extern "C" {
+
+struct legacy_audio_module {
+ struct audio_module module;
+};
+
+struct legacy_audio_device {
+ struct audio_hw_device device;
+
+ AudioHardwareInterface *hwif;
+};
+
+struct legacy_stream_out {
+ struct audio_stream_out stream;
+
+ AudioStreamOut *legacy_out;
+};
+
+struct legacy_stream_in {
+ struct audio_stream_in stream;
+
+ AudioStreamIn *legacy_in;
+};
+
+
+enum {
+ HAL_API_REV_1_0,
+ HAL_API_REV_2_0,
+ HAL_API_REV_NUM
+} hal_api_rev;
+
+static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] =
+{
+ /* output devices */
+ { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE },
+ { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER },
+ { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET },
+ { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES },
+ { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER },
+ { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
+ { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
+ { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
+ { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
+ /* input devices */
+ { AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION },
+ { AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT },
+ { AudioSystem::DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC },
+ { AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET },
+ { AudioSystem::DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET },
+ { AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL },
+ { AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL },
+ { AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC },
+ { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
+};
+
+static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev)
+{
+ const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM;
+ uint32_t to_device = AUDIO_DEVICE_NONE;
+ uint32_t in_bit = 0;
+
+ if (from_rev != HAL_API_REV_1_0) {
+ in_bit = from_device & AUDIO_DEVICE_BIT_IN;
+ from_device &= ~AUDIO_DEVICE_BIT_IN;
+ }
+
+ while (from_device) {
+ uint32_t i = 31 - __builtin_clz(from_device);
+ uint32_t cur_device = (1 << i) | in_bit;
+
+ for (i = 0; i < k_num_devices; i++) {
+ if (audio_device_conv_table[i][from_rev] == cur_device) {
+ to_device |= audio_device_conv_table[i][to_rev];
+ break;
+ }
+ }
+ from_device &= ~cur_device;
+ }
+ return to_device;
+}
+
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return (audio_channel_mask_t) out->legacy_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) out->legacy_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ Vector<String16> args;
+ return out->legacy_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ int val;
+ String8 s8 = String8(kvpairs);
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return out->legacy_out->setParameters(s8);
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = out->legacy_out->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+ struct legacy_stream_out *out =
+ reinterpret_cast<struct legacy_stream_out *>(stream);
+ return out->legacy_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getRenderPosition(dsp_frames);
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ const struct legacy_stream_out *out =
+ reinterpret_cast<const struct legacy_stream_out *>(stream);
+ return out->legacy_out->getNextWriteTimestamp(timestamp);
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return (audio_channel_mask_t) in->legacy_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ // legacy API, don't change return type
+ return (audio_format_t) in->legacy_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ struct legacy_stream_in *in = reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ Vector<String16> args;
+ return in->legacy_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ int val;
+ AudioParameter parms = AudioParameter(String8(kvpairs));
+ String8 s8 = String8(kvpairs);
+
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_2_0, HAL_API_REV_1_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return in->legacy_in->setParameters(s8);
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ String8 s8;
+ int val;
+
+ s8 = in->legacy_in->getParameters(String8(keys));
+
+ AudioParameter parms = AudioParameter(s8);
+ if (parms.getInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val) == NO_ERROR) {
+ val = convert_audio_device(val, HAL_API_REV_1_0, HAL_API_REV_2_0);
+ parms.remove(String8(AUDIO_PARAMETER_STREAM_ROUTING));
+ parms.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), val);
+ s8 = parms.toString();
+ }
+
+ return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+ return in->legacy_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct legacy_stream_in *in =
+ reinterpret_cast<const struct legacy_stream_in *>(stream);
+ return in->legacy_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct legacy_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+ return reinterpret_cast<struct legacy_audio_device *>(dev);
+}
+
+static inline const struct legacy_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+ return reinterpret_cast<const struct legacy_audio_device *>(dev);
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+
+ return ladev->hwif->initCheck();
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setVoiceVolume(volume);
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMasterVolume(volume);
+}
+
+static int adev_get_master_volume(struct audio_hw_device *dev, float* volume)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->getMasterVolume(volume);
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ // as this is the legacy API, don't change it to use audio_mode_t instead of int
+ return ladev->hwif->setMode((int) mode);
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setMicMute(state);
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getMicMute(state);
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ return ladev->hwif->setParameters(String8(kvpairs));
+}
+
+static char * adev_get_parameters(const struct audio_hw_device *dev,
+ const char *keys)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ String8 s8;
+
+ s8 = ladev->hwif->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+ const struct audio_config *config)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ return ladev->hwif->getInputBufferSize(config->sample_rate, (int) config->format,
+ audio_channel_count_from_in_mask(config->channel_mask));
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ audio_output_flags_t flags,
+ struct audio_config *config,
+ struct audio_stream_out **stream_out,
+ const char *address __unused)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status;
+ struct legacy_stream_out *out;
+ int ret;
+
+ out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
+ if (!out)
+ return -ENOMEM;
+
+ devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+ out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,
+ (int *) &config->format,
+ &config->channel_mask,
+ &config->sample_rate, &status);
+ if (!out->legacy_out) {
+ ret = status;
+ goto err_open;
+ }
+
+ out->stream.common.get_sample_rate = out_get_sample_rate;
+ out->stream.common.set_sample_rate = out_set_sample_rate;
+ out->stream.common.get_buffer_size = out_get_buffer_size;
+ out->stream.common.get_channels = out_get_channels;
+ out->stream.common.get_format = out_get_format;
+ out->stream.common.set_format = out_set_format;
+ out->stream.common.standby = out_standby;
+ out->stream.common.dump = out_dump;
+ out->stream.common.set_parameters = out_set_parameters;
+ out->stream.common.get_parameters = out_get_parameters;
+ out->stream.common.add_audio_effect = out_add_audio_effect;
+ out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream.get_latency = out_get_latency;
+ out->stream.set_volume = out_set_volume;
+ out->stream.write = out_write;
+ out->stream.get_render_position = out_get_render_position;
+ out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
+
+ *stream_out = &out->stream;
+ return 0;
+
+err_open:
+ free(out);
+ *stream_out = NULL;
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+ struct audio_stream_out* stream)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_out *out = reinterpret_cast<struct legacy_stream_out *>(stream);
+
+ ladev->hwif->closeOutputStream(out->legacy_out);
+ free(out);
+}
+
+/** This method creates and opens the audio hardware input stream */
+static int adev_open_input_stream(struct audio_hw_device *dev,
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ struct audio_stream_in **stream_in,
+ audio_input_flags_t flags __unused,
+ const char *address __unused,
+ audio_source_t source __unused)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ status_t status;
+ struct legacy_stream_in *in;
+ int ret;
+
+ in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
+ if (!in)
+ return -ENOMEM;
+
+ devices = convert_audio_device(devices, HAL_API_REV_2_0, HAL_API_REV_1_0);
+
+ in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
+ &config->channel_mask, &config->sample_rate,
+ &status, (AudioSystem::audio_in_acoustics)0);
+ if (!in->legacy_in) {
+ ret = status;
+ goto err_open;
+ }
+
+ in->stream.common.get_sample_rate = in_get_sample_rate;
+ in->stream.common.set_sample_rate = in_set_sample_rate;
+ in->stream.common.get_buffer_size = in_get_buffer_size;
+ in->stream.common.get_channels = in_get_channels;
+ in->stream.common.get_format = in_get_format;
+ in->stream.common.set_format = in_set_format;
+ in->stream.common.standby = in_standby;
+ in->stream.common.dump = in_dump;
+ in->stream.common.set_parameters = in_set_parameters;
+ in->stream.common.get_parameters = in_get_parameters;
+ in->stream.common.add_audio_effect = in_add_audio_effect;
+ in->stream.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ *stream_in = &in->stream;
+ return 0;
+
+err_open:
+ free(in);
+ *stream_in = NULL;
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+ struct audio_stream_in *stream)
+{
+ struct legacy_audio_device *ladev = to_ladev(dev);
+ struct legacy_stream_in *in =
+ reinterpret_cast<struct legacy_stream_in *>(stream);
+
+ ladev->hwif->closeInputStream(in->legacy_in);
+ free(in);
+}
+
+static int adev_dump(const struct audio_hw_device *dev, int fd)
+{
+ const struct legacy_audio_device *ladev = to_cladev(dev);
+ Vector<String16> args;
+
+ return ladev->hwif->dumpState(fd, args);
+}
+
+static int legacy_adev_close(hw_device_t* device)
+{
+ struct audio_hw_device *hwdev =
+ reinterpret_cast<struct audio_hw_device *>(device);
+ struct legacy_audio_device *ladev = to_ladev(hwdev);
+
+ if (!ladev)
+ return 0;
+
+ if (ladev->hwif)
+ delete ladev->hwif;
+
+ free(ladev);
+ return 0;
+}
+
+static int legacy_adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct legacy_audio_device *ladev;
+ int ret;
+
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
+ return -EINVAL;
+
+ ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
+ if (!ladev)
+ return -ENOMEM;
+
+ ladev->device.common.tag = HARDWARE_DEVICE_TAG;
+ ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ ladev->device.common.module = const_cast<hw_module_t*>(module);
+ ladev->device.common.close = legacy_adev_close;
+
+ ladev->device.init_check = adev_init_check;
+ ladev->device.set_voice_volume = adev_set_voice_volume;
+ ladev->device.set_master_volume = adev_set_master_volume;
+ ladev->device.get_master_volume = adev_get_master_volume;
+ ladev->device.set_mode = adev_set_mode;
+ ladev->device.set_mic_mute = adev_set_mic_mute;
+ ladev->device.get_mic_mute = adev_get_mic_mute;
+ ladev->device.set_parameters = adev_set_parameters;
+ ladev->device.get_parameters = adev_get_parameters;
+ ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ ladev->device.open_output_stream = adev_open_output_stream;
+ ladev->device.close_output_stream = adev_close_output_stream;
+ ladev->device.open_input_stream = adev_open_input_stream;
+ ladev->device.close_input_stream = adev_close_input_stream;
+ ladev->device.dump = adev_dump;
+
+ ladev->hwif = createAudioHardware();
+ if (!ladev->hwif) {
+ ret = -EIO;
+ goto err_create_audio_hw;
+ }
+
+ *device = &ladev->device.common;
+
+ return 0;
+
+err_create_audio_hw:
+ free(ladev);
+ return ret;
+}
+
+static struct hw_module_methods_t legacy_audio_module_methods = {
+ open: legacy_adev_open
+};
+
+struct legacy_audio_module HAL_MODULE_INFO_SYM = {
+ module: {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ module_api_version: AUDIO_MODULE_API_VERSION_0_1,
+ hal_api_version: HARDWARE_HAL_API_VERSION,
+ id: AUDIO_HARDWARE_MODULE_ID,
+ name: "LEGACY Audio HW HAL",
+ author: "The Android Open Source Project",
+ methods: &legacy_audio_module_methods,
+ dso : NULL,
+ reserved : {0},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/audio/audio_policy.conf b/libhardware_legacy/audio/audio_policy.conf
new file mode 100644
index 0000000..3e29976
--- /dev/null
+++ b/libhardware_legacy/audio/audio_policy.conf
@@ -0,0 +1,64 @@
+#
+# Audio policy configuration for generic device builds (goldfish audio HAL - emulator)
+#
+
+# Global configuration section: lists input and output devices always present on the device
+# as well as the output device selected by default.
+# Devices are designated by a string that corresponds to the enum in audio.h
+
+global_configuration {
+ attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
+ default_output_device AUDIO_DEVICE_OUT_SPEAKER
+ 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
+# device. Each hw module node is named after the corresponding hw module library base name.
+# For instance, "primary" corresponds to audio.primary.<device>.so.
+# The "primary" module is mandatory and must include at least one output with
+# AUDIO_OUTPUT_FLAG_PRIMARY flag.
+# Each module descriptor contains one or more output profile descriptors and zero or more
+# input profile descriptors. Each profile lists all the parameters supported by a given output
+# or input stream category.
+# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
+# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
+
+audio_hw_modules {
+ primary {
+ outputs {
+ primary {
+ sampling_rates 44100
+ channel_masks AUDIO_CHANNEL_OUT_STEREO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_OUT_SPEAKER
+ flags AUDIO_OUTPUT_FLAG_PRIMARY
+ }
+ }
+ inputs {
+ primary {
+ sampling_rates 8000|16000
+ channel_masks AUDIO_CHANNEL_IN_MONO
+ formats AUDIO_FORMAT_PCM_16_BIT
+ devices AUDIO_DEVICE_IN_BUILTIN_MIC
+ }
+ }
+ }
+ 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/libhardware_legacy/audio/audio_policy_hal.cpp b/libhardware_legacy/audio/audio_policy_hal.cpp
new file mode 100644
index 0000000..87c4131
--- /dev/null
+++ b/libhardware_legacy/audio/audio_policy_hal.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "legacy_audio_policy_hal"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include "AudioPolicyCompatClient.h"
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct legacy_ap_module {
+ struct audio_policy_module module;
+};
+
+struct legacy_ap_device {
+ struct audio_policy_device device;
+};
+
+struct legacy_audio_policy {
+ struct audio_policy policy;
+
+ void *service;
+ struct audio_policy_service_ops *aps_ops;
+ AudioPolicyCompatClient *service_client;
+ AudioPolicyInterface *apm;
+};
+
+static inline struct legacy_audio_policy * to_lap(struct audio_policy *pol)
+{
+ return reinterpret_cast<struct legacy_audio_policy *>(pol);
+}
+
+static inline const struct legacy_audio_policy * to_clap(const struct audio_policy *pol)
+{
+ return reinterpret_cast<const struct legacy_audio_policy *>(pol);
+}
+
+
+static int ap_set_device_connection_state(struct audio_policy *pol,
+ audio_devices_t device,
+ audio_policy_dev_state_t state,
+ const char *device_address)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ (AudioSystem::device_connection_state)state,
+ device_address);
+}
+
+static audio_policy_dev_state_t ap_get_device_connection_state(
+ const struct audio_policy *pol,
+ audio_devices_t device,
+ const char *device_address)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return (audio_policy_dev_state_t)lap->apm->getDeviceConnectionState(
+ (AudioSystem::audio_devices)device,
+ device_address);
+}
+
+static void ap_set_phone_state(struct audio_policy *pol, audio_mode_t state)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ // as this is the legacy API, don't change it to use audio_mode_t instead of int
+ lap->apm->setPhoneState((int) state);
+}
+
+ /* indicate a change in ringer mode */
+static void ap_set_ringer_mode(struct audio_policy *pol, uint32_t mode,
+ uint32_t mask)
+{
+ // deprecated, never called
+}
+
+ /* force using a specific device category for the specified usage */
+static void ap_set_force_use(struct audio_policy *pol,
+ audio_policy_force_use_t usage,
+ audio_policy_forced_cfg_t config)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->setForceUse((AudioSystem::force_use)usage,
+ (AudioSystem::forced_config)config);
+}
+
+ /* retreive current device category forced for a given usage */
+static audio_policy_forced_cfg_t ap_get_force_use(
+ const struct audio_policy *pol,
+ audio_policy_force_use_t usage)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return (audio_policy_forced_cfg_t)lap->apm->getForceUse(
+ (AudioSystem::force_use)usage);
+}
+
+/* if can_mute is true, then audio streams that are marked ENFORCED_AUDIBLE
+ * can still be muted. */
+static void ap_set_can_mute_enforced_audible(struct audio_policy *pol,
+ bool can_mute)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->setSystemProperty("ro.camera.sound.forced", can_mute ? "0" : "1");
+}
+
+static int ap_init_check(const struct audio_policy *pol)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->initCheck();
+}
+
+static audio_io_handle_t ap_get_output(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ 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, format, channelMask,
+ (AudioSystem::output_flags)flags,
+ offloadInfo);
+}
+
+static int ap_start_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->startOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static int ap_stop_output(struct audio_policy *pol, audio_io_handle_t output,
+ audio_stream_type_t stream, int session)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->stopOutput(output, (AudioSystem::stream_type)stream,
+ session);
+}
+
+static void ap_release_output(struct audio_policy *pol,
+ audio_io_handle_t output)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->releaseOutput(output);
+}
+
+static audio_io_handle_t ap_get_input(struct audio_policy *pol, audio_source_t inputSource,
+ uint32_t sampling_rate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_in_acoustics_t acoustics)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->getInput((int) inputSource, sampling_rate, format, channelMask,
+ (AudioSystem::audio_in_acoustics)acoustics);
+}
+
+static int ap_start_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->startInput(input);
+}
+
+static int ap_stop_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->stopInput(input);
+}
+
+static void ap_release_input(struct audio_policy *pol, audio_io_handle_t input)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->releaseInput(input);
+}
+
+static void ap_init_stream_volume(struct audio_policy *pol,
+ audio_stream_type_t stream, int index_min,
+ int index_max)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ lap->apm->initStreamVolume((AudioSystem::stream_type)stream, index_min,
+ index_max);
+}
+
+static int ap_set_stream_volume_index(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_get_stream_volume_index(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ AUDIO_DEVICE_OUT_DEFAULT);
+}
+
+static int ap_set_stream_volume_index_for_device(struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int index,
+ audio_devices_t device)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ device);
+}
+
+static int ap_get_stream_volume_index_for_device(const struct audio_policy *pol,
+ audio_stream_type_t stream,
+ int *index,
+ audio_devices_t device)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStreamVolumeIndex((AudioSystem::stream_type)stream,
+ index,
+ device);
+}
+
+static uint32_t ap_get_strategy_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getStrategyForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_devices_t ap_get_devices_for_stream(const struct audio_policy *pol,
+ audio_stream_type_t stream)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ return lap->apm->getDevicesForStream((AudioSystem::stream_type)stream);
+}
+
+static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->getOutputForEffect(desc);
+}
+
+static int ap_register_effect(struct audio_policy *pol,
+ const struct effect_descriptor_s *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->registerEffect(desc, io, strategy, session, id);
+}
+
+static int ap_unregister_effect(struct audio_policy *pol, int id)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->unregisterEffect(id);
+}
+
+static int ap_set_effect_enabled(struct audio_policy *pol, int id, bool enabled)
+{
+ struct legacy_audio_policy *lap = to_lap(pol);
+ return lap->apm->setEffectEnabled(id, enabled);
+}
+
+static bool ap_is_stream_active(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->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);
+ return lap->apm->isSourceActive(source);
+}
+
+static int ap_dump(const struct audio_policy *pol, int fd)
+{
+ const struct legacy_audio_policy *lap = to_clap(pol);
+ 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,
+ struct audio_policy **ap)
+{
+ struct legacy_audio_policy *lap;
+ int ret;
+
+ if (!service || !aps_ops)
+ return -EINVAL;
+
+ lap = (struct legacy_audio_policy *)calloc(1, sizeof(*lap));
+ if (!lap)
+ return -ENOMEM;
+
+ lap->policy.set_device_connection_state = ap_set_device_connection_state;
+ lap->policy.get_device_connection_state = ap_get_device_connection_state;
+ lap->policy.set_phone_state = ap_set_phone_state;
+ lap->policy.set_ringer_mode = ap_set_ringer_mode;
+ lap->policy.set_force_use = ap_set_force_use;
+ lap->policy.get_force_use = ap_get_force_use;
+ lap->policy.set_can_mute_enforced_audible =
+ ap_set_can_mute_enforced_audible;
+ lap->policy.init_check = ap_init_check;
+ lap->policy.get_output = ap_get_output;
+ lap->policy.start_output = ap_start_output;
+ lap->policy.stop_output = ap_stop_output;
+ lap->policy.release_output = ap_release_output;
+ lap->policy.get_input = ap_get_input;
+ lap->policy.start_input = ap_start_input;
+ lap->policy.stop_input = ap_stop_input;
+ lap->policy.release_input = ap_release_input;
+ lap->policy.init_stream_volume = ap_init_stream_volume;
+ lap->policy.set_stream_volume_index = ap_set_stream_volume_index;
+ lap->policy.get_stream_volume_index = ap_get_stream_volume_index;
+ lap->policy.set_stream_volume_index_for_device = ap_set_stream_volume_index_for_device;
+ lap->policy.get_stream_volume_index_for_device = ap_get_stream_volume_index_for_device;
+ lap->policy.get_strategy_for_stream = ap_get_strategy_for_stream;
+ lap->policy.get_devices_for_stream = ap_get_devices_for_stream;
+ lap->policy.get_output_for_effect = ap_get_output_for_effect;
+ lap->policy.register_effect = ap_register_effect;
+ 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;
+ lap->service_client =
+ new AudioPolicyCompatClient(aps_ops, service);
+ if (!lap->service_client) {
+ ret = -ENOMEM;
+ goto err_new_compat_client;
+ }
+
+ lap->apm = createAudioPolicyManager(lap->service_client);
+ if (!lap->apm) {
+ ret = -ENOMEM;
+ goto err_create_apm;
+ }
+
+ *ap = &lap->policy;
+ return 0;
+
+err_create_apm:
+ delete lap->service_client;
+err_new_compat_client:
+ free(lap);
+ *ap = NULL;
+ return ret;
+}
+
+static int destroy_legacy_ap(const struct audio_policy_device *ap_dev,
+ struct audio_policy *ap)
+{
+ struct legacy_audio_policy *lap = to_lap(ap);
+
+ if (!lap)
+ return 0;
+
+ if (lap->apm)
+ destroyAudioPolicyManager(lap->apm);
+ if (lap->service_client)
+ delete lap->service_client;
+ free(lap);
+ return 0;
+}
+
+static int legacy_ap_dev_close(hw_device_t* device)
+{
+ if (device)
+ free(device);
+ return 0;
+}
+
+static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ struct legacy_ap_device *dev;
+
+ if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
+ return -EINVAL;
+
+ dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
+ if (!dev)
+ return -ENOMEM;
+
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = legacy_ap_dev_close;
+ dev->device.create_audio_policy = create_legacy_ap;
+ dev->device.destroy_audio_policy = destroy_legacy_ap;
+
+ *device = &dev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t legacy_ap_module_methods = {
+ .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},
+ },
+ },
+};
+
+}; // extern "C"
+
+}; // namespace android_audio_legacy
diff --git a/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h b/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h
new file mode 100644
index 0000000..eac40dc
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioHardwareBase.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_HARDWARE_BASE_H
+#define ANDROID_AUDIO_HARDWARE_BASE_H
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include <system/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioHardwareBase is a convenient base class used for implementing the
+ * AudioHardwareInterface interface.
+ */
+class AudioHardwareBase : public AudioHardwareInterface
+{
+public:
+ AudioHardwareBase();
+ virtual ~AudioHardwareBase() { }
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, IN_CALL
+ * when a telephony call is in progress, IN_COMMUNICATION when a VoIP call is in progress.
+ */
+ virtual status_t setMode(int mode);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+ virtual status_t getMasterVolume(float *volume);
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const Vector<String16>& args);
+
+protected:
+ /** returns true if the given mode maps to a telephony or VoIP call is in progress */
+ virtual bool isModeInCall(int mode)
+ { return ((mode == AudioSystem::MODE_IN_CALL)
+ || (mode == AudioSystem::MODE_IN_COMMUNICATION)); };
+ /** returns true if a telephony or VoIP call is in progress */
+ virtual bool isInCall() { return isModeInCall(mMode); };
+ int mMode;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_BASE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h b/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
new file mode 100644
index 0000000..6328063
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_HARDWARE_INTERFACE_H
+#define ANDROID_AUDIO_HARDWARE_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include <media/IAudioFlinger.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <cutils/bitops.h>
+
+namespace android_audio_legacy {
+ using android::Vector;
+ using android::String16;
+ using android::String8;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioStreamOut is the abstraction interface for the audio output hardware.
+ *
+ * It provides information about various properties of the audio output hardware driver.
+ */
+class AudioStreamOut {
+public:
+ virtual ~AudioStreamOut() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** returns size of output buffer - eg. 4800 */
+ virtual size_t bufferSize() const = 0;
+
+ /**
+ * returns the output channel mask
+ */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AudioSystem:PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const { return audio_channel_count_from_out_mask(channels())*
+ ((format()==AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); }
+
+ /**
+ * return the audio hardware driver latency in milli seconds.
+ */
+ virtual uint32_t latency() const = 0;
+
+ /**
+ * Use this method in situations where audio mixing is done in the
+ * hardware. This method serves as a direct interface with hardware,
+ * allowing you to directly set the volume as apposed to via the framework.
+ * This method might produce multiple PCM outputs or hardware accelerated
+ * codecs, such as MP3 or AAC.
+ */
+ virtual status_t setVolume(float left, float right) = 0;
+
+ /** write audio buffer to driver. Returns number of bytes written */
+ virtual ssize_t write(const void* buffer, size_t bytes) = 0;
+
+ /**
+ * Put the audio hardware output into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby() = 0;
+
+ /** dump the state of the audio output device */
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ // set/get audio output parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the output in standby and then change the parameter value.
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+ // return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby
+ virtual status_t getRenderPosition(uint32_t *dspFrames) = 0;
+
+ /**
+ * get the local time at which the next write to the audio driver will be
+ * presented
+ */
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
+ /**
+ * Return a recent count of the number of audio frames presented to an external observer.
+ */
+ virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
+
+};
+
+/**
+ * AudioStreamIn is the abstraction interface for the audio input hardware.
+ *
+ * It defines the various properties of the audio hardware input driver.
+ */
+class AudioStreamIn {
+public:
+ virtual ~AudioStreamIn() = 0;
+
+ /** return audio sampling rate in hz - eg. 44100 */
+ virtual uint32_t sampleRate() const = 0;
+
+ /** return the input buffer size allowed by audio driver */
+ virtual size_t bufferSize() const = 0;
+
+ /** return input channel mask */
+ virtual uint32_t channels() const = 0;
+
+ /**
+ * return audio format in 8bit or 16bit PCM format -
+ * eg. AudioSystem:PCM_16_BIT
+ */
+ virtual int format() const = 0;
+
+ /**
+ * return the frame size (number of bytes per sample).
+ */
+ uint32_t frameSize() const { return audio_channel_count_from_in_mask(channels())*
+ ((format()==AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(int8_t)); }
+
+ /** set the input gain for the audio driver. This method is for
+ * for future use */
+ virtual status_t setGain(float gain) = 0;
+
+ /** read audio buffer in from audio driver */
+ virtual ssize_t read(void* buffer, ssize_t bytes) = 0;
+
+ /** dump the state of the audio input device */
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ /**
+ * Put the audio hardware input into standby mode. Returns
+ * status based on include/utils/Errors.h
+ */
+ virtual status_t standby() = 0;
+
+ // set/get audio input parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ // If the implementation does not accept a parameter change while the output is
+ // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+ // The audio flinger will put the input in standby and then change the parameter value.
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+
+ // Return the number of input frames lost in the audio driver since the last call of this function.
+ // Audio driver is expected to reset the value to 0 and restart counting upon returning the current value by this function call.
+ // Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers.
+ // Unit: the number of input audio frames
+ virtual unsigned int getInputFramesLost() const = 0;
+
+ virtual status_t addAudioEffect(effect_handle_t effect) = 0;
+ virtual status_t removeAudioEffect(effect_handle_t effect) = 0;
+};
+
+/**
+ * AudioHardwareInterface.h defines the interface to the audio hardware abstraction layer.
+ *
+ * The interface supports setting and getting parameters, selecting audio routing
+ * paths, and defining input and output streams.
+ *
+ * AudioFlinger initializes the audio hardware and immediately opens an output stream.
+ * You can set Audio routing to output to handset, speaker, Bluetooth, or a headset.
+ *
+ * The audio input stream is initialized when AudioFlinger is called to carry out
+ * a record operation.
+ */
+class AudioHardwareInterface
+{
+public:
+ virtual ~AudioHardwareInterface() {}
+
+ /**
+ * check to see if the audio hardware interface has been initialized.
+ * return status based on values defined in include/utils/Errors.h
+ */
+ virtual status_t initCheck() = 0;
+
+ /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+ virtual status_t setVoiceVolume(float volume) = 0;
+
+ /**
+ * set the audio volume for all audio activities other than voice call.
+ * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+ * the software mixer will emulate this capability.
+ */
+ virtual status_t setMasterVolume(float volume) = 0;
+
+ /**
+ * Get the current master volume value for the HAL, if the HAL supports
+ * master volume control. AudioFlinger will query this value from the
+ * primary audio HAL when the service starts and use the value for setting
+ * the initial master volume across all HALs.
+ */
+ virtual status_t getMasterVolume(float *volume) = 0;
+
+ /**
+ * setMode is called when the audio mode changes. NORMAL mode is for
+ * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+ * when a call is in progress.
+ */
+ virtual status_t setMode(int mode) = 0;
+
+ // mic mute
+ virtual status_t setMicMute(bool state) = 0;
+ virtual status_t getMicMute(bool* state) = 0;
+
+ // set/get global audio parameters
+ virtual status_t setParameters(const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(const String8& keys) = 0;
+
+ // Returns audio input buffer size according to parameters passed or 0 if one of the
+ // parameters is not supported
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+ /** This method creates and opens the audio hardware output stream */
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0) = 0;
+ virtual AudioStreamOut* openOutputStreamWithFlags(
+ uint32_t devices,
+ audio_output_flags_t flags=(audio_output_flags_t)0,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0) = 0;
+ virtual void closeOutputStream(AudioStreamOut* out) = 0;
+
+ /** This method creates and opens the audio hardware input stream */
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics) = 0;
+ virtual void closeInputStream(AudioStreamIn* in) = 0;
+
+ /**This method dumps the state of the audio hardware */
+ virtual status_t dumpState(int fd, const Vector<String16>& args) = 0;
+
+ virtual status_t setMasterMute(bool muted) = 0;
+
+ static AudioHardwareInterface* create();
+
+ virtual int createAudioPatch(unsigned int num_sources,
+ const struct audio_port_config *sources,
+ unsigned int num_sinks,
+ const struct audio_port_config *sinks,
+ audio_patch_handle_t *handle) = 0;
+
+ virtual int releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+ virtual int getAudioPort(struct audio_port *port) = 0;
+
+ virtual int setAudioPortConfig(const struct audio_port_config *config) = 0;
+
+protected:
+
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void);
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_INTERFACE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h b/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h
new file mode 100644
index 0000000..da03ee3
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioPolicyInterface.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYINTERFACE_H
+#define ANDROID_AUDIOPOLICYINTERFACE_H
+
+#include <media/AudioSystem.h>
+#include <media/ToneGenerator.h>
+#include <utils/String8.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+#include <hardware/audio_policy.h>
+
+namespace android_audio_legacy {
+ using android::Vector;
+ using android::String8;
+ using android::ToneGenerator;
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces
+// between the platform specific audio policy manager and Android generic audio policy manager.
+// The platform specific audio policy manager must implement methods of the AudioPolicyInterface class.
+// This implementation makes use of the AudioPolicyClientInterface to control the activity and
+// configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+// - keep track of current system state (removable device connections, phone state, user requests...).
+// System state changes and user actions are notified to audio policy manager with methods of the AudioPolicyInterface.
+// - process getOutput() queries received when AudioTrack objects are created: Those queries
+// return a handler on an output that has been selected, configured and opened by the audio policy manager and that
+// must be used by the AudioTrack when registering to the AudioFlinger with the createTrack() method.
+// When the AudioTrack object is released, a putOutput() query is received and the audio policy manager can decide
+// to close or reconfigure the output depending on other streams using this output and current system state.
+// - similarly process getInput() and putInput() queries received from AudioRecord objects and configure audio inputs.
+// - process volume control requests: the stream volume is converted from an index value (received from UI) to a float value
+// applicable to each output as a function of platform specific settings and current output route (destination device). It
+// also make sure that streams are not muted if not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors (as for libaudio.so)
+// and is linked with libaudioflinger.so
+
+
+// Audio Policy Manager Interface
+class AudioPolicyInterface
+{
+
+public:
+ virtual ~AudioPolicyInterface() {}
+ //
+ // configuration functions
+ //
+
+ // indicate a change in device connection status
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address) = 0;
+ // retrieve a device connection status
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+ const char *device_address) = 0;
+ // indicate a change in phone state. Valid phones states are defined by AudioSystem::audio_mode
+ virtual void setPhoneState(int state) = 0;
+ // force using a specific device category for the specified usage
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+ // retrieve current device category forced for a given usage
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+ // set a system property (e.g. camera sound always audible)
+ virtual void setSystemProperty(const char* property, const char* value) = 0;
+ // check proper initialization
+ virtual status_t initCheck() = 0;
+
+ //
+ // Audio routing query functions
+ //
+
+ // request an output appropriate for playback of the supplied stream type and parameters
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t *offloadInfo) = 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,
+ int session = 0) = 0;
+ // indicates to the audio policy manager that the output stops being used by corresponding stream.
+ virtual status_t stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session = 0) = 0;
+ // releases the output.
+ virtual void releaseOutput(audio_io_handle_t output) = 0;
+
+ // request an input appropriate for record from the supplied device with supplied parameters.
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics) = 0;
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input) = 0;
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input) = 0;
+ // releases the input.
+ virtual void releaseInput(audio_io_handle_t input) = 0;
+
+ //
+ // volume control functions
+ //
+
+ // initialises stream volume conversion parameters by specifying volume index range.
+ virtual void initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax) = 0;
+
+ // sets the new stream volume at a level corresponding to the supplied index for the
+ // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+ // setting volume for all devices
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream,
+ int index,
+ audio_devices_t device) = 0;
+
+ // retrieve current volume index for the specified stream and the
+ // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+ // querying the volume of the active device.
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream,
+ int *index,
+ audio_devices_t device) = 0;
+
+ // return the strategy corresponding to a given stream type
+ virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
+
+ // return the enabled output devices for the given stream type
+ virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream) = 0;
+
+ // Audio effect management
+ virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
+ virtual status_t registerEffect(const effect_descriptor_t *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id) = 0;
+ virtual status_t unregisterEffect(int id) = 0;
+ 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;
+};
+
+
+// Audio Policy client Interface
+class AudioPolicyClientInterface
+{
+public:
+ virtual ~AudioPolicyClientInterface() {}
+
+ //
+ // Audio HW module functions
+ //
+
+ // loads a HW module.
+ virtual audio_module_handle_t loadHwModule(const char *name) = 0;
+
+ //
+ // Audio output Control functions
+ //
+
+ // opens an audio output with the requested parameters. The parameter values can indicate to use the default values
+ // in case the audio policy manager has no specific requirements for the output being opened.
+ // When the function returns, the parameter values reflect the actual values used by the audio hardware output stream.
+ // The audio policy manager can check if the proposed parameters are suitable or not and act accordingly.
+ virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ 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;
+ // closes the output stream
+ virtual status_t closeOutput(audio_io_handle_t output) = 0;
+ // suspends the output. When an output is suspended, the corresponding audio hardware output stream is placed in
+ // standby and the AudioTracks attached to the mixer thread are still processed but the output mix is discarded.
+ virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+ // restores a suspended output.
+ virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+ //
+ // Audio input Control functions
+ //
+
+ // opens an audio input
+ virtual audio_io_handle_t openInput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask) = 0;
+ // closes an audio input
+ virtual status_t closeInput(audio_io_handle_t input) = 0;
+ //
+ // misc control functions
+ //
+
+ // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes
+ // for each output (destination device) it is attached to.
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0) = 0;
+
+ // invalidate a stream type, causing a reroute to an unspecified new output
+ virtual status_t invalidateStream(AudioSystem::stream_type stream) = 0;
+
+ // function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0) = 0;
+ // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
+
+ // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing
+ // over a telephony device during a phone call.
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) = 0;
+ virtual status_t stopTone() = 0;
+
+ // set down link audio volume.
+ virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
+
+ // move effect to the specified output
+ virtual status_t moveEffects(int session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput) = 0;
+
+};
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface);
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYINTERFACE_H
diff --git a/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h b/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h
new file mode 100644
index 0000000..cf03f78
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioPolicyManagerBase.h
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+
+
+namespace android_audio_legacy {
+ using android::KeyedVector;
+ using android::DefaultKeyedVector;
+ using android::SortedVector;
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#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
+// and override methods for which the platform specific behavior differs from the implementation
+// in AudioPolicyManagerBase. Even if no specific behavior is required, the AudioPolicyManager
+// class must be implemented as well as the class factory function createAudioPolicyManager()
+// and provided in a shared library libaudiopolicy.so.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManagerBase: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+ AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface);
+ virtual ~AudioPolicyManagerBase();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+ const char *device_address);
+ virtual void setPhoneState(int state);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual status_t initCheck();
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::output_flags flags,
+ const audio_offload_info_t *offloadInfo);
+ virtual status_t startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session = 0);
+ virtual status_t stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session = 0);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual void closeAllInputs();
+ virtual void initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream,
+ int index,
+ audio_devices_t device);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream,
+ int *index,
+ audio_devices_t device);
+
+ // return the strategy corresponding to a given stream type
+ virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
+
+ // 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 = NULL);
+ virtual status_t registerEffect(const effect_descriptor_t *desc,
+ audio_io_handle_t io,
+ uint32_t strategy,
+ int session,
+ int id);
+ virtual status_t unregisterEffect(int id);
+ 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 {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_DTMF,
+ STRATEGY_ENFORCED_AUDIBLE,
+ NUM_STRATEGIES
+ };
+
+ // 4 points to define the volume attenuation curve, each characterized by the volume
+ // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+ // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+
+ enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
+
+ class VolumeCurvePoint
+ {
+ public:
+ int mIndex;
+ float mDBAttenuation;
+ };
+
+ // device categories used for volume curve management.
+ enum device_category {
+ DEVICE_CATEGORY_HEADSET,
+ DEVICE_CATEGORY_SPEAKER,
+ DEVICE_CATEGORY_EARPIECE,
+ DEVICE_CATEGORY_CNT
+ };
+
+ class IOProfile;
+
+ class HwModule {
+ public:
+ HwModule(const char *name);
+ ~HwModule();
+
+ void dump(int fd);
+
+ const char *const mName; // base name of the audio HW module (primary, a2dp ...)
+ audio_module_handle_t mHandle;
+ Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
+ Vector <IOProfile *> mInputProfiles; // input profiles exposed by this module
+ };
+
+ // the IOProfile class describes the capabilities of an output or input stream.
+ // It is currently assumed that all combination of listed parameters are supported.
+ // It is used by the policy manager to determine if an output or input is suitable for
+ // a given use case, open/close it accordingly and connect/disconnect audio tracks
+ // to/from it.
+ class IOProfile
+ {
+ public:
+ IOProfile(HwModule *module);
+ ~IOProfile();
+
+ bool isCompatibleProfile(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_output_flags_t flags) const;
+
+ void dump(int fd);
+ void log();
+
+ // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+ // indicates the supported parameters should be read from the output stream
+ // after it is opened for the first time
+ Vector <uint32_t> mSamplingRates; // supported sampling rates
+ Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+ Vector <audio_format_t> mFormats; // supported audio formats
+ audio_devices_t mSupportedDevices; // supported devices (devices this output can be
+ // routed to)
+ audio_output_flags_t mFlags; // attribute flags (e.g primary output,
+ // direct output...). For outputs only.
+ HwModule *mModule; // audio HW module exposing this I/O stream
+ };
+
+ // default volume curve
+ static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // default volume curve for media strategy
+ static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+ // volume curve for media strategy on speakers
+ 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];
+ // default volume curves per stream and device category. See initializeVolumeCurves()
+ static const VolumeCurvePoint *sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES][DEVICE_CATEGORY_CNT];
+
+ // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+ // and keep track of the usage of this output by each audio stream type.
+ class AudioOutputDescriptor
+ {
+ public:
+ AudioOutputDescriptor(const IOProfile *profile);
+
+ status_t dump(int fd);
+
+ 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 = 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; //
+ audio_format_t mFormat; //
+ audio_channel_mask_t mChannelMask; // output configuration
+ uint32_t mLatency; //
+ audio_output_flags_t mFlags; //
+ audio_devices_t mDevice; // current device this output is routed to
+ uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
+ nsecs_t mStopTime[AudioSystem::NUM_STREAM_TYPES];
+ AudioOutputDescriptor *mOutput1; // used by duplicated outputs: first output
+ AudioOutputDescriptor *mOutput2; // used by duplicated outputs: second output
+ float mCurVolume[AudioSystem::NUM_STREAM_TYPES]; // current stream volume
+ int mMuteCount[AudioSystem::NUM_STREAM_TYPES]; // mute request counter
+ 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)
+ bool mForceRouting; // Next routing for this output will be forced as current device routed is null
+ };
+
+ // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+ // and keep track of the usage of this input.
+ class AudioInputDescriptor
+ {
+ public:
+ AudioInputDescriptor(const IOProfile *profile);
+
+ status_t dump(int fd);
+
+ audio_io_handle_t mId; // input handle
+ uint32_t mSamplingRate; //
+ audio_format_t mFormat; // input configuration
+ audio_channel_mask_t mChannelMask; //
+ audio_devices_t mDevice; // current device this input is routed to
+ uint32_t mRefCount; // number of AudioRecord clients using this output
+ int mInputSource; // input source selected by application (mediarecorder.h)
+ const IOProfile *mProfile; // I/O profile this output derives from
+ };
+
+ // stream descriptor used for volume control
+ class StreamDescriptor
+ {
+ public:
+ StreamDescriptor();
+
+ int getVolumeIndex(audio_devices_t device);
+ void dump(int fd);
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ KeyedVector<audio_devices_t, int> mIndexCur; // current volume index per device
+ bool mCanBeMuted; // true is the stream can be muted
+
+ const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
+ };
+
+ // stream descriptor used for volume control
+ class EffectDescriptor
+ {
+ public:
+
+ status_t dump(int fd);
+
+ int mIo; // io the effect is attached to
+ routing_strategy mStrategy; // routing strategy the effect is associated to
+ int mSession; // audio session the effect is on
+ effect_descriptor_t mDesc; // effect descriptor
+ bool mEnabled; // enabled state: CPU load being used or not
+ };
+
+ void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
+ void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc);
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[],
+ // otherwise it is determine by current state
+ // (device connected,phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDevicesAndOutputs() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache);
+
+ // change the route of the specified output. Returns the number of ms we have slept to
+ // allow new routing to take effect in certain cases.
+ uint32_t setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force = false,
+ int delayMs = 0);
+
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+ // return io handle of active input or 0 if no input is active
+ // Only considers inputs from physical devices (e.g. main mic, headset mic) when
+ // ignoreVirtualInputs is true.
+ audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+ // initialize volume curves for each strategy and device category
+ void initializeVolumeCurves();
+
+ // compute the actual volume for a given stream according to the requested index and a particular
+ // device
+ virtual float computeVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device);
+
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // apply all stream volumes to the specified output and device
+ void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // Mute or unmute all streams handled by the specified strategy on the specified output
+ void setStrategyMute(routing_strategy strategy,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs = 0,
+ audio_devices_t device = (audio_devices_t)0);
+
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(int stream,
+ bool on,
+ audio_io_handle_t output,
+ int delayMs = 0,
+ audio_devices_t device = (audio_devices_t)0);
+
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(int stream, bool starting, bool stateChange);
+
+ // true if device is in a telephony or VoIP call
+ virtual bool isInCall();
+
+ // true if given state represents a device in a telephony or VoIP call
+ virtual bool isStateInCall(int state);
+
+ // when a device is connected, checks if an open output can be routed
+ // to this device. If none is open, tries to open one of the available outputs.
+ // Returns an output suitable to this device or 0.
+ // when a device is disconnected, checks if an output is not used any more and
+ // returns its handle if any.
+ // transfers the audio tracks and effects from one output thread to another accordingly.
+ status_t checkOutputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& outputs,
+ const String8 paramStr);
+
+ status_t checkInputsForDevice(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ SortedVector<audio_io_handle_t>& inputs,
+ const String8 paramStr);
+
+ // close an output and its companion duplicating output.
+ void closeOutput(audio_io_handle_t output);
+
+ // checks and if necessary changes outputs used for all strategies.
+ // must be called every time a condition that affects the output choice for a given strategy
+ // changes: connected device, phone state, force use...
+ // Must be called before updateDevicesAndOutputs()
+ void checkOutputForStrategy(routing_strategy strategy);
+
+ // Same as checkOutputForStrategy() but for a all strategies in order of priority
+ void checkOutputForAllStrategies();
+
+ // manages A2DP output suspend/restore according to phone state and BT SCO usage
+ void checkA2dpSuspend();
+
+ // returns the A2DP output handle if it is open or 0 otherwise
+ audio_io_handle_t getA2dpOutput();
+
+ // selects the most appropriate device on output for current state
+ // must be called every time a condition that affects the device choice for a given output is
+ // changed: connected device, phone state, force use, output start, output stop..
+ // see getDeviceForStrategy() for the use of fromCache parameter
+
+ audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+ // updates cache of device used by all strategies (mDeviceForStrategy[])
+ // must be called every time a condition that affects the device choice for a given strategy is
+ // changed: connected device, phone state, force use...
+ // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+ // Must be called after checkOutputForAllStrategies()
+
+ void updateDevicesAndOutputs();
+
+ virtual uint32_t getMaxEffectsCpuLoad();
+ virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+ status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled);
+
+ // returns the category the device belongs to with regard to volume curve management
+ static device_category getDeviceCategory(audio_devices_t device);
+
+ // extract one device relevant for volume control from multiple device selection
+ static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+ SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs);
+ bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+ SortedVector<audio_io_handle_t>& outputs2);
+
+ // mute/unmute strategies using an incompatible device combination
+ // if muting, wait for the audio in pcm buffer to be drained before proceeding
+ // if unmuting, unmute only after the specified delay
+ // Returns the number of ms waited
+ uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+ audio_devices_t prevDevice,
+ uint32_t delayMs);
+
+ audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+ AudioSystem::output_flags flags);
+ IOProfile *getInputProfile(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask);
+ IOProfile *getProfileForDirectOutput(audio_devices_t device,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_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);
+ void loadFormats(char *name, IOProfile *profile);
+ void loadOutChannels(char *name, IOProfile *profile);
+ void loadInChannels(char *name, IOProfile *profile);
+ status_t loadOutput(cnode *root, HwModule *module);
+ status_t loadInput(cnode *root, HwModule *module);
+ void loadHwModule(cnode *root);
+ void loadHwModules(cnode *root);
+ void loadGlobalConfig(cnode *root);
+ status_t loadAudioPolicyConfig(const char *path);
+ void defaultAudioPolicyConfig(void);
+
+
+ AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
+ audio_io_handle_t mPrimaryOutput; // primary output handle
+ // list of descriptors for outputs currently opened
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;
+ // copy of mOutputs before setDeviceConnectionState() opens new outputs
+ // reset to mOutputs when updateDevicesAndOutputs() is called.
+ DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mPreviousOutputs;
+
+ // list of input descriptors currently opened
+ DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs;
+
+ audio_devices_t mAvailableOutputDevices; // bit field of all available output devices
+ audio_devices_t mAvailableInputDevices; // bit field of all available input devices
+ // without AUDIO_DEVICE_BIT_IN to allow direct bit
+ // field comparisons
+ int mPhoneState; // current phone state
+ AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
+
+ StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
+ String8 mA2dpDeviceAddress; // A2DP device MAC address
+ String8 mScoDeviceAddress; // SCO device MAC address
+ String8 mUsbOutCardAndDevice; // USB audio ALSA card and device numbers:
+ // card=<card_number>;device=<><device_number>
+ bool mLimitRingtoneVolume; // limit ringtone volume to music volume if headset connected
+ audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+ float mLastVoiceVolume; // last voice volume value sent to audio HAL
+
+ // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+ static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+ // Maximum memory allocated to audio effects in KB
+ static const uint32_t MAX_EFFECTS_MEMORY = 512;
+ uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+ uint32_t mTotalEffectsMemory; // current memory used by effects
+ KeyedVector<int, EffectDescriptor *> mEffects; // list of registered audio effects
+ bool mA2dpSuspended; // true if A2DP output is suspended
+ bool mHasA2dp; // true on platforms with support for bluetooth A2DP
+ bool mHasUsb; // true on platforms with support for USB audio
+ bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix
+ 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;
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannels;
+ uint32_t mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+private:
+ static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+ int indexInUi);
+ // updates device caching and output for streams that can influence the
+ // routing of notifications
+ void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+ static bool isVirtualInputDevice(audio_devices_t device);
+};
+
+};
diff --git a/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h b/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
new file mode 100644
index 0000000..524e798
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/AudioSystemLegacy.h
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOSYSTEM_LEGACY_H_
+#define ANDROID_AUDIOSYSTEM_LEGACY_H_
+
+#include <utils/Errors.h>
+#include <media/AudioParameter.h>
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android_audio_legacy {
+
+using android::status_t;
+using android::AudioParameter;
+
+enum {
+ OK = android::OK,
+ NO_ERROR = android::NO_ERROR,
+
+ UNKNOWN_ERROR = android::UNKNOWN_ERROR,
+
+ NO_MEMORY = android::NO_MEMORY,
+ INVALID_OPERATION = android::INVALID_OPERATION,
+ BAD_VALUE = android::BAD_VALUE,
+ BAD_TYPE = android::BAD_TYPE,
+ NAME_NOT_FOUND = android::NAME_NOT_FOUND,
+ PERMISSION_DENIED = android::PERMISSION_DENIED,
+ NO_INIT = android::NO_INIT,
+ ALREADY_EXISTS = android::ALREADY_EXISTS,
+ DEAD_OBJECT = android::DEAD_OBJECT,
+ FAILED_TRANSACTION = android::FAILED_TRANSACTION,
+ BAD_INDEX = android::BAD_INDEX,
+ NOT_ENOUGH_DATA = android::NOT_ENOUGH_DATA,
+ WOULD_BLOCK = android::WOULD_BLOCK,
+ TIMED_OUT = android::TIMED_OUT,
+ UNKNOWN_TRANSACTION = android::UNKNOWN_TRANSACTION,
+};
+
+enum audio_source {
+ AUDIO_SOURCE_DEFAULT = 0,
+ AUDIO_SOURCE_MIC = 1,
+ AUDIO_SOURCE_VOICE_UPLINK = 2,
+ AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+ AUDIO_SOURCE_VOICE_CALL = 4,
+ AUDIO_SOURCE_CAMCORDER = 5,
+ AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+ AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+ AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_COMMUNICATION,
+
+ AUDIO_SOURCE_LIST_END // must be last - used to validate audio source type
+};
+
+class AudioSystem {
+public:
+#if 1
+ enum stream_type {
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+ DTMF = 8,
+ TTS = 9,
+ NUM_STREAM_TYPES
+ };
+
+ // Audio sub formats (see AudioSystem::audio_format).
+ enum pcm_sub_format {
+ PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
+ PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
+ };
+
+ enum audio_sessions {
+ SESSION_OUTPUT_STAGE = AUDIO_SESSION_OUTPUT_STAGE,
+ SESSION_OUTPUT_MIX = AUDIO_SESSION_OUTPUT_MIX,
+ };
+
+ // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
+ // bit rate, stereo mode, version...
+ enum mp3_sub_format {
+ //TODO
+ };
+
+ // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
+ // encoding mode for recording...
+ enum amr_sub_format {
+ //TODO
+ };
+
+ // AAC sub format field definition: specify profile or bitrate for recording...
+ enum aac_sub_format {
+ //TODO
+ };
+
+ // VORBIS sub format field definition: specify quality for recording...
+ enum vorbis_sub_format {
+ //TODO
+ };
+
+ // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
+ // The main format indicates the main codec type. The sub format field indicates options and parameters
+ // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
+ // or profile. It can also be used for certain formats to give informations not present in the encoded
+ // audio stream (e.g. octet alignement for AMR).
+ enum audio_format {
+ INVALID_FORMAT = -1,
+ FORMAT_DEFAULT = 0,
+ PCM = 0x00000000, // must be 0 for backward compatibility
+ MP3 = 0x01000000,
+ AMR_NB = 0x02000000,
+ AMR_WB = 0x03000000,
+ AAC = 0x04000000,
+ HE_AAC_V1 = 0x05000000,
+ HE_AAC_V2 = 0x06000000,
+ VORBIS = 0x07000000,
+ MAIN_FORMAT_MASK = 0xFF000000,
+ SUB_FORMAT_MASK = 0x00FFFFFF,
+ // Aliases
+ PCM_16_BIT = (PCM|PCM_SUB_16_BIT),
+ PCM_8_BIT = (PCM|PCM_SUB_8_BIT)
+ };
+
+ enum audio_channels {
+ // output channels
+ CHANNEL_OUT_FRONT_LEFT = 0x1,
+ CHANNEL_OUT_FRONT_RIGHT = 0x2,
+ CHANNEL_OUT_FRONT_CENTER = 0x4,
+ CHANNEL_OUT_LOW_FREQUENCY = 0x8,
+ CHANNEL_OUT_BACK_LEFT = 0x10,
+ CHANNEL_OUT_BACK_RIGHT = 0x20,
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40,
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+ CHANNEL_OUT_BACK_CENTER = 0x100,
+ CHANNEL_OUT_SIDE_LEFT = 0x200,
+ CHANNEL_OUT_SIDE_RIGHT = 0x400,
+ CHANNEL_OUT_TOP_CENTER = 0x800,
+ CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000,
+ CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000,
+ CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000,
+ CHANNEL_OUT_TOP_BACK_LEFT = 0x8000,
+ CHANNEL_OUT_TOP_BACK_CENTER = 0x10000,
+ CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000,
+
+ CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+ CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+ CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+ CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
+ CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT),
+ CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT |
+ CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER |
+ CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT | CHANNEL_OUT_TOP_CENTER |
+ CHANNEL_OUT_TOP_FRONT_LEFT | CHANNEL_OUT_TOP_FRONT_CENTER |
+ CHANNEL_OUT_TOP_FRONT_RIGHT | CHANNEL_OUT_TOP_BACK_LEFT |
+ CHANNEL_OUT_TOP_BACK_CENTER | CHANNEL_OUT_TOP_BACK_RIGHT),
+
+ // input channels
+ CHANNEL_IN_LEFT = 0x4,
+ CHANNEL_IN_RIGHT = 0x8,
+ CHANNEL_IN_FRONT = 0x10,
+ CHANNEL_IN_BACK = 0x20,
+ CHANNEL_IN_LEFT_PROCESSED = 0x40,
+ CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+ CHANNEL_IN_FRONT_PROCESSED = 0x100,
+ CHANNEL_IN_BACK_PROCESSED = 0x200,
+ CHANNEL_IN_PRESSURE = 0x400,
+ CHANNEL_IN_X_AXIS = 0x800,
+ CHANNEL_IN_Y_AXIS = 0x1000,
+ CHANNEL_IN_Z_AXIS = 0x2000,
+ CHANNEL_IN_VOICE_UPLINK = 0x4000,
+ CHANNEL_IN_VOICE_DNLINK = 0x8000,
+ CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+ CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+ CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
+ CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
+ CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
+ };
+
+ enum audio_mode {
+ MODE_INVALID = -2,
+ MODE_CURRENT = -1,
+ MODE_NORMAL = 0,
+ MODE_RINGTONE,
+ MODE_IN_CALL,
+ MODE_IN_COMMUNICATION,
+ NUM_MODES // not a valid entry, denotes end-of-list
+ };
+
+ enum audio_in_acoustics {
+ AGC_ENABLE = 0x0001,
+ AGC_DISABLE = 0,
+ NS_ENABLE = 0x0002,
+ NS_DISABLE = 0,
+ TX_IIR_ENABLE = 0x0004,
+ TX_DISABLE = 0
+ };
+
+ // DO NOT USE: the "audio_devices" enumeration below is obsolete, use type "audio_devices_t" and
+ // audio device enumeration from system/audio.h instead.
+ enum audio_devices {
+ // output devices
+ DEVICE_OUT_EARPIECE = 0x1,
+ DEVICE_OUT_SPEAKER = 0x2,
+ DEVICE_OUT_WIRED_HEADSET = 0x4,
+ DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+ DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+ DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ DEVICE_OUT_AUX_DIGITAL = 0x400,
+ DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+ DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
+ DEVICE_OUT_DEFAULT = 0x8000,
+ DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+ DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+ DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET |
+ DEVICE_OUT_DEFAULT),
+ DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+
+ // input devices
+ DEVICE_IN_COMMUNICATION = 0x10000,
+ DEVICE_IN_AMBIENT = 0x20000,
+ DEVICE_IN_BUILTIN_MIC = 0x40000,
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+ DEVICE_IN_WIRED_HEADSET = 0x100000,
+ DEVICE_IN_AUX_DIGITAL = 0x200000,
+ DEVICE_IN_VOICE_CALL = 0x400000,
+ DEVICE_IN_BACK_MIC = 0x800000,
+ DEVICE_IN_DEFAULT = 0x80000000,
+
+ DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+ DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT)
+ };
+
+ // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
+ enum output_flags {
+ OUTPUT_FLAG_INDIRECT = 0x0,
+ OUTPUT_FLAG_DIRECT = 0x1
+ };
+
+ // device categories used for setForceUse()
+ enum forced_config {
+ FORCE_NONE,
+ FORCE_SPEAKER,
+ FORCE_HEADPHONES,
+ FORCE_BT_SCO,
+ FORCE_BT_A2DP,
+ FORCE_WIRED_ACCESSORY,
+ FORCE_BT_CAR_DOCK,
+ FORCE_BT_DESK_DOCK,
+ FORCE_ANALOG_DOCK,
+ FORCE_DIGITAL_DOCK,
+ FORCE_NO_BT_A2DP,
+ FORCE_SYSTEM_ENFORCED,
+ NUM_FORCE_CONFIG,
+ FORCE_DEFAULT = FORCE_NONE
+ };
+
+ // usages used for setForceUse()
+ enum force_use {
+ FOR_COMMUNICATION,
+ FOR_MEDIA,
+ FOR_RECORD,
+ FOR_DOCK,
+ FOR_SYSTEM,
+ NUM_FORCE_USE
+ };
+
+ //
+ // AudioPolicyService interface
+ //
+
+ // device connection states used for setDeviceConnectionState()
+ enum device_connection_state {
+ DEVICE_STATE_UNAVAILABLE,
+ DEVICE_STATE_AVAILABLE,
+ NUM_DEVICE_STATES
+ };
+
+#endif
+
+ static uint32_t popCount(uint32_t u) {
+ return popcount(u);
+ }
+
+#if 1
+ static bool isOutputDevice(audio_devices device) {
+ if ((popcount(device) == 1) && ((device & ~DEVICE_OUT_ALL) == 0))
+ return true;
+ else
+ return false;
+ }
+ static bool isInputDevice(audio_devices device) {
+ if ((popcount(device) == 1) && ((device & ~DEVICE_IN_ALL) == 0))
+ return true;
+ else
+ return false;
+ }
+ static bool isA2dpDevice(audio_devices device) {
+ return audio_is_a2dp_device((audio_devices_t)device);
+ }
+ static bool isBluetoothScoDevice(audio_devices device) {
+ return audio_is_bluetooth_sco_device((audio_devices_t)device);
+ }
+ static bool isLowVisibility(stream_type stream) {
+ return audio_is_low_visibility((audio_stream_type_t)stream);
+ }
+ static bool isValidFormat(uint32_t format) {
+ return audio_is_valid_format((audio_format_t) format);
+ }
+ static bool isLinearPCM(uint32_t format) {
+ return audio_is_linear_pcm((audio_format_t) format);
+ }
+ static bool isOutputChannel(uint32_t channel) {
+ return audio_is_output_channel(channel);
+ }
+ static bool isInputChannel(uint32_t channel) {
+ return audio_is_input_channel(channel);
+ }
+
+#endif
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOSYSTEM_LEGACY_H_
diff --git a/libhardware_legacy/include/hardware_legacy/IMountService.h b/libhardware_legacy/include/hardware_legacy/IMountService.h
new file mode 100644
index 0000000..257319c
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/IMountService.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+#ifndef ANDROID_HARDWARE_IMOUNTSERVICE_H
+#define ANDROID_HARDWARE_IMOUNTSERVICE_H
+
+#include <binder/IInterface.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IMountService : public IInterface
+{
+public:
+ static const int OperationSucceeded = 0;
+ static const int OperationFailedInternalError = -1;
+ static const int OperationFailedNoMedia = -2;
+ static const int OperationFailedMediaBlank = -3;
+ static const int OperationFailedMediaCorrupt = -4;
+ static const int OperationFailedVolumeNotMounted = -5;
+
+
+public:
+ DECLARE_META_INTERFACE(MountService);
+
+ virtual void getShareMethodList() = 0;
+ virtual bool getShareMethodAvailable(String16 method) = 0;
+ virtual int shareVolume(String16 path, String16 method) = 0;
+ virtual int unshareVolume(String16 path, String16 method) = 0;
+ virtual bool getVolumeShared(String16 path, String16 method) = 0;
+ virtual int mountVolume(String16 path) = 0;
+ virtual int unmountVolume(String16 path) = 0;
+ virtual int formatVolume(String16 path) = 0;
+ virtual String16 getVolumeState(String16 mountPoint) = 0;
+ virtual int createSecureContainer(String16 id, int sizeMb, String16 fstype, String16 key, int ownerUid) = 0;
+ virtual int finalizeSecureContainer(String16 id) = 0;
+ virtual int destroySecureContainer(String16 id) = 0;
+ virtual int mountSecureContainer(String16 id, String16 key, int ownerUid) = 0;
+ virtual int unmountSecureContainer(String16 id) = 0;
+ virtual int renameSecureContainer(String16 oldId, String16 newId) = 0;
+ virtual String16 getSecureContainerPath(String16 id) = 0;
+ virtual void getSecureContainerList() = 0;
+ virtual void shutdown() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_IMOUNTSERVICE_H
diff --git a/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h b/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h
new file mode 100644
index 0000000..3ec2c94
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/audio_policy_conf.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_AUDIO_POLICY_CONF_H
+#define ANDROID_AUDIO_POLICY_CONF_H
+
+
+/////////////////////////////////////////////////
+// Definitions for audio policy configuration file (audio_policy.conf)
+/////////////////////////////////////////////////
+
+#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32
+
+#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"
+#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf"
+
+// global configuration
+#define GLOBAL_CONFIG_TAG "global_configuration"
+
+#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"
+
+#define OUTPUTS_TAG "outputs"
+#define INPUTS_TAG "inputs"
+
+#define SAMPLING_RATES_TAG "sampling_rates"
+#define FORMATS_TAG "formats"
+#define CHANNELS_TAG "channel_masks"
+#define DEVICES_TAG "devices"
+#define FLAGS_TAG "flags"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+ // "formats" in outputs descriptors indicating that supported
+ // values should be queried after opening the output.
+
+#endif // ANDROID_AUDIO_POLICY_CONF_H
diff --git a/libhardware_legacy/include/hardware_legacy/gscan.h b/libhardware_legacy/include/hardware_legacy/gscan.h
new file mode 100644
index 0000000..69e4159
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/gscan.h
@@ -0,0 +1,461 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_GSCAN_H__
+#define __WIFI_HAL_GSCAN_H__
+
+/* AP Scans */
+
+typedef enum {
+ WIFI_BAND_UNSPECIFIED,
+ WIFI_BAND_BG = 1, // 2.4 GHz
+ WIFI_BAND_A = 2, // 5 GHz without DFS
+ WIFI_BAND_A_DFS = 4, // 5 GHz DFS only
+ WIFI_BAND_A_WITH_DFS = 6, // 5 GHz with DFS
+ WIFI_BAND_ABG = 3, // 2.4 GHz + 5 GHz; no DFS
+ WIFI_BAND_ABG_WITH_DFS = 7, // 2.4 GHz + 5 GHz with DFS
+} wifi_band;
+
+const unsigned MAX_CHANNELS = 16;
+const unsigned MAX_BUCKETS = 16;
+const unsigned MAX_HOTLIST_APS = 128;
+const unsigned MAX_SIGNIFICANT_CHANGE_APS = 64;
+const unsigned MAX_PNO_SSID = 64;
+const unsigned MAX_HOTLIST_SSID = 8;
+const unsigned MAX_BLACKLIST_BSSID = 16;
+const unsigned MAX_AP_CACHE_PER_SCAN = 32;
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
+ int band, int max_channels, wifi_channel *channels, int *num_channels);
+
+typedef struct {
+ int max_scan_cache_size; // total space allocated for scan (in bytes)
+ int max_scan_buckets; // maximum number of channel buckets
+ int max_ap_cache_per_scan; // maximum number of APs that can be stored per scan
+ int max_rssi_sample_size; // number of RSSI samples used for averaging RSSI
+ int max_scan_reporting_threshold; // max possible report_threshold as described
+ // in wifi_scan_cmd_params
+ int max_hotlist_bssids; // maximum number of entries for hotlist BSSIDs
+ int max_hotlist_ssids; // maximum number of entries for hotlist SSIDs
+ int max_significant_wifi_change_aps; // maximum number of entries for
+ // significant wifi change APs
+ int max_bssid_history_entries; // number of BSSID/RSSI entries that device can hold
+ int max_number_epno_networks; // max number of epno entries
+ int max_number_epno_networks_by_ssid; // max number of epno entries if ssid is specified,
+ // that is, epno entries for which an exact match is
+ // required, or entries corresponding to hidden ssids
+ int max_number_of_white_listed_ssid; // max number of white listed SSIDs, M target is 2 to 4
+} wifi_gscan_capabilities;
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+ wifi_gscan_capabilities *capabilities);
+
+typedef enum {
+ WIFI_SCAN_BUFFER_FULL,
+ WIFI_SCAN_COMPLETE,
+} wifi_scan_event;
+
+
+/* Format of information elements found in the beacon */
+typedef struct {
+ byte id; // element identifier
+ byte len; // number of bytes to follow
+ byte data[];
+} wifi_information_element;
+
+typedef struct {
+ wifi_timestamp ts; // time since boot (in microsecond) when the result was
+ // retrieved
+ char ssid[32+1]; // null terminated
+ mac_addr bssid;
+ wifi_channel channel; // channel frequency in MHz
+ wifi_rssi rssi; // in db
+ wifi_timespan rtt; // in nanoseconds
+ wifi_timespan rtt_sd; // standard deviation in rtt
+ unsigned short beacon_period; // period advertised in the beacon
+ unsigned short capability; // capabilities advertised in the beacon
+ unsigned int ie_length; // size of the ie_data blob
+ char ie_data[1]; // blob of all the information elements found in the
+ // beacon; this data should be a packed list of
+ // wifi_information_element objects, one after the other.
+ // other fields
+} wifi_scan_result;
+
+typedef struct {
+ /* reported when report_threshold is reached in scan cache */
+ void (*on_scan_results_available) (wifi_request_id id, unsigned num_results_available);
+
+ /* reported when each probe response is received, if report_events
+ * enabled in wifi_scan_cmd_params */
+ void (*on_full_scan_result) (wifi_request_id id, wifi_scan_result *result);
+
+ /* optional event - indicates progress of scanning statemachine */
+ void (*on_scan_event) (wifi_scan_event event, unsigned status);
+
+} wifi_scan_result_handler;
+
+typedef struct {
+ wifi_channel channel; // frequency
+ int dwellTimeMs; // dwell time hint
+ int passive; // 0 => active, 1 => passive scan; ignored for DFS
+ /* Add channel class */
+} wifi_scan_channel_spec;
+
+#define REPORT_EVENTS_BUFFER_FULL 0
+#define REPORT_EVENTS_EACH_SCAN 1
+#define REPORT_EVENTS_FULL_RESULTS 2
+#define REPORT_EVENTS_NO_BATCH 4
+
+typedef struct {
+ int bucket; // bucket index, 0 based
+ wifi_band band; // when UNSPECIFIED, use channel list
+ int period; // desired period, in millisecond; if this is too
+ // low, the firmware should choose to generate results as
+ // fast as it can instead of failing the command.
+ // for exponential backoff bucket this is the min_period
+ /* report_events semantics -
+ * This is a bit field; which defines following bits -
+ * REPORT_EVENTS_BUFFER_FULL => report only when scan history is % full
+ * REPORT_EVENTS_EACH_SCAN => report a scan completion event after scan
+ * REPORT_EVENTS_FULL_RESULTS => forward scan results (beacons/probe responses + IEs)
+ * in real time to HAL, in addition to completion events
+ * Note: To keep backward compatibility, fire completion
+ * events regardless of REPORT_EVENTS_EACH_SCAN.
+ * REPORT_EVENTS_NO_BATCH => controls batching, 0 => batching, 1 => no batching
+ */
+ byte report_events;
+ int max_period; // if max_period is non zero or different than period, then this bucket is
+ // an exponential backoff bucket and the scan period will grow exponentially
+ // as per formula: actual_period(N) = period ^ (N/(step_count+1))
+ // to a maximum period of max_period
+ int exponent; // for exponential back off bucket: multiplier: new_period=old_period*exponent
+ int step_count; // for exponential back off bucket, number of scans performed at a given
+ // period and until the exponent is applied
+
+ int num_channels;
+ // channels to scan; these may include DFS channels
+ // Note that a given channel may appear in multiple buckets
+ wifi_scan_channel_spec channels[MAX_CHANNELS];
+} wifi_scan_bucket_spec;
+
+typedef struct {
+ int base_period; // base timer period in ms
+ int max_ap_per_scan; // number of APs to store in each scan ientryn the
+ // BSSID/RSSI history buffer (keep the highest RSSI APs)
+ int report_threshold_percent; // in %, when scan buffer is this much full, wake up AP
+ int report_threshold_num_scans; // in number of scans, wake up AP after these many scans
+ int num_buckets;
+ wifi_scan_bucket_spec buckets[MAX_BUCKETS];
+} wifi_scan_cmd_params;
+
+/* Start periodic GSCAN */
+wifi_error wifi_start_gscan(wifi_request_id id, wifi_interface_handle iface,
+ wifi_scan_cmd_params params, wifi_scan_result_handler handler);
+
+/* Stop periodic GSCAN */
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface);
+
+typedef enum {
+ WIFI_SCAN_FLAG_INTERRUPTED = 1 // Indicates that scan results are not complete because
+ // probes were not sent on some channels
+} wifi_scan_flags;
+
+/* Get the GSCAN cached scan results */
+typedef struct {
+ int scan_id; // a unique identifier for the scan unit
+ int flags; // a bitmask with additional
+ // information about scan
+ int num_results; // number of bssids retrieved by the scan
+ wifi_scan_result results[MAX_AP_CACHE_PER_SCAN]; // scan results - one for each bssid
+} wifi_cached_scan_results;
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
+ int max, wifi_cached_scan_results *results, int *num);
+
+/* BSSID Hotlist */
+typedef struct {
+ void (*on_hotlist_ap_found)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
+ void (*on_hotlist_ap_lost)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
+} wifi_hotlist_ap_found_handler;
+
+typedef struct {
+ mac_addr bssid; // AP BSSID
+ wifi_rssi low; // low threshold
+ wifi_rssi high; // high threshold
+} ap_threshold_param;
+
+typedef struct {
+ int lost_ap_sample_size;
+ int num_bssid; // number of hotlist APs
+ ap_threshold_param ap[MAX_HOTLIST_APS]; // hotlist APs
+} wifi_bssid_hotlist_params;
+
+/* Set the BSSID Hotlist */
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler);
+
+/* Clear the BSSID Hotlist */
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+/* SSID Hotlist */
+typedef struct {
+ void (*on_hotlist_ssid_found)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
+ void (*on_hotlist_ssid_lost)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
+} wifi_hotlist_ssid_handler;
+
+typedef struct {
+ char ssid[32+1]; // SSID
+ wifi_band band; // band for this set of threshold params
+ wifi_rssi low; // low threshold
+ wifi_rssi high; // high threshold
+} ssid_threshold_param;
+
+typedef struct {
+ int lost_ssid_sample_size;
+ int num_ssid; // number of hotlist SSIDs
+ ssid_threshold_param ssid[MAX_HOTLIST_SSID]; // hotlist SSIDs
+} wifi_ssid_hotlist_params;
+
+
+/* Set the SSID Hotlist */
+wifi_error wifi_set_ssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ssid_hotlist_params params, wifi_hotlist_ssid_handler handler);
+
+/* Clear the SSID Hotlist */
+wifi_error wifi_reset_ssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+
+/* BSSID blacklist */
+typedef struct {
+ int num_bssid; // number of blacklisted BSSIDs
+ mac_addr bssids[MAX_BLACKLIST_BSSID]; // blacklisted BSSIDs
+} wifi_bssid_params;
+
+/* Set the BSSID blacklist */
+wifi_error wifi_set_bssid_blacklist(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_params params);
+
+
+/* Significant wifi change */
+typedef struct {
+ mac_addr bssid; // BSSID
+ wifi_channel channel; // channel frequency in MHz
+ int num_rssi; // number of rssi samples
+ wifi_rssi rssi[]; // RSSI history in db
+} wifi_significant_change_result;
+
+typedef struct {
+ void (*on_significant_change)(wifi_request_id id,
+ unsigned num_results, wifi_significant_change_result **results);
+} wifi_significant_change_handler;
+
+// The sample size parameters in the wifi_significant_change_params structure
+// represent the number of occurence of a g-scan where the BSSID was seen and RSSI was
+// collected for that BSSID, or, the BSSID was expected to be seen and didn't.
+// for instance: lost_ap_sample_size : number of time a g-scan was performed on the
+// channel the BSSID was seen last, and the BSSID was not seen during those g-scans
+typedef struct {
+ int rssi_sample_size; // number of samples for averaging RSSI
+ int lost_ap_sample_size; // number of samples to confirm AP loss
+ int min_breaching; // number of APs breaching threshold
+ int num_bssid; // max 64
+ ap_threshold_param ap[MAX_SIGNIFICANT_CHANGE_APS];
+} wifi_significant_change_params;
+
+/* Set the Signifcant AP change list */
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_significant_change_params params, wifi_significant_change_handler handler);
+
+/* Clear the Signifcant AP change list */
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* Random MAC OUI for PNO */
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui);
+
+// Whether directed scan needs to be performed (for hidden SSIDs)
+#define WIFI_PNO_FLAG_DIRECTED_SCAN = 1
+// Whether PNO event shall be triggered if the network is found on A band
+#define WIFI_PNO_FLAG_A_BAND = 2
+// Whether PNO event shall be triggered if the network is found on G band
+#define WIFI_PNO_FLAG_G_BAND = 4
+// Whether strict matching is required (i.e. firmware shall not match on the entire SSID)
+#define WIFI_PNO_FLAG_STRICT_MATCH = 8
+
+// Code for matching the beacon AUTH IE - additional codes TBD
+#define WIFI_PNO_AUTH_CODE_OPEN 1 // open
+#define WIFI_PNO_AUTH_CODE_PSK 2 // WPA_PSK or WPA2PSK
+#define WIFI_PNO_AUTH_CODE_EAPOL 4 // any EAPOL
+
+// Enhanced PNO:
+// Enhanced PNO feature is expected to be enabled all of the time (e.g. screen lit) and may thus
+// requires firmware to store a large number of networks, covering the whole list of known network.
+// Therefore, it is acceptable for firmware to store a crc24, crc32 or other short hash of the SSID,
+// such that a low but non-zero probability of collision exist. With that scheme it should be
+// possible for firmware to keep an entry as small as 4 bytes for each pno network.
+// For instance, a firmware pn0 entry can be implemented in the form of:
+// PNO ENTRY = crc24(3 bytes) | RSSI_THRESHOLD>>3 (5 bits) | auth flags(3 bits)
+//
+// A PNO network shall be reported once, that is, once a network is reported by firmware
+// its entry shall be marked as "done" until framework calls wifi_set_epno_list again.
+// Calling wifi_set_epno_list shall reset the "done" status of pno networks in firmware.
+typedef struct {
+ char ssid[32+1];
+ byte rssi_threshold; // threshold for considering this SSID as found, required granularity for
+ // this threshold is 4dBm to 8dBm
+ byte flags; // WIFI_PNO_FLAG_XXX
+ byte auth_bit_field; // auth bit field for matching WPA IE
+} wifi_epno_network;
+
+/* PNO list */
+typedef struct {
+ int num_networks; // number of SSIDs
+ wifi_epno_network networks[]; // PNO networks
+} wifi_epno_params;
+
+typedef struct {
+ // on results
+ void (*on_network_found)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
+} wifi_epno_handler;
+
+
+/* Set the PNO list */
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+ int num_networks, wifi_epno_network *networks, wifi_epno_handler handler);
+
+
+/* SSID white list */
+/* Note that this feature requires firmware to be able to indicate to kernel sme and wpa_supplicant
+ * that the SSID of the network has changed
+ * and thus requires further changed in cfg80211 stack, for instance,
+ * the below function would change:
+
+ void __cfg80211_roamed(struct wireless_dev *wdev,
+ struct cfg80211_bss *bss,
+ const u8 *req_ie, size_t req_ie_len,
+ const u8 *resp_ie, size_t resp_ie_len)
+ * when firmware roam to a new SSID the corresponding link layer stats info need to be updated:
+ struct wifi_interface_link_layer_info;
+ */
+typedef struct {
+ char ssid[32+1]; // null terminated
+} wifi_ssid;
+
+wifi_error wifi_set_ssid_white_list(wifi_request_id id, wifi_interface_handle iface,
+ int num_networks, wifi_ssid *ssids);
+
+/* Set G-SCAN roam parameters */
+/**
+ * Firmware roaming is implemented with two modes:
+ * 1- "Alert" mode roaming, (Note: alert roaming is the pre-L roaming, whereas firmware is
+ * "urgently" hunting for another BSSID because the RSSI is low, or because many successive
+ * beacons have been lost or other bad link conditions).
+ * 2- "Lazy" mode, where firmware is hunting for a better BSSID or white listed SSID even though
+ * the RSSI of the link is good.
+ * Lazy mode is configured thru G-scan, that is, the results of G-scans are compared to the
+ * current RSSI and fed thru the roaming engine.
+ * Lazy scan will be enabled (and or throttled down by reducing the number of G-scans) by
+ * framework only in certain conditions, such as:
+ * - no real time (VO/VI) traffic at the interface
+ * - low packet rate for BE/BK packets a the interface
+ * - system conditions (screen lit/dark) etc...
+ *
+ * For consistency, the roam parameters will always be configured by framework such that:
+ *
+ * condition 1- A_band_boost_threshold >= (alert_roam_rssi_trigger + 10)
+ * This condition ensures that Lazy roam doesn't cause the device to roam to a 5GHz BSSID whose RSSI
+ * is lower than the alert threshold, which would consequently trigger a roam to a low RSSI BSSID,
+ * hence triggering alert mode roaming.
+ * In other words, in alert mode, the A_band parameters may safely be ignored by WiFi chipset.
+ *
+ * condition 2- A_band_boost_threshold > A_band_penalty_factor
+ *
+ */
+
+/**
+ * Example:
+ * A_band_boost_threshold = -65
+ * A_band_penalty_threshold = -75
+ * A_band_boost_factor = 4
+ * A_band_penalty_factor = 2
+ * A_band_max_boost = 50
+ *
+ * a 5GHz RSSI value is transformed as below:
+ * -20 -> -20+ 50 = 30
+ * -60 -> -60 + 4 * (-60 - A_band_boost_threshold) = -60 + 16 = -44
+ * -70 -> -70
+ * -80 -> -80 - 2 * (A_band_penalty_threshold - (-80)) = -80 - 10 = -90
+ */
+
+typedef struct {
+ // Lazy roam parameters
+ // A_band_XX parameters are applied to 5GHz BSSIDs when comparing with a 2.4GHz BSSID
+ // they may not be applied when comparing two 5GHz BSSIDs
+ int A_band_boost_threshold; // RSSI threshold above which 5GHz RSSI is favored
+ int A_band_penalty_threshold; // RSSI threshold below which 5GHz RSSI is penalized
+ int A_band_boost_factor; // factor by which 5GHz RSSI is boosted
+ // boost=RSSI_measured-5GHz_boost_threshold)*5GHz_boost_factor
+ int A_band_penalty_factor; // factor by which 5GHz RSSI is penalized
+ // penalty=(5GHz_penalty_factor-RSSI_measured)*5GHz_penalty_factor
+ int A_band_max_boost; // maximum boost that can be applied to a 5GHz RSSI
+
+ // Hysteresis: ensuring the currently associated BSSID is favored
+ // so as to prevent ping-pong situations
+ int lazy_roam_hysteresis; // boost applied to current BSSID
+
+ // Alert mode enable, i.e. configuring when firmware enters alert mode
+ int alert_roam_rssi_trigger; // RSSI below which "Alert" roam is enabled
+} wifi_roam_params;
+
+wifi_error wifi_set_gscan_roam_params(wifi_request_id id, wifi_interface_handle iface,
+ wifi_roam_params * params);
+
+/**
+ * Enable/Disable "Lazy" roam
+ */
+wifi_error wifi_enable_lazy_roam(wifi_request_id id, wifi_interface_handle iface, int enable);
+
+/**
+ * Per BSSID preference
+ */
+typedef struct {
+ mac_addr bssid;
+ int rssi_modifier; // modifier applied to the RSSI of the BSSID for the purpose of comparing
+ // it with other roam candidate
+} wifi_bssid_preference;
+
+wifi_error wifi_set_bssid_preference(wifi_request_id id, wifi_interface_handle iface,
+ int num_bssid, wifi_bssid_preference *prefs);
+
+typedef struct {
+ int id; // identifier of this network block, report this in event
+ char realm[256]; // null terminated UTF8 encoded realm, 0 if unspecified
+ int64_t roamingConsortiumIds[16]; // roaming consortium ids to match, 0s if unspecified
+ byte plmn[3]; // mcc/mnc combination as per rules, 0s if unspecified
+} wifi_passpoint_network;
+
+typedef struct {
+ void (*on_passpoint_network_found)(
+ wifi_request_id id,
+ int net_id, // network block identifier for the matched network
+ wifi_scan_result *result, // scan result, with channel and beacon information
+ int anqp_len, // length of ANQP blob
+ byte *anqp // ANQP data, in the information_element format
+ );
+} wifi_passpoint_event_handler;
+
+/* Sets a list for passpoint networks for PNO purposes; it should be matched
+ * against any passpoint networks (designated by Interworking element) found
+ * during regular PNO scan. */
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+ wifi_passpoint_network *networks, wifi_passpoint_event_handler handler);
+
+/* Reset passpoint network list - no Passpoint networks should be matched after this */
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/link_layer_stats.h b/libhardware_legacy/include/hardware_legacy/link_layer_stats.h
new file mode 100644
index 0000000..c6202ad
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/link_layer_stats.h
@@ -0,0 +1,253 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_STATS_H
+#define __WIFI_HAL_STATS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define STATS_MAJOR_VERSION 1
+#define STATS_MINOR_VERSION 0
+#define STATS_MICRO_VERSION 0
+
+typedef enum {
+ WIFI_DISCONNECTED = 0,
+ WIFI_AUTHENTICATING = 1,
+ WIFI_ASSOCIATING = 2,
+ WIFI_ASSOCIATED = 3,
+ WIFI_EAPOL_STARTED = 4, // if done by firmware/driver
+ WIFI_EAPOL_COMPLETED = 5, // if done by firmware/driver
+} wifi_connection_state;
+
+typedef enum {
+ WIFI_ROAMING_IDLE = 0,
+ WIFI_ROAMING_ACTIVE = 1,
+} wifi_roam_state;
+
+typedef enum {
+ WIFI_INTERFACE_STA = 0,
+ WIFI_INTERFACE_SOFTAP = 1,
+ WIFI_INTERFACE_IBSS = 2,
+ WIFI_INTERFACE_P2P_CLIENT = 3,
+ WIFI_INTERFACE_P2P_GO = 4,
+ WIFI_INTERFACE_NAN = 5,
+ WIFI_INTERFACE_MESH = 6,
+ WIFI_INTERFACE_UNKNOWN = -1
+ } wifi_interface_mode;
+
+#define WIFI_CAPABILITY_QOS 0x00000001 // set for QOS association
+#define WIFI_CAPABILITY_PROTECTED 0x00000002 // set for protected association (802.11 beacon frame control protected bit set)
+#define WIFI_CAPABILITY_INTERWORKING 0x00000004 // set if 802.11 Extended Capabilities element interworking bit is set
+#define WIFI_CAPABILITY_HS20 0x00000008 // set for HS20 association
+#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 // set is 802.11 Extended Capabilities element UTF-8 SSID bit is set
+#define WIFI_CAPABILITY_COUNTRY 0x00000020 // set is 802.11 Country Element is present
+
+typedef struct {
+ wifi_interface_mode mode; // interface mode
+ u8 mac_addr[6]; // interface mac address (self)
+ wifi_connection_state state; // connection state (valid for STA, CLI only)
+ wifi_roam_state roaming; // roaming state
+ u32 capabilities; // WIFI_CAPABILITY_XXX (self)
+ u8 ssid[33]; // null terminated SSID
+ u8 bssid[6]; // bssid
+ u8 ap_country_str[3]; // country string advertised by AP
+ u8 country_str[3]; // country string for this association
+} wifi_interface_link_layer_info;
+
+/* channel information */
+typedef struct {
+ wifi_channel_width width; // channel width (20, 40, 80, 80+80, 160)
+ wifi_channel center_freq; // primary 20 MHz channel
+ wifi_channel center_freq0; // center frequency (MHz) first segment
+ wifi_channel center_freq1; // center frequency (MHz) second segment
+} wifi_channel_info;
+
+/* wifi rate */
+typedef struct {
+ u32 preamble :3; // 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved
+ u32 nss :2; // 0:1x1, 1:2x2, 3:3x3, 4:4x4
+ u32 bw :3; // 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz
+ u32 rateMcsIdx :8; // OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps
+ // HT/VHT it would be mcs index
+ u32 reserved :16; // reserved
+ u32 bitrate; // units of 100 Kbps
+} wifi_rate;
+
+/* channel statistics */
+typedef struct {
+ wifi_channel_info channel; // channel
+ u32 on_time; // msecs the radio is awake (32 bits number accruing over time)
+ u32 cca_busy_time; // msecs the CCA register is busy (32 bits number accruing over time)
+} wifi_channel_stat;
+
+/* radio statistics */
+typedef struct {
+ wifi_radio radio; // wifi radio (if multiple radio supported)
+ u32 on_time; // msecs the radio is awake (32 bits number accruing over time)
+ u32 tx_time; // msecs the radio is transmitting (32 bits number accruing over time)
+ u32 rx_time; // msecs the radio is in active receive (32 bits number accruing over time)
+ u32 on_time_scan; // msecs the radio is awake due to all scan (32 bits number accruing over time)
+ u32 on_time_nbd; // msecs the radio is awake due to NAN (32 bits number accruing over time)
+ u32 on_time_gscan; // msecs the radio is awake due to G?scan (32 bits number accruing over time)
+ u32 on_time_roam_scan; // msecs the radio is awake due to roam?scan (32 bits number accruing over time)
+ u32 on_time_pno_scan; // msecs the radio is awake due to PNO scan (32 bits number accruing over time)
+ u32 on_time_hs20; // msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits number accruing over time)
+ u32 num_channels; // number of channels
+ wifi_channel_stat channels[]; // channel statistics
+} wifi_radio_stat;
+
+/**
+ * Packet statistics reporting by firmware is performed on MPDU basi (i.e. counters increase by 1 for each MPDU)
+ * As well, "data packet" in associated comments, shall be interpreted as 802.11 data packet,
+ * that is, 802.11 frame control subtype == 2 and excluding management and control frames.
+ *
+ * As an example, in the case of transmission of an MSDU fragmented in 16 MPDUs which are transmitted
+ * OTA in a 16 units long a-mpdu, for which a block ack is received with 5 bits set:
+ * tx_mpdu : shall increase by 5
+ * retries : shall increase by 16
+ * tx_ampdu : shall increase by 1
+ * data packet counters shall not increase regardless of the number of BAR potentially sent by device for this a-mpdu
+ * data packet counters shall not increase regardless of the number of BA received by device for this a-mpdu
+ *
+ * For each subsequent retransmission of the 11 remaining non ACK'ed mpdus
+ * (regardless of the fact that they are transmitted in a-mpdu or not)
+ * retries : shall increase by 1
+ *
+ * If no subsequent BA or ACK are received from AP, until packet lifetime expires for those 11 packet that were not ACK'ed
+ * mpdu_lost : shall increase by 11
+ */
+
+/* per rate statistics */
+typedef struct {
+ wifi_rate rate; // rate information
+ u32 tx_mpdu; // number of successfully transmitted data pkts (ACK rcvd)
+ u32 rx_mpdu; // number of received data pkts
+ u32 mpdu_lost; // number of data packet losses (no ACK)
+ u32 retries; // total number of data pkt retries
+ u32 retries_short; // number of short data pkt retries
+ u32 retries_long; // number of long data pkt retries
+} wifi_rate_stat;
+
+/* access categories */
+typedef enum {
+ WIFI_AC_VO = 0,
+ WIFI_AC_VI = 1,
+ WIFI_AC_BE = 2,
+ WIFI_AC_BK = 3,
+ WIFI_AC_MAX = 4,
+} wifi_traffic_ac;
+
+/* wifi peer type */
+typedef enum
+{
+ WIFI_PEER_STA,
+ WIFI_PEER_AP,
+ WIFI_PEER_P2P_GO,
+ WIFI_PEER_P2P_CLIENT,
+ WIFI_PEER_NAN,
+ WIFI_PEER_TDLS,
+ WIFI_PEER_INVALID,
+} wifi_peer_type;
+
+/* per peer statistics */
+typedef struct {
+ wifi_peer_type type; // peer type (AP, TDLS, GO etc.)
+ u8 peer_mac_address[6]; // mac address
+ u32 capabilities; // peer WIFI_CAPABILITY_XXX
+ u32 num_rate; // number of rates
+ wifi_rate_stat rate_stats[]; // per rate statistics, number of entries = num_rate
+} wifi_peer_info;
+
+/* Per access category statistics */
+typedef struct {
+ wifi_traffic_ac ac; // access category (VI, VO, BE, BK)
+ u32 tx_mpdu; // number of successfully transmitted unicast data pkts (ACK rcvd)
+ u32 rx_mpdu; // number of received unicast data packets
+ u32 tx_mcast; // number of succesfully transmitted multicast data packets
+ // STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent
+ u32 rx_mcast; // number of received multicast data packets
+ u32 rx_ampdu; // number of received unicast a-mpdus; support of this counter is optional
+ u32 tx_ampdu; // number of transmitted unicast a-mpdus; support of this counter is optional
+ u32 mpdu_lost; // number of data pkt losses (no ACK)
+ u32 retries; // total number of data pkt retries
+ u32 retries_short; // number of short data pkt retries
+ u32 retries_long; // number of long data pkt retries
+ u32 contention_time_min; // data pkt min contention time (usecs)
+ u32 contention_time_max; // data pkt max contention time (usecs)
+ u32 contention_time_avg; // data pkt avg contention time (usecs)
+ u32 contention_num_samples; // num of data pkts used for contention statistics
+} wifi_wmm_ac_stat;
+
+/* interface statistics */
+typedef struct {
+ wifi_interface_handle iface; // wifi interface
+ wifi_interface_link_layer_info info; // current state of the interface
+ u32 beacon_rx; // access point beacon received count from connected AP
+ u64 average_tsf_offset; // average beacon offset encountered (beacon_TSF - TBTT)
+ // The average_tsf_offset field is used so as to calculate the
+ // typical beacon contention time on the channel as well may be
+ // used to debug beacon synchronization and related power consumption issue
+ u32 leaky_ap_detected; // indicate that this AP typically leaks packets beyond the driver guard time.
+ u32 leaky_ap_avg_num_frames_leaked; // average number of frame leaked by AP after frame with PM bit set was ACK'ed by AP
+ u32 leaky_ap_guard_time; // guard time currently in force (when implementing IEEE power management based on
+ // frame control PM bit), How long driver waits before shutting down the radio and
+ // after receiving an ACK for a data frame with PM bit set)
+ u32 mgmt_rx; // access point mgmt frames received count from connected AP (including Beacon)
+ u32 mgmt_action_rx; // action frames received count
+ u32 mgmt_action_tx; // action frames transmit count
+ wifi_rssi rssi_mgmt; // access Point Beacon and Management frames RSSI (averaged)
+ wifi_rssi rssi_data; // access Point Data Frames RSSI (averaged) from connected AP
+ wifi_rssi rssi_ack; // access Point ACK RSSI (averaged) from connected AP
+ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; // per ac data packet statistics
+ u32 num_peers; // number of peers
+ wifi_peer_info peer_info[]; // per peer statistics
+} wifi_iface_stat;
+
+/* configuration params */
+typedef struct {
+ u32 mpdu_size_threshold; // threshold to classify the pkts as short or long
+ // packet size < mpdu_size_threshold => short
+ u32 aggressive_statistics_gathering; // set for field debug mode. Driver should collect all statistics regardless of performance impact.
+} wifi_link_layer_params;
+
+/* API to trigger the link layer statistics collection.
+ Unless his API is invoked - link layer statistics will not be collected.
+ Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked
+ Interface statistics (once started) reset and start afresh after each connection */
+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params);
+
+/* callback for reporting link layer stats */
+typedef struct {
+ void (*on_link_stats_results) (wifi_request_id id, wifi_iface_stat *iface_stat,
+ int num_radios, wifi_radio_stat *radio_stat);
+} wifi_stats_result_handler;
+
+/* api to collect the link layer statistics for a given iface and all the radio stats */
+wifi_error wifi_get_link_stats(wifi_request_id id,
+ wifi_interface_handle iface, wifi_stats_result_handler handler);
+
+/* wifi statistics bitmap */
+#define WIFI_STATS_RADIO 0x00000001 // all radio statistics
+#define WIFI_STATS_RADIO_CCA 0x00000002 // cca_busy_time (within radio statistics)
+#define WIFI_STATS_RADIO_CHANNELS 0x00000004 // all channel statistics (within radio statistics)
+#define WIFI_STATS_RADIO_SCAN 0x00000008 // all scan statistics (within radio statistics)
+#define WIFI_STATS_IFACE 0x00000010 // all interface statistics
+#define WIFI_STATS_IFACE_TXRATE 0x00000020 // all tx rate statistics (within interface statistics)
+#define WIFI_STATS_IFACE_AC 0x00000040 // all ac statistics (within interface statistics)
+#define WIFI_STATS_IFACE_CONTENTION 0x00000080 // all contention (min, max, avg) statistics (within ac statisctics)
+
+/* clear api to reset statistics, stats_clear_rsp_mask identifies what stats have been cleared
+ stop_req = 1 will imply whether to stop the statistics collection.
+ stop_rsp = 1 will imply that stop_req was honored and statistics collection was stopped.
+ */
+wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
+ u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
+
diff --git a/libhardware_legacy/include/hardware_legacy/power.h b/libhardware_legacy/include/hardware_legacy/power.h
new file mode 100644
index 0000000..604e0ed
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/power.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HARDWARE_POWER_H
+#define _HARDWARE_POWER_H
+
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+enum {
+ PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off
+ FULL_WAKE_LOCK = 2 // the screen is also on
+};
+
+// while you have a lock held, the device will stay on at least at the
+// level you request.
+int acquire_wake_lock(int lock, const char* id);
+int release_wake_lock(const char* id);
+
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_POWER_H
diff --git a/libhardware_legacy/include/hardware_legacy/rtt.h b/libhardware_legacy/include/hardware_legacy/rtt.h
new file mode 100644
index 0000000..2808723
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/rtt.h
@@ -0,0 +1,274 @@
+
+#include "wifi_hal.h"
+#include "gscan.h"
+
+#ifndef __WIFI_HAL_RTT_H__
+#define __WIFI_HAL_RTT_H__
+
+/* Ranging status */
+typedef enum {
+ RTT_STATUS_SUCCESS = 0,
+ RTT_STATUS_FAILURE = 1, // general failure status
+ RTT_STATUS_FAIL_NO_RSP = 2, // target STA does not respond to request
+ RTT_STATUS_FAIL_REJECTED = 3, // request rejected. Applies to 2-sided RTT only
+ RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4,
+ RTT_STATUS_FAIL_TM_TIMEOUT = 5, // timing measurement times out
+ RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6, // Target on different channel, cannot range
+ RTT_STATUS_FAIL_NO_CAPABILITY = 7, // ranging not supported
+ RTT_STATUS_ABORTED = 8, // request aborted for unknown reason
+ RTT_STATUS_FAIL_INVALID_TS = 9, // Invalid T1-T4 timestamp
+ RTT_STATUS_FAIL_PROTOCOL = 10, // 11mc protocol failed
+ RTT_STATUS_FAIL_SCHEDULE = 11, // request could not be scheduled
+ RTT_STATUS_FAIL_BUSY_TRY_LATER = 12, // responder cannot collaborate at time of request
+ RTT_STATUS_INVALID_REQ = 13, // bad request args
+ RTT_STATUS_NO_WIFI = 14, // WiFi not enabled
+ RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 // Responder overrides param info, cannot range with new params
+} wifi_rtt_status;
+
+/* RTT peer type */
+typedef enum {
+ RTT_PEER_AP = 0x1,
+ RTT_PEER_STA = 0x2,
+ RTT_PEER_P2P_GO = 0x3,
+ RTT_PEER_P2P_CLIENT = 0x4,
+ RTT_PEER_NAN = 0x5
+} rtt_peer_type;
+
+/* RTT Measurement Bandwidth */
+typedef enum {
+ WIFI_RTT_BW_5 = 0x01,
+ WIFI_RTT_BW_10 = 0x02,
+ WIFI_RTT_BW_20 = 0x04,
+ WIFI_RTT_BW_40 = 0x08,
+ WIFI_RTT_BW_80 = 0x10,
+ WIFI_RTT_BW_160 = 0x20
+} wifi_rtt_bw;
+
+/* RTT Measurement Preamble */
+typedef enum {
+ WIFI_RTT_PREAMBLE_LEGACY = 0x1,
+ WIFI_RTT_PREAMBLE_HT = 0x2,
+ WIFI_RTT_PREAMBLE_VHT = 0x4
+} wifi_rtt_preamble;
+
+/* RTT Type */
+typedef enum {
+ RTT_TYPE_1_SIDED = 0x1,
+ RTT_TYPE_2_SIDED = 0x2,
+} wifi_rtt_type;
+
+/* RTT configuration */
+typedef struct {
+ mac_addr addr; // peer device mac address
+ wifi_rtt_type type; // 1-sided or 2-sided RTT
+ rtt_peer_type peer; // optional - peer device hint (STA, P2P, AP)
+ wifi_channel_info channel; // Required for STA-AP mode, optional for P2P, NBD etc.
+ unsigned burst_period; // Time interval between bursts (units: 100 ms).
+ // Applies to 1-sided and 2-sided RTT multi-burst requests.
+ // Range: 0-31, 0: no preference by initiator (2-sided RTT)
+ unsigned num_burst; // Total number of RTT bursts to be executed. It will be
+ // specified in the same way as the parameter "Number of
+ // Burst Exponent" found in the FTM frame format. It
+ // applies to both: 1-sided RTT and 2-sided RTT. Valid
+ // values are 0 to 15 as defined in 802.11mc std.
+ // 0 means single shot
+ // The implication of this parameter on the maximum
+ // number of RTT results is the following:
+ // for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+ // for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+ unsigned num_frames_per_burst; // num of frames per burst.
+ // Minimum value = 1, Maximum value = 31
+ // For 2-sided this equals the number of FTM frames
+ // to be attempted in a single burst. This also
+ // equals the number of FTM frames that the
+ // initiator will request that the responder send
+ // in a single frame.
+ unsigned num_retries_per_rtt_frame; // number of retries for a failed RTT frame. Applies
+ // to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+
+ //following fields are only valid for 2-side RTT
+ unsigned num_retries_per_ftmr; // Maximum number of retries that the initiator can
+ // retry an FTMR frame.
+ // Minimum value = 0, Maximum value = 3
+ byte LCI_request; // 1: request LCI, 0: do not request LCI
+ byte LCR_request; // 1: request LCR, 0: do not request LCR
+ unsigned burst_duration; // Applies to 1-sided and 2-sided RTT. Valid values will
+ // be 2-11 and 15 as specified by the 802.11mc std for
+ // the FTM parameter burst duration. In a multi-burst
+ // request, if responder overrides with larger value,
+ // the initiator will return failure. In a single-burst
+ // request if responder overrides with larger value,
+ // the initiator will sent TMR_STOP to terminate RTT
+ // at the end of the burst_duration it requested.
+ wifi_rtt_preamble preamble; // RTT preamble to be used in the RTT frames
+ wifi_rtt_bw bw; // RTT BW to be used in the RTT frames
+} wifi_rtt_config;
+
+/* RTT results */
+typedef struct {
+ mac_addr addr; // device mac address
+ unsigned burst_num; // burst number in a multi-burst request
+ unsigned measurement_number; // Total RTT measurement frames attempted
+ unsigned success_number; // Total successful RTT measurement frames
+ byte number_per_burst_peer; // Maximum number of "FTM frames per burst" supported by
+ // the responder STA. Applies to 2-sided RTT only.
+ // If reponder overrides with larger value:
+ // - for single-burst request initiator will truncate the
+ // larger value and send a TMR_STOP after receiving as
+ // many frames as originally requested.
+ // - for multi-burst request, initiator will return
+ // failure right away.
+ wifi_rtt_status status; // ranging status
+ byte retry_after_duration; // When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+ // this will be the time provided by the responder as to
+ // when the request can be tried again. Applies to 2-sided
+ // RTT only. In sec, 1-31sec.
+ wifi_rtt_type type; // RTT type
+ wifi_rssi rssi; // average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB
+ wifi_rssi rssi_spread; // rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional)
+ wifi_rate tx_rate; // 1-sided RTT: TX rate of RTT frame.
+ // 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+ wifi_rate rx_rate; // 1-sided RTT: TX rate of Ack from other side.
+ // 2-sided RTT: TX rate of FTM frame coming from responder.
+ wifi_timespan rtt; // round trip time in 0.1 nanoseconds
+ wifi_timespan rtt_sd; // rtt standard deviation in 0.1 nanoseconds
+ wifi_timespan rtt_spread; // difference between max and min rtt times recorded
+ int distance; // distance in cm (optional)
+ int distance_sd; // standard deviation in cm (optional)
+ int distance_spread; // difference between max and min distance recorded (optional)
+ wifi_timestamp ts; // time of the measurement (in microseconds since boot)
+ int burst_duration; // in ms, actual time taken by the FW to finish one burst
+ // measurement. Applies to 1-sided and 2-sided RTT.
+ int negotiated_burst_num; // Number of bursts allowed by the responder. Applies
+ // to 2-sided RTT only.
+ wifi_information_element *LCI; // for 11mc only
+ wifi_information_element *LCR; // for 11mc only
+} wifi_rtt_result;
+
+/* RTT result callback */
+typedef struct {
+ void (*on_rtt_results) (wifi_request_id id, unsigned num_results, wifi_rtt_result *rtt_result[]);
+} wifi_rtt_event_handler;
+
+/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler);
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
+ unsigned num_devices, mac_addr addr[]);
+
+/* NBD ranging channel map */
+typedef struct {
+ wifi_channel availablity[32]; // specifies the channel map for each of the 16 TU windows
+ // frequency of 0 => unspecified; which means firmware is
+ // free to do whatever it wants in this window.
+} wifi_channel_map;
+
+/* API to start publishing the channel map on responder device in a NBD cluster.
+ Responder device will take this request and schedule broadcasting the channel map
+ in a NBD ranging attribute in a SDF. DE will automatically remove the ranging
+ attribute from the OTA queue after number of DW specified by num_dw
+ where Each DW is 512 TUs apart */
+wifi_error wifi_rtt_channel_map_set(wifi_request_id id,
+ wifi_interface_handle iface, wifi_channel_map *params, unsigned num_dw);
+
+/* API to clear the channel map on the responder device in a NBD cluster.
+ Responder device will cancel future ranging channel request, starting from “next”
+ DW interval and will also stop broadcasting NBD ranging attribute in SDF */
+wifi_error wifi_rtt_channel_map_clear(wifi_request_id id, wifi_interface_handle iface);
+
+// Preamble definition for bit mask used in wifi_rtt_capabilities
+#define PREAMBLE_LEGACY 0x1
+#define PREAMBLE_HT 0x2
+#define PREAMBLE_VHT 0x4
+
+// BW definition for bit mask used in wifi_rtt_capabilities
+#define BW_5_SUPPORT 0x1
+#define BW_10_SUPPORT 0x2
+#define BW_20_SUPPORT 0x4
+#define BW_40_SUPPORT 0x8
+#define BW_80_SUPPORT 0x10
+#define BW_160_SUPPORT 0x20
+
+/* RTT Capabilities */
+typedef struct {
+ byte rtt_one_sided_supported; // if 1-sided rtt data collection is supported
+ byte rtt_ftm_supported; // if ftm rtt data collection is supported
+ byte lci_support; // if initiator supports LCI request. Applies to 2-sided RTT
+ byte lcr_support; // if initiator supports LCR request. Applies to 2-sided RTT
+ byte preamble_support; // bit mask indicates what preamble is supported by initiator
+ byte bw_support; // bit mask indicates what BW is supported by initiator
+} wifi_rtt_capabilities;
+
+/* RTT capabilities of the device */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, wifi_rtt_capabilities *capabilities);
+
+/* debugging definitions */
+enum {
+ RTT_DEBUG_DISABLE,
+ RTT_DEBUG_LOG,
+ RTT_DEBUG_PROTO,
+ RTT_DEBUG_BURST,
+ RTT_DEBUG_ACCURACY,
+ RTT_DEBUG_LOGDETAIL
+}; //rtt debug type
+
+enum {
+ RTT_DEBUG_FORMAT_TXT,
+ RTT_DEBUG_FORMAT_BINARY
+}; //rtt debug format
+
+typedef struct rtt_debug {
+ unsigned version;
+ unsigned len; // total length of after len field
+ unsigned type; // rtt debug type
+ unsigned format; //rtt debug format
+ char dbuf[0]; // debug content
+} rtt_debug_t;
+
+/* set configuration for debug */
+wifi_error wifi_rtt_debug_cfg(wifi_interface_handle h, unsigned rtt_dbg_type, char *cfgbuf, unsigned cfg_buf_size);
+/* get the debug information */
+wifi_error wifi_rtt_debug_get(wifi_interface_handle h, rtt_debug_t **debugbuf);
+/* free the debug buffer */
+wifi_error wifi_rtt_debug_free(wifi_interface_handle h, rtt_debug_t *debugbuf);
+
+/* API for setting LCI/LCR information to be provided to a requestor */
+typedef enum {
+ WIFI_MOTION_NOT_EXPECTED = 0, // Not expected to change location
+ WIFI_MOTION_EXPECTED = 1, // Expected to change location
+ WIFI_MOTION_UNKNOWN = 2, // Movement pattern unknown
+} wifi_motion_pattern;
+
+typedef struct {
+ long latitude; // latitude in degrees * 2^25 , 2's complement
+ long longitude; // latitude in degrees * 2^25 , 2's complement
+ int altitude; // Altitude in units of 1/256 m
+ byte latitude_unc; // As defined in Section 2.3.2 of IETF RFC 6225
+ byte longitude_unc; // As defined in Section 2.3.2 of IETF RFC 6225
+ byte altitude_unc; // As defined in Section 2.4.5 from IETF RFC 6225:
+
+ //Following element for configuring the Z subelement
+ wifi_motion_pattern motion_pattern;
+ int floor; // floor in units of 1/16th of floor. 0x80000000 if unknown.
+ int height_above_floor; // in units of 1/64 m
+ int height_unc; // in units of 1/64 m. 0 if unknown
+} wifi_lci_information;
+
+typedef struct {
+ char country_code[2]; // country code
+ int length; // length of the info field
+ char civic_info[256]; // Civic info to be copied in FTM frame
+} wifi_lcr_information;
+
+// API to configure the LCI. Used in RTT Responder mode only
+wifi_error wifi_set_lci(wifi_request_id id, wifi_interface_handle iface,
+ wifi_lci_information *lci);
+
+// API to configure the LCR. Used in RTT Responder mode only.
+wifi_error wifi_set_lcr(wifi_request_id id, wifi_interface_handle iface,
+ wifi_lcr_information *lcr);
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/tdls.h b/libhardware_legacy/include/hardware_legacy/tdls.h
new file mode 100644
index 0000000..9ac225a
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/tdls.h
@@ -0,0 +1,85 @@
+
+#include "wifi_hal.h"
+
+#ifndef _TDLS_H_
+#define _TDLS_H_
+
+typedef enum {
+ WIFI_TDLS_DISABLED = 1, /* TDLS is not enabled, default status for all STAs */
+ WIFI_TDLS_ENABLED, /* TDLS is enabled, but not yet tried */
+ WIFI_TDLS_ESTABLISHED, /* Direct link is established */
+ WIFI_TDLS_ESTABLISHED_OFF_CHANNEL, /* Direct link is established using MCC */
+ WIFI_TDLS_DROPPED, /* Direct link was established,
+ * but is temporarily dropped now */
+ WIFI_TDLS_FAILED /* TDLS permanent failed. Inform error to upper layer
+ * and go back to WIFI_TDLS_DISABLED */
+} wifi_tdls_state;
+
+typedef enum {
+ WIFI_TDLS_SUCCESS, /* Success */
+ WIFI_TDLS_UNSPECIFIED = -1, /* Unspecified reason */
+ WIFI_TDLS_NOT_SUPPORTED = -2, /* Remote side doesn't support TDLS */
+ WIFI_TDLS_UNSUPPORTED_BAND = -3, /* Remote side doesn't support this band */
+ WIFI_TDLS_NOT_BENEFICIAL = -4, /* Going to AP is better than going direct */
+ WIFI_TDLS_DROPPED_BY_REMOTE = -5 /* Remote side doesn't want it anymore */
+} wifi_tdls_reason;
+
+typedef struct {
+ int channel; /* channel hint, in channel number (NOT frequency ) */
+ int global_operating_class; /* operating class to use */
+ int max_latency_ms; /* max latency that can be tolerated by apps */
+ int min_bandwidth_kbps; /* bandwidth required by apps, in kilo bits per second */
+} wifi_tdls_params;
+
+typedef struct {
+ int channel;
+ int global_operating_class;
+ wifi_tdls_state state;
+ wifi_tdls_reason reason;
+} wifi_tdls_status;
+
+typedef struct {
+ int max_concurrent_tdls_session_num; /* Maximum TDLS session number can be supported by the
+ * Firmware and hardware*/
+ int is_global_tdls_supported; /* 1 -- support, 0 -- not support */
+ int is_per_mac_tdls_supported; /* 1 -- support, 0 -- not support */
+ int is_off_channel_tdls_supported; /* 1 -- support, 0 -- not support */
+} wifi_tdls_capabilities;
+
+typedef struct {
+ /* on_tdls_state_changed - reports state of TDLS link to framework
+ * Report this event when the state of TDLS link changes */
+ void (*on_tdls_state_changed)(mac_addr addr, wifi_tdls_status status);
+} wifi_tdls_handler;
+
+
+/* wifi_enable_tdls - enables TDLS-auto mode for a specific route
+ *
+ * params specifies hints, which provide more information about
+ * why TDLS is being sought. The firmware should do its best to
+ * honor the hints before downgrading regular AP link
+ * If upper layer has no specific values, this should be NULL
+ *
+ * handler is used to inform the upper layer about the status change and the corresponding reason
+ */
+wifi_error wifi_enable_tdls(wifi_interface_handle iface, mac_addr addr,
+ wifi_tdls_params *params, wifi_tdls_handler handler);
+
+/* wifi_disable_tdls - disables TDLS-auto mode for a specific route
+ *
+ * This terminates any existing TDLS with addr device, and frees the
+ * device resources to make TDLS connections on new routes.
+ *
+ * DON'T fire any more events on 'handler' specified in earlier call to
+ * wifi_enable_tdls after this action.
+ */
+wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr);
+
+/* wifi_get_tdls_status - allows getting the status of TDLS for a specific route */
+wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
+ wifi_tdls_status *status);
+
+/* return the current HW + Firmware combination's TDLS capabilities */
+wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
+ wifi_tdls_capabilities *capabilities);
+#endif
diff --git a/libhardware_legacy/include/hardware_legacy/uevent.h b/libhardware_legacy/include/hardware_legacy/uevent.h
new file mode 100644
index 0000000..bedfff5
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/uevent.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HARDWARE_UEVENT_H
+#define _HARDWARE_UEVENT_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+int uevent_init();
+int uevent_get_fd();
+int uevent_next_event(char* buffer, int buffer_length);
+int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
+ void *handler_data);
+int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len));
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // _HARDWARE_UEVENT_H
diff --git a/libhardware_legacy/include/hardware_legacy/wifi.h b/libhardware_legacy/include/hardware_legacy/wifi.h
new file mode 100644
index 0000000..93f0383
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WIFI_H
+#define _WIFI_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Load the Wi-Fi driver.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_load_driver();
+
+/**
+ * Unload the Wi-Fi driver.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_unload_driver();
+
+/**
+ * Check if the Wi-Fi driver is loaded.
+ * Check if the Wi-Fi driver is loaded.
+
+ * @return 0 on success, < 0 on failure.
+ */
+int is_wifi_driver_loaded();
+
+
+/**
+ * Start supplicant.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_start_supplicant(int p2pSupported);
+
+/**
+ * Stop supplicant.
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_stop_supplicant(int p2pSupported);
+
+/**
+ * Open a connection to supplicant
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+int wifi_connect_to_supplicant();
+
+/**
+ * Close connection to supplicant
+ *
+ * @return 0 on success, < 0 on failure.
+ */
+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 buf is the buffer that receives the event
+ * @param len is the maximum length of the buffer
+ *
+ * @returns number of bytes in buffer, 0 if no
+ * event (for instance, no connection), and less than 0
+ * if there is an error.
+ */
+int wifi_wait_for_event(char *buf, size_t len);
+
+/**
+ * wifi_command() issues a command to the Wi-Fi driver.
+ *
+ * Android extends the standard commands listed at
+ * /link http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
+ * to include support for sending commands to the driver:
+ *
+ * See wifi/java/android/net/wifi/WifiNative.java for the details of
+ * driver commands that are supported
+ *
+ * @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
+ * bytes in the reply buffer.
+ *
+ * @return 0 if successful, < 0 if an error.
+ */
+int wifi_command(const char *command, char *reply, size_t *reply_len);
+
+/**
+ * do_dhcp_request() issues a dhcp request and returns the acquired
+ * information.
+ *
+ * All IPV4 addresses/mask are in network byte order.
+ *
+ * @param ipaddr return the assigned IPV4 address
+ * @param gateway return the gateway being used
+ * @param mask return the IPV4 mask
+ * @param dns1 return the IPV4 address of a DNS server
+ * @param dns2 return the IPV4 address of a DNS server
+ * @param server return the IPV4 address of DHCP server
+ * @param lease return the length of lease in seconds.
+ *
+ * @return 0 if successful, < 0 if error.
+ */
+int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
+ int *dns1, int *dns2, int *server, int *lease);
+
+/**
+ * Return the error string of the last do_dhcp_request().
+ */
+const char *get_dhcp_error_string();
+
+/**
+ * Return the path to requested firmware
+ */
+#define WIFI_GET_FW_PATH_STA 0
+#define WIFI_GET_FW_PATH_AP 1
+#define WIFI_GET_FW_PATH_P2P 2
+const char *wifi_get_fw_path(int fw_type);
+
+/**
+ * Change the path to firmware for the wlan driver
+ */
+int wifi_change_fw_path(const char *fwpath);
+
+/**
+ * Check and create if necessary initial entropy file
+ */
+#define WIFI_ENTROPY_FILE "/data/misc/wifi/entropy.bin"
+int ensure_entropy_file_exists();
+
+#if __cplusplus
+}; // extern "C"
+#endif
+
+#endif // _WIFI_H
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_config.h b/libhardware_legacy/include/hardware_legacy/wifi_config.h
new file mode 100644
index 0000000..8ad14f4
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_config.h
@@ -0,0 +1,47 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_CONFIG_H
+#define __WIFI_HAL_CONFIG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define CONFIG_MAJOR_VERSION 1
+#define CONFIG_MINOR_VERSION 0
+#define CONFIG_MICRO_VERSION 0
+
+typedef int wifi_radio;
+
+// whether the wifi chipset wakes at every dtim beacon or a multiple of the dtim period
+// if extended_dtim is set to 3, the STA shall wake up every 3 DTIM beacons
+wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
+ wifi_interface_handle iface, int extended_dtim);
+
+//set the country code to driver
+wifi_error wifi_set_country_code(wifi_interface_handle iface, const char* country_code);
+
+//set the wifi_iface stats averaging factor used to calculate
+// statistics like average the TSF offset or average number of frame leaked
+// For instance, upon beacon reception:
+// current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000
+// For instance, when evaluating leaky APs:
+// current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000
+
+wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id, wifi_interface_handle iface,
+ u16 factor);
+
+// configure guard time, i.e. when implementing IEEE power management based on
+// frame control PM bit, how long driver waits before shutting down the radio and
+// after receiving an ACK for a data frame with PM bit set
+wifi_error wifi_set_guard_time(wifi_request_id id, wifi_interface_handle iface,
+ u32 guard_time);
+
+#ifdef __cplusplus
+}
+
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
+
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_hal.h b/libhardware_legacy/include/hardware_legacy/wifi_hal.h
new file mode 100644
index 0000000..a0ce8fd
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_hal.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_H__
+#define __WIFI_HAL_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include <stdint.h>
+
+/* WiFi Common definitions */
+/* channel operating width */
+typedef enum {
+ WIFI_CHAN_WIDTH_20 = 0,
+ WIFI_CHAN_WIDTH_40 = 1,
+ WIFI_CHAN_WIDTH_80 = 2,
+ WIFI_CHAN_WIDTH_160 = 3,
+ WIFI_CHAN_WIDTH_80P80 = 4,
+ WIFI_CHAN_WIDTH_5 = 5,
+ WIFI_CHAN_WIDTH_10 = 6,
+ WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width;
+
+typedef int wifi_radio;
+typedef int wifi_channel;
+
+typedef struct {
+ wifi_channel_width width;
+ int center_frequency0;
+ int center_frequency1;
+ int primary_frequency;
+} wifi_channel_spec;
+
+typedef enum {
+ WIFI_SUCCESS = 0,
+ WIFI_ERROR_NONE = 0,
+ WIFI_ERROR_UNKNOWN = -1,
+ WIFI_ERROR_UNINITIALIZED = -2,
+ WIFI_ERROR_NOT_SUPPORTED = -3,
+ WIFI_ERROR_NOT_AVAILABLE = -4, // Not available right now, but try later
+ WIFI_ERROR_INVALID_ARGS = -5,
+ WIFI_ERROR_INVALID_REQUEST_ID = -6,
+ WIFI_ERROR_TIMED_OUT = -7,
+ WIFI_ERROR_TOO_MANY_REQUESTS = -8, // Too many instances of this request
+ WIFI_ERROR_OUT_OF_MEMORY = -9
+} wifi_error;
+
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef signed char s8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef int wifi_request_id;
+typedef int wifi_channel; // indicates channel frequency in MHz
+typedef int wifi_rssi;
+typedef byte mac_addr[6];
+typedef byte oui[3];
+typedef int64_t wifi_timestamp; // In microseconds (us)
+typedef int64_t wifi_timespan; // In nanoseconds (ns)
+
+typedef struct wifi_info *wifi_handle;
+typedef struct wifi_interface_info *wifi_interface_handle;
+
+/* Initialize/Cleanup */
+
+wifi_error wifi_initialize(wifi_handle *handle);
+typedef void (*wifi_cleaned_up_handler) (wifi_handle handle);
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler);
+void wifi_event_loop(wifi_handle handle);
+
+/* Error handling */
+void wifi_get_error_info(wifi_error err, const char **msg); // return a pointer to a static string
+
+/* Feature enums */
+#define WIFI_FEATURE_INFRA 0x0001 // Basic infrastructure mode
+#define WIFI_FEATURE_INFRA_5G 0x0002 // Support for 5 GHz Band
+#define WIFI_FEATURE_HOTSPOT 0x0004 // Support for GAS/ANQP
+#define WIFI_FEATURE_P2P 0x0008 // Wifi-Direct
+#define WIFI_FEATURE_SOFT_AP 0x0010 // Soft AP
+#define WIFI_FEATURE_GSCAN 0x0020 // Google-Scan APIs
+#define WIFI_FEATURE_NAN 0x0040 // Neighbor Awareness Networking
+#define WIFI_FEATURE_D2D_RTT 0x0080 // Device-to-device RTT
+#define WIFI_FEATURE_D2AP_RTT 0x0100 // Device-to-AP RTT
+#define WIFI_FEATURE_BATCH_SCAN 0x0200 // Batched Scan (legacy)
+#define WIFI_FEATURE_PNO 0x0400 // Preferred network offload
+#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 // Support for two STAs
+#define WIFI_FEATURE_TDLS 0x1000 // Tunnel directed link setup
+#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 // Support for TDLS off channel
+#define WIFI_FEATURE_EPR 0x4000 // Enhanced power reporting
+#define WIFI_FEATURE_AP_STA 0x8000 // Support for AP STA Concurrency
+#define WIFI_FEATURE_LINK_LAYER_STATS 0x10000 // Link layer stats collection
+#define WIFI_FEATURE_LOGGER 0x20000 // WiFi Logger
+#define WIFI_FEATURE_HAL_EPNO 0x40000 // WiFi PNO enhanced
+#define WIFI_FEATURE_RSSI_MONITOR 0x80000 // RSSI Monitor
+#define WIFI_FEATURE_MKEEP_ALIVE 0x100000 // WiFi mkeep_alive
+
+// Add more features here
+
+
+typedef int feature_set;
+
+#define IS_MASK_SET(mask, flags) (((flags) & (mask)) == (mask))
+#define IS_MASK_RESET(mask, flags) (((flags) & (mask)) == 0)
+
+#define IS_SUPPORTED_FEATURE(feature, featureSet) IS_MASK_SET(feature, fetureSet)
+#define IS_UNSUPPORTED_FEATURE(feature, featureSet) IS_MASK_RESET(feature, fetureSet)
+
+/* Feature set */
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set);
+
+/*
+ * Each row represents a valid feature combination;
+ * all other combinations are invalid!
+ */
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+ feature_set set[], int *set_size);
+
+/* multiple interface support */
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num_ifaces, wifi_interface_handle **ifaces);
+wifi_error wifi_get_iface_name(wifi_interface_handle iface, char *name, size_t size);
+
+/* Configuration events */
+
+typedef struct {
+ void (*on_country_code_changed)(char code[2]); // We can get this from supplicant too
+
+ // More event handlers
+} wifi_event_handler;
+
+typedef struct {
+ void (*on_rssi_threshold_breached)(wifi_request_id id, u8 *cur_bssid, s8 cur_rssi);
+} wifi_rssi_event_handler;
+
+wifi_error wifi_set_iface_event_handler(wifi_request_id id, wifi_interface_handle iface, wifi_event_handler eh);
+wifi_error wifi_reset_iface_event_handler(wifi_request_id id, wifi_interface_handle iface);
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs);
+
+/* include various feature headers */
+
+#include "gscan.h"
+#include "link_layer_stats.h"
+#include "rtt.h"
+#include "tdls.h"
+#include "wifi_logger.h"
+#include "wifi_config.h"
+#include "wifi_nan.h"
+#include "wifi_offload.h"
+
+//wifi HAL function pointer table
+typedef struct {
+ wifi_error (* wifi_initialize) (wifi_handle *);
+ void (* wifi_cleanup) (wifi_handle, wifi_cleaned_up_handler);
+ void (*wifi_event_loop)(wifi_handle);
+ void (* wifi_get_error_info) (wifi_error , const char **);
+ wifi_error (* wifi_get_supported_feature_set) (wifi_interface_handle, feature_set *);
+ wifi_error (* wifi_get_concurrency_matrix) (wifi_interface_handle, int, feature_set *, int *);
+ wifi_error (* wifi_set_scanning_mac_oui) (wifi_interface_handle, unsigned char *);
+ wifi_error (* wifi_get_supported_channels)(wifi_handle, int *, wifi_channel *);
+ wifi_error (* wifi_is_epr_supported)(wifi_handle);
+ wifi_error (* wifi_get_ifaces) (wifi_handle , int *, wifi_interface_handle **);
+ wifi_error (* wifi_get_iface_name) (wifi_interface_handle, char *name, size_t);
+ wifi_error (* wifi_set_iface_event_handler) (wifi_request_id,wifi_interface_handle ,
+ wifi_event_handler);
+ wifi_error (* wifi_reset_iface_event_handler) (wifi_request_id, wifi_interface_handle);
+ wifi_error (* wifi_start_gscan) (wifi_request_id, wifi_interface_handle, wifi_scan_cmd_params,
+ wifi_scan_result_handler);
+ wifi_error (* wifi_stop_gscan)(wifi_request_id, wifi_interface_handle);
+ wifi_error (* wifi_get_cached_gscan_results)(wifi_interface_handle, byte, int,
+ wifi_cached_scan_results *, int *);
+ wifi_error (* wifi_set_bssid_hotlist)(wifi_request_id, wifi_interface_handle,
+ wifi_bssid_hotlist_params, wifi_hotlist_ap_found_handler);
+ wifi_error (* wifi_reset_bssid_hotlist)(wifi_request_id, wifi_interface_handle);
+ wifi_error (* wifi_set_significant_change_handler)(wifi_request_id, wifi_interface_handle,
+ wifi_significant_change_params, wifi_significant_change_handler);
+ wifi_error (* wifi_reset_significant_change_handler)(wifi_request_id, wifi_interface_handle);
+ wifi_error (* wifi_get_gscan_capabilities)(wifi_interface_handle, wifi_gscan_capabilities *);
+ wifi_error (* wifi_set_link_stats) (wifi_interface_handle, wifi_link_layer_params);
+ wifi_error (* wifi_get_link_stats) (wifi_request_id,wifi_interface_handle,
+ wifi_stats_result_handler);
+ wifi_error (* wifi_clear_link_stats)(wifi_interface_handle,u32, u32 *, u8, u8 *);
+ wifi_error (* wifi_get_valid_channels)(wifi_interface_handle,int, int, wifi_channel *, int *);
+ wifi_error (* wifi_rtt_range_request)(wifi_request_id, wifi_interface_handle, unsigned,
+ wifi_rtt_config[], wifi_rtt_event_handler);
+ wifi_error (* wifi_rtt_range_cancel)(wifi_request_id, wifi_interface_handle, unsigned,
+ mac_addr[]);
+ wifi_error (* wifi_get_rtt_capabilities)(wifi_interface_handle, wifi_rtt_capabilities *);
+ wifi_error (* wifi_set_nodfs_flag)(wifi_interface_handle, u32);
+ wifi_error (* wifi_start_logging)(wifi_interface_handle, u32, u32, u32, u32, char *);
+ wifi_error (* wifi_set_epno_list)(int, wifi_interface_info *, int, wifi_epno_network *,
+ wifi_epno_handler);
+ wifi_error (* wifi_set_country_code)(wifi_interface_handle, const char *);
+ wifi_error (* wifi_get_firmware_memory_dump)( wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler);
+ wifi_error (* wifi_set_log_handler)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler);
+ wifi_error (* wifi_reset_log_handler)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (* wifi_set_alert_handler)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler);
+ wifi_error (* wifi_reset_alert_handler)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (* wifi_get_firmware_version)(wifi_interface_handle iface, char *buffer,
+ int buffer_size);
+ wifi_error (* wifi_get_ring_buffers_status)(wifi_interface_handle iface,
+ u32 *num_rings, wifi_ring_buffer_status *status);
+ wifi_error (* wifi_get_logger_supported_feature_set)(wifi_interface_handle iface,
+ unsigned int *support);
+ wifi_error (* wifi_get_ring_data)(wifi_interface_handle iface, char *ring_name);
+ wifi_error (* wifi_enable_tdls)(wifi_interface_handle, mac_addr, wifi_tdls_params *,
+ wifi_tdls_handler);
+ wifi_error (* wifi_disable_tdls)(wifi_interface_handle, mac_addr);
+ wifi_error (*wifi_get_tdls_status) (wifi_interface_handle, mac_addr, wifi_tdls_status *);
+ wifi_error (*wifi_get_tdls_capabilities)(wifi_interface_handle iface,
+ wifi_tdls_capabilities *capabilities);
+ wifi_error (* wifi_get_driver_version)(wifi_interface_handle iface, char *buffer,
+ int buffer_size);
+ wifi_error (* wifi_set_passpoint_list)(wifi_request_id id, wifi_interface_handle iface,
+ int num, wifi_passpoint_network *networks, wifi_passpoint_event_handler handler);
+ wifi_error (* wifi_reset_passpoint_list)(wifi_request_id id, wifi_interface_handle iface);
+ wifi_error (*wifi_set_bssid_blacklist)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_bssid_params params);
+ wifi_error (*wifi_enable_lazy_roam)(wifi_request_id id,
+ wifi_interface_handle iface, int enable);
+ wifi_error (*wifi_set_bssid_preference)(wifi_request_id id, wifi_interface_handle iface,
+ int num_bssid, wifi_bssid_preference *prefs);
+ wifi_error (*wifi_set_gscan_roam_params)(wifi_request_id id, wifi_interface_handle iface,
+ wifi_roam_params * params);
+ wifi_error (*wifi_set_ssid_white_list)(wifi_request_id id, wifi_interface_handle iface,
+ int num_networks, wifi_ssid *ssids);
+ wifi_error (*wifi_set_lci) (wifi_request_id id, wifi_interface_handle iface,
+ wifi_lci_information *lci);
+ wifi_error (*wifi_set_lcr) (wifi_request_id id, wifi_interface_handle iface,
+ wifi_lcr_information *lcr);
+ wifi_error (*wifi_start_sending_offloaded_packet)(wifi_request_id id,
+ wifi_interface_handle iface, u8 *ip_packet, u16 ip_packet_len,
+ u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec);
+ wifi_error (*wifi_stop_sending_offloaded_packet)(wifi_request_id id,
+ wifi_interface_handle iface);
+ wifi_error (*wifi_start_rssi_monitoring)(wifi_request_id id, wifi_interface_handle
+ iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+ wifi_error (*wifi_stop_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface);
+} wifi_hal_fn;
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_logger.h b/libhardware_legacy/include/hardware_legacy/wifi_logger.h
new file mode 100644
index 0000000..9823aa3
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_logger.h
@@ -0,0 +1,413 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_LOGGER_H
+#define __WIFI_HAL_LOGGER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define LOGGER_MAJOR_VERSION 1
+#define LOGGER_MINOR_VERSION 0
+#define LOGGER_MICRO_VERSION 0
+
+
+
+/**
+ * WiFi logger life cycle is as follow:
+ *
+ * - At initialization time, framework will call wifi_get_ring_buffers_status
+ * so as to obtain the names and list of supported buffers.
+ * - When WiFi operation start framework will call wifi_start_logging
+ * so as to trigger log collection.
+ * - Developper UI will provide an option to the user, so as it can set the verbose level
+ * of individual buffer as reported by wifi_get_ring_buffers_status.
+ * - During wifi operations, driver will periodically report per ring data to framework
+ * by invoking the on_ring_buffer_data call back.
+ * - when capturing a bug report, framework will indicate to driver that all the data
+ * has to be uploaded, urgently, by calling wifi_get_ring_data.
+ *
+ * The data uploaded by driver will be stored by framework in separate files, with one stream
+ * of file per ring.
+ * Framework will store the files in pcapng format, allowing for easy merging and parsing
+ * with network analyzer tools.
+ */
+
+
+typedef int wifi_radio;
+typedef int wifi_ring_buffer_id;
+
+#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX 1 // 0: TX, 1: RX
+#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS 2 // whether packet was transmitted or
+ // received/decrypted successfully
+#define PER_PACKET_ENTRY_FLAGS_80211_HEADER 4 // has full 802.11 header, else has 802.3 header
+#define PER_PACKET_ENTRY_FLAGS_PROTECTED 8 // whether packet was encrypted
+
+typedef struct {
+ u8 flags;
+ u8 tid; // transmit or received tid
+ u16 MCS; // modulation and bandwidth
+ u8 rssi; // TX: RSSI of ACK for that packet
+ // RX: RSSI of packet
+ u8 num_retries; // number of attempted retries
+ u16 last_transmit_rate; // last transmit rate in .5 mbps
+ u16 link_layer_transmit_sequence; // transmit/reeive sequence for that MPDU packet
+ u64 firmware_entry_timestamp; // TX: firmware timestamp (us) when packet is queued within
+ // firmware buffer for SDIO/HSIC or into PCIe buffer
+ // RX: firmware receive timestamp
+ u64 start_contention_timestamp; // firmware timestamp (us) when packet start contending for the
+ // medium for the first time, at head of its AC queue,
+ // or as part of an MPDU or A-MPDU. This timestamp is
+ // not updated for each retry, only the first transmit attempt.
+ u64 transmit_success_timestamp; // fimrware timestamp (us) when packet is successfully
+ // transmitted or aborted because it has exhausted
+ // its maximum number of retries.
+ u8 data[0]; // packet data. The length of packet data is determined by the entry_size field of
+ // the wifi_ring_buffer_entry structure. It is expected that first bytes of the
+ // packet, or packet headers only (up to TCP or RTP/UDP headers)
+ // will be copied into the ring
+} __attribute__((packed)) wifi_ring_per_packet_status_entry;
+
+
+/* Below events refer to the wifi_connectivity_event ring and shall be supported */
+#define WIFI_EVENT_ASSOCIATION_REQUESTED 0 // driver receives association command from kernel
+#define WIFI_EVENT_AUTH_COMPLETE 1
+#define WIFI_EVENT_ASSOC_COMPLETE 2
+#define WIFI_EVENT_FW_AUTH_STARTED 3 // fw event indicating auth frames are sent
+#define WIFI_EVENT_FW_ASSOC_STARTED 4 // fw event indicating assoc frames are sent
+#define WIFI_EVENT_FW_RE_ASSOC_STARTED 5 // fw event indicating reassoc frames are sent
+#define WIFI_EVENT_DRIVER_SCAN_REQUESTED 6
+#define WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND 7
+#define WIFI_EVENT_DRIVER_SCAN_COMPLETE 8
+#define WIFI_EVENT_G_SCAN_STARTED 9
+#define WIFI_EVENT_G_SCAN_COMPLETE 10
+#define WIFI_EVENT_DISASSOCIATION_REQUESTED 11
+#define WIFI_EVENT_RE_ASSOCIATION_REQUESTED 12
+#define WIFI_EVENT_ROAM_REQUESTED 13
+#define WIFI_EVENT_BEACON_RECEIVED 14 // received beacon from AP (event enabled
+ // only in verbose mode)
+#define WIFI_EVENT_ROAM_SCAN_STARTED 15 // firmware has triggered a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SCAN_COMPLETE 16 // firmware has completed a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SEARCH_STARTED 17 // firmware has started searching for roam
+ // candidates (with reason =xx)
+#define WIFI_EVENT_ROAM_SEARCH_STOPPED 18 // firmware has stopped searching for roam
+ // candidates (with reason =xx)
+#define WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT 20 // received channel switch anouncement from AP
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START 21 // fw start transmit eapol frame, with
+ // EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP 22 // fw gives up eapol frame, with rate,
+ // success/failure and number retries
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED 23 // kernel queue EAPOL for transmission
+ // in driver with EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED 24 // with rate, regardless of the fact that
+ // EAPOL frame is accepted or rejected by fw
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED 26 // with rate, and eapol index, driver has
+ // received EAPOL frame and will queue it up
+ // to wpa_supplicant
+#define WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE 27 // with success/failure, parameters
+#define WIFI_EVENT_BT_COEX_BT_SCO_START 28
+#define WIFI_EVENT_BT_COEX_BT_SCO_STOP 29
+#define WIFI_EVENT_BT_COEX_BT_SCAN_START 30 // for paging/scan etc., when BT starts transmiting
+ // twice per BT slot
+#define WIFI_EVENT_BT_COEX_BT_SCAN_STOP 31
+#define WIFI_EVENT_BT_COEX_BT_HID_START 32
+#define WIFI_EVENT_BT_COEX_BT_HID_STOP 33
+#define WIFI_EVENT_ROAM_AUTH_STARTED 34 // fw sends auth frame in roaming to next candidate
+#define WIFI_EVENT_ROAM_AUTH_COMPLETE 35 // fw receive auth confirm from ap
+#define WIFI_EVENT_ROAM_ASSOC_STARTED 36 // firmware sends assoc/reassoc frame in
+ // roaming to next candidate
+#define WIFI_EVENT_ROAM_ASSOC_COMPLETE 37 // firmware receive assoc/reassoc confirm from ap
+#define WIFI_EVENT_G_SCAN_STOP 38 // firmware sends stop G_SCAN
+#define WIFI_EVENT_G_SCAN_CYCLE_STARTED 39 // firmware indicates G_SCAN scan cycle started
+#define WIFI_EVENT_G_SCAN_CYCLE_COMPLETED 40 // firmware indicates G_SCAN scan cycle completed
+#define WIFI_EVENT_G_SCAN_BUCKET_STARTED 41 // firmware indicates G_SCAN scan start
+ // for a particular bucket
+#define WIFI_EVENT_G_SCAN_BUCKET_COMPLETED 42 // firmware indicates G_SCAN scan completed for
+ // for a particular bucket
+#define WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE 43 // Event received from firmware about G_SCAN scan
+ // results being available
+#define WIFI_EVENT_G_SCAN_CAPABILITIES 44 // Event received from firmware with G_SCAN
+ // capabilities
+#define WIFI_EVENT_ROAM_CANDIDATE_FOUND 45 // Event received from firmware when eligible
+ // candidate is found
+#define WIFI_EVENT_ROAM_SCAN_CONFIG 46 // Event received from firmware when roam scan
+ // configuration gets enabled or disabled
+
+/**
+ * Parameters of wifi logger events are TLVs
+ * Event parameters tags are defined as:
+ */
+#define WIFI_TAG_VENDOR_SPECIFIC 0 // take a byte stream as parameter
+#define WIFI_TAG_BSSID 1 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR 2 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_SSID 3 // takes a 32 bytes SSID address as parameter
+#define WIFI_TAG_STATUS 4 // takes an integer as parameter
+#define WIFI_TAG_CHANNEL_SPEC 5 // takes one or more wifi_channel_spec as parameter
+#define WIFI_TAG_WAKE_LOCK_EVENT 6 // takes a wake_lock_event struct as parameter
+#define WIFI_TAG_ADDR1 7 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR2 8 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR3 9 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR4 10 // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_TSF 11 // take a 64 bits TSF value as parameter
+#define WIFI_TAG_IE 12 // take one or more specific 802.11 IEs parameter,
+ // IEs are in turn indicated in TLV format as per
+ // 802.11 spec
+#define WIFI_TAG_INTERFACE 13 // take interface name as parameter
+#define WIFI_TAG_REASON_CODE 14 // take a reason code as per 802.11 as parameter
+#define WIFI_TAG_RATE_MBPS 15 // take a wifi rate in 0.5 mbps
+#define WIFI_TAG_REQUEST_ID 16 // take an integer as parameter
+#define WIFI_TAG_BUCKET_ID 17 // take an integer as parameter
+#define WIFI_TAG_GSCAN_PARAMS 18 // takes a wifi_scan_cmd_params struct as parameter
+#define WIFI_TAG_GSCAN_CAPABILITIES 19 // takes a wifi_gscan_capabilities struct as parameter
+#define WIFI_TAG_SCAN_ID 20 // take an integer as parameter
+#define WIFI_TAG_RSSI 21 // take an integer as parameter
+#define WIFI_TAG_CHANNEL 22 // take an integer as parameter
+#define WIFI_TAG_LINK_ID 23 // take an integer as parameter
+#define WIFI_TAG_LINK_ROLE 24 // take an integer as parameter
+#define WIFI_TAG_LINK_STATE 25 // take an integer as parameter
+#define WIFI_TAG_LINK_TYPE 26 // take an integer as parameter
+#define WIFI_TAG_TSCO 27 // take an integer as parameter
+#define WIFI_TAG_RSCO 28 // take an integer as parameter
+#define WIFI_TAG_EAPOL_MESSAGE_TYPE 29 // take an integer as parameter
+ // M1-1, M2-2, M3-3, M4-4
+
+typedef struct {
+ u16 tag;
+ u16 length; // length of value
+ u8 value[0];
+} __attribute__((packed)) tlv_log;
+
+typedef struct {
+ u16 event;
+ tlv_log tlvs[0]; // separate parameter structure per event to be provided and optional data
+ // the event_data is expected to include an official android part, with some
+ // parameter as transmit rate, num retries, num scan result found etc...
+ // as well, event_data can include a vendor proprietary part which is
+ // understood by the developer only.
+} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;
+
+
+/**
+ * Ring buffer name for power events ring. note that power event are extremely frequents
+ * and thus should be stored in their own ring/file so as not to clobber connectivity events.
+ */
+typedef struct {
+ int status; // 0 taken, 1 released
+ int reason; // reason why this wake lock is taken
+ char name[0]; // null terminated
+} __attribute__((packed)) wake_lock_event;
+
+typedef struct {
+ u16 event;
+ tlv_log tlvs[0];
+} __attribute__((packed)) wifi_power_event;
+
+
+/**
+ * This structure represent a logger entry within a ring buffer.
+ * Wifi driver are responsible to manage the ring buffer and write the debug
+ * information into those rings.
+ *
+ * In general, the debug entries can be used to store meaningful 802.11 information (SME, MLME,
+ * connection and packet statistics) as well as vendor proprietary data that is specific to a
+ * specific driver or chipset.
+ * Binary entries can be used so as to store packet data or vendor specific information and
+ * will be treated as blobs of data by android.
+ *
+ * A user land process will be started by framework so as to periodically retrieve the
+ * data logged by drivers into their ring buffer, store the data into log files and include
+ * the logs into android bugreports.
+ */
+enum {
+ RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)), // set for binary entries
+ RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1)) // set if 64 bits timestamp is present
+};
+
+enum {
+ ENTRY_TYPE_CONNECT_EVENT = 1,
+ ENTRY_TYPE_PKT,
+ ENTRY_TYPE_WAKE_LOCK,
+ ENTRY_TYPE_POWER_EVENT,
+ ENTRY_TYPE_DATA
+};
+
+typedef struct {
+ u16 entry_size; // the size of payload excluding the header.
+ u8 flags;
+ u8 type; // entry type
+ u64 timestamp; // present if has_timestamp bit is set.
+} __attribute__((packed)) wifi_ring_buffer_entry;
+
+#define WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES 0x00000001 // set if binary entries are present
+#define WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES 0x00000002 // set if ascii entries are present
+
+
+/* ring buffer params */
+/**
+ * written_bytes and read_bytes implement a producer consumer API
+ * hence written_bytes >= read_bytes
+ * a modulo arithmetic of the buffer size has to be applied to those counters:
+ * actual offset into ring buffer = written_bytes % ring_buffer_byte_size
+ *
+ */
+typedef struct {
+ u8 name[32];
+ u32 flags;
+ wifi_ring_buffer_id ring_id; // unique integer representing the ring
+ u32 ring_buffer_byte_size; // total memory size allocated for the buffer
+ u32 verbose_level; // verbose level for ring buffer
+ u32 written_bytes; // number of bytes that was written to the buffer by driver,
+ // monotonously increasing integer
+ u32 read_bytes; // number of bytes that was read from the buffer by user land,
+ // monotonously increasing integer
+ u32 written_records; // number of records that was written to the buffer by driver,
+ // monotonously increasing integer
+} wifi_ring_buffer_status;
+
+
+/**
+ * Callback for reporting ring data
+ *
+ * The ring buffer data collection is event based:
+ * - Driver calls on_ring_buffer_data when new records are available, the wifi_ring_buffer_status
+ * passed up to framework in the call back indicates to framework if more data is available in
+ * the ring buffer. It is not expected that driver will necessarily always empty the ring
+ * immediately as data is available, instead driver will report data every X seconds or if
+ * N bytes are available.
+ * - In the case where a bug report has to be captured, framework will require driver to upload
+ * all data immediately. This is indicated to driver when framework calls wifi_get_ringdata.
+ * When framework calls wifi_get_ring_data, driver will start sending all available data in the
+ * indicated ring by repeatedly invoking the on_ring_buffer_data callback.
+ *
+ * The callback is called by log handler whenever ring data comes in driver.
+ */
+typedef struct {
+ void (*on_ring_buffer_data) (char *ring_name, char *buffer, int buffer_size,
+ wifi_ring_buffer_status *status);
+} wifi_ring_buffer_data_handler;
+
+/**
+ * API to set the log handler for getting ring data
+ * - Only a single instance of log handler can be instantiated for each ring buffer.
+ */
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_ring_buffer_data_handler handler);
+
+/* API to reset the log handler */
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface);
+
+
+/**
+ * Callback for reporting FW dump
+ *
+ * The buffer data collection is event based such as FW health check or FW dump.
+ * The callback is called by alert handler.
+ */
+typedef struct {
+ void (*on_alert) (wifi_request_id id, char *buffer, int buffer_size, int err_code);
+} wifi_alert_handler;
+
+/*
+ * API to set the alert handler for the alert case in Wi-Fi Chip
+ * - Only a single instance of alert handler can be instantiated.
+ */
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_alert_handler handler);
+
+/* API to reset the alert handler */
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* API for framework to indicate driver has to upload and drain all data of a given ring */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name);
+
+
+/**
+ * API to trigger the debug collection.
+ * Unless his API is invoked - logging is not triggered.
+ * - Verbose_level 0 corresponds to no collection,
+ * and it makes log handler stop by no more events from driver.
+ * - Verbose_level 1 correspond to normal log level, with minimal user impact.
+ * This is the default value.
+ * - Verbose_level 2 are enabled when user is lazily trying to reproduce a problem,
+ * wifi performances and power can be impacted but device should not otherwise be
+ * significantly impacted.
+ * - Verbose_level 3+ are used when trying to actively debug a problem.
+ *
+ * ring_name represent the name of the ring for which data collection shall start.
+ *
+ * flags: TBD parameter used to enable/disable specific events on a ring
+ * max_interval: maximum interval in seconds for driver to invoke on_ring_buffer_data,
+ * ignore if zero
+ * min_data_size: minimum data size in buffer for driver to invoke on_ring_buffer_data,
+ * ignore if zero
+ */
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+ u32 max_interval_sec, u32 min_data_size, char *ring_name);
+
+/**
+ * API to get the status of all ring buffers supported by driver.
+ * - Caller is responsible to allocate / free ring buffer status.
+ * - Maximum no of ring buffer would be 10.
+ */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, u32 *num_rings,
+ wifi_ring_buffer_status *status);
+
+/**
+ * Synchronous memory dump by user request.
+ * - Caller is responsible to store memory dump data into a local,
+ * e.g., /data/misc/wifi/memdump.bin
+ */
+typedef struct {
+ void (*on_firmware_memory_dump) (char *buffer, int buffer_size);
+} wifi_firmware_memory_dump_handler;
+
+/**
+ * API to collect a firmware memory dump for a given iface by async memdump event.
+ * - Triggered by Alerthandler, esp. when FW problem or FW health check happens
+ * - Caller is responsible to store fw dump data into a local,
+ * e.g., /data/misc/wifi/alertdump-1.bin
+ */
+wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
+ wifi_firmware_memory_dump_handler handler);
+
+/**
+ * API to collect a firmware version string.
+ * - Caller is responsible to allocate / free a buffer to retrieve firmware verion info.
+ * - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, int buffer_size);
+
+/**
+ * API to collect a driver version string.
+ * - Caller is responsible to allocate / free a buffer to retrieve driver verion info.
+ * - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size);
+
+
+/* Feature set */
+enum {
+ WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), // Memory dump of FW
+ WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
+ WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), // Connectivity event
+ WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), // POWER of Driver
+ WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), // WAKE LOCK of Driver
+ WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), // verbose log of FW
+ WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)) // monitor the health of FW
+};
+
+/**
+ * API to retrieve the current supportive features.
+ * - An integer variable is enough to have bit mapping info by caller.
+ */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+ unsigned int *support);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
+
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_nan.h b/libhardware_legacy/include/hardware_legacy/wifi_nan.h
new file mode 100755
index 0000000..70e97f1
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_nan.h
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NAN_H__
+#define __NAN_H__
+
+#include "wifi_hal.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*****************************************************************************
+ * NAN Discovery Service Structures and Functions
+ *****************************************************************************/
+
+/*
+ Definitions
+ All multi-byte fields within all NAN protocol stack messages are assumed to be in Little Endian order.
+*/
+
+typedef int NanVersion;
+
+#define NAN_MAC_ADDR_LEN 6
+#define NAN_COUNTRY_STRING_LEN 3
+#define NAN_MAJOR_VERSION 1
+#define NAN_MINOR_VERSION 0
+#define NAN_MICRO_VERSION 0
+
+/* NAN Maximum Lengths */
+#define NAN_MAX_SERVICE_NAME_LEN 255
+#define NAN_MAX_MATCH_FILTER_LEN 255
+#define NAN_MAX_SERVICE_SPECIFIC_INFO_LEN 1024
+
+/*
+ Definition of various NanRequestType
+*/
+typedef enum {
+ NAN_REQUEST_ENABLE =0,
+ NAN_REQUEST_DISABLE =1,
+ NAN_REQUEST_PUBLISH =2,
+ NAN_REQUEST_PUBLISH_CANCEL =3,
+ NAN_REQUEST_TRANSMIT_FOLLOWUP =4,
+ NAN_REQUEST_SUBSCRIBE =5,
+ NAN_REQUEST_SUBSCRIBE_CANCEL =6,
+ NAN_REQUEST_STATS =7,
+ NAN_REQUEST_CONFIG =8,
+ NAN_REQUEST_TCA =9,
+ NAN_REQUEST_LAST =0xFFFF
+} NanRequestType;
+
+/*
+ Definition of various NanResponseType
+*/
+typedef enum {
+ NAN_RESPONSE_ENABLED =0,
+ NAN_RESPONSE_DISABLED =1,
+ NAN_RESPONSE_PUBLISH =2,
+ NAN_RESPONSE_PUBLISH_CANCEL =3,
+ NAN_RESPONSE_TRANSMIT_FOLLOWUP =4,
+ NAN_RESPONSE_SUBSCRIBE =5,
+ NAN_RESPONSE_SUBSCRIBE_CANCEL =6,
+ NAN_RESPONSE_STATS =7,
+ NAN_RESPONSE_CONFIG =8,
+ NAN_RESPONSE_TCA =9,
+ NAN_RESPONSE_ERROR =10,
+ NAN_RESPONSE_UNKNOWN =0xFFFF
+} NanResponseType;
+
+/*
+ Definition of various NanIndication(events)
+*/
+typedef enum {
+ NAN_INDICATION_PUBLISH_REPLIED =0,
+ NAN_INDICATION_PUBLISH_TERMINATED =1,
+ NAN_INDICATION_SUBSCRIBE_MATCH =2,
+ NAN_INDICATION_SUBSCRIBE_UNMATCH =3,
+ NAN_INDICATION_SUBSCRIBE_TERMINATED =4,
+ NAN_INDICATION_DE_EVENT =5,
+ NAN_INDICATION_FOLLOWUP =6,
+ NAN_INDICATION_DISABLED =7,
+ NAN_INDICATION_TCA =8,
+ NAN_INDICATION_UNKNOWN =0xFFFF
+} NanIndicationType;
+
+
+/* NAN Publish Types */
+typedef enum {
+ NAN_PUBLISH_TYPE_UNSOLICITED = 0,
+ NAN_PUBLISH_TYPE_SOLICITED,
+ NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED,
+ NAN_PUBLISH_TYPE_LAST,
+} NanPublishType;
+
+/* NAN Transmit Priorities */
+typedef enum {
+ NAN_TX_PRIORITY_LOW = 0,
+ NAN_TX_PRIORITY_NORMAL,
+ NAN_TX_PRIORITY_HIGH,
+ NAN_TX_PRIORITY_LAST
+} NanTxPriority;
+
+/* NAN Statistics Request ID Codes */
+typedef enum
+{
+ NAN_STATS_ID_FIRST = 0,
+ NAN_STATS_ID_DE_PUBLISH = NAN_STATS_ID_FIRST,
+ NAN_STATS_ID_DE_SUBSCRIBE,
+ NAN_STATS_ID_DE_MAC,
+ NAN_STATS_ID_DE_TIMING_SYNC,
+ NAN_STATS_ID_DE_DW,
+ NAN_STATS_ID_DE,
+ NAN_STATS_ID_LAST
+} NanStatsId;
+
+/* NAN Protocol Event ID Codes */
+typedef enum
+{
+ NAN_EVENT_ID_FIRST = 0,
+ NAN_EVENT_ID_SELF_STA_MAC_ADDR = NAN_EVENT_ID_FIRST,
+ NAN_EVENT_ID_STARTED_CLUSTER,
+ NAN_EVENT_ID_JOINED_CLUSTER,
+ NAN_EVENT_ID_LAST
+} NanEventId;
+
+/* TCA IDs */
+typedef enum
+{
+ NAN_TCA_ID_FIRST = 0,
+ NAN_TCA_ID_CLUSTER_SIZE = NAN_TCA_ID_FIRST,
+ NAN_TCA_ID_LAST
+} NanTcaId;
+
+/*
+ Various NAN Protocol Response code
+*/
+typedef enum
+{
+ /* NAN Protocol Response Codes */
+ NAN_STATUS_SUCCESS = 0,
+ NAN_STATUS_TIMEOUT,
+ NAN_STATUS_DE_FAILURE,
+ NAN_STATUS_INVALID_MSG_VERSION,
+ NAN_STATUS_INVALID_MSG_LEN,
+ NAN_STATUS_INVALID_MSG_ID,
+ NAN_STATUS_INVALID_HANDLE,
+ NAN_STATUS_NO_SPACE_AVAILABLE,
+ NAN_STATUS_INVALID_PUBLISH_TYPE,
+ NAN_STATUS_INVALID_TX_TYPE,
+ NAN_STATUS_INVALID_MATCH_ALGORITHM,
+ NAN_STATUS_DISABLE_IN_PROGRESS,
+ NAN_STATUS_INVALID_TLV_LEN,
+ NAN_STATUS_INVALID_TLV_TYPE,
+ NAN_STATUS_MISSING_TLV_TYPE,
+ NAN_STATUS_INVALID_TOTAL_TLVS_LEN,
+ NAN_STATUS_INVALID_MATCH_HANDLE,
+ NAN_STATUS_INVALID_TLV_VALUE,
+ NAN_STATUS_INVALID_TX_PRIORITY,
+ NAN_STATUS_INVALID_TCA_ID,
+ NAN_STATUS_INVALID_STATS_ID,
+
+ /* NAN Configuration Response codes */
+ NAN_STATUS_INVALID_RSSI_CLOSE_VALUE = 128,
+ NAN_STATUS_INVALID_RSSI_MEDIUM_VALUE,
+ NAN_STATUS_INVALID_HOP_COUNT_LIMIT,
+ NAN_STATUS_INVALID_CLUSTER_JOIN_COUNT,
+ NAN_STATUS_INVALID_MIN_WAKE_DW_DURATION_VALUE,
+ NAN_STATUS_INVALID_OFDM_DATA_RATE_VALUE,
+ NAN_STATUS_INVALID_RANDOM_FACTOR_UPDATE_TIME_VALUE,
+ NAN_STATUS_INVALID_MASTER_PREFERENCE_VALUE,
+ NAN_STATUS_INVALID_EARLY_DW_WAKE_INTERVAL_VALUE,
+ NAN_STATUS_INVALID_LOW_CLUSTER_ID_VALUE,
+ NAN_STATUS_INVALID_HIGH_CLUSTER_ID_VALUE,
+ NAN_STATUS_INVALID_INITIAL_SCAN_PERIOD,
+ NAN_STATUS_INVALID_ONGOING_SCAN_PERIOD,
+ NAN_STATUS_INVALID_RSSI_PROXIMITY_VALUE
+} NanStatusType;
+
+/*
+ Various NAN Terminated Indication Code
+*/
+typedef enum
+{
+ NAN_TERMINATED_REASON_INVALID = 0,
+ NAN_TERMINATED_REASON_TIMEOUT,
+ NAN_TERMINATED_REASON_USER_REQUEST,
+ NAN_TERMINATED_REASON_FAILURE,
+ NAN_TERMINATED_REASON_COUNT_REACHED,
+ NAN_TERMINATED_REASON_DE_SHUTDOWN,
+ NAN_TERMINATED_REASON_DISABLE_IN_PROGRESS
+} NanTerminatedStatus;
+
+/* NAN Transmit Types */
+typedef enum
+{
+ NAN_TX_TYPE_BROADCAST = 0,
+ NAN_TX_TYPE_UNICAST,
+ NAN_TX_TYPE_LAST
+} NanTxType;
+
+/* NAN Subscribe Type Bit */
+#define NAN_SUBSCRIBE_TYPE_PASSIVE 0
+#define NAN_SUBSCRIBE_TYPE_ACTIVE 1
+
+/* NAN Service Response Filter Attribute Bit */
+#define NAN_SRF_ATTR_BLOOM_FILTER 0
+#define NAN_SRF_ATTR_PARTIAL_MAC_ADDR 1
+
+/* NAN Service Response Filter Include Bit */
+#define NAN_SRF_INCLUDE_DO_NOT_RESPOND 0
+#define NAN_SRF_INCLUDE_RESPOND 1
+
+/* NAN Match Algorithms */
+typedef enum
+{
+ NAN_MATCH_ALG_FIRST = 0,
+ NAN_MATCH_ALG_MATCH_ONCE = NAN_MATCH_ALG_FIRST,
+ NAN_MATCH_ALG_MATCH_CONTINUOUS,
+ NAN_MATCH_ALG_LAST
+} NanMatchAlg;
+
+/* NAN Header */
+typedef struct {
+ /*
+ 16-bit quantity which is allocated by the FW.
+ Pass the Handle as 0xFFFF if the Host would like to set up a new
+ Publish/Subscribe and the FW will pass back a valid handle in response msg.
+ To update an already opened Publish/Subscribe Host can pass a Handle
+ which has already been allocated by the FW.
+ */
+ u16 handle;
+
+ /*
+ 16-bit quantity which is allocated in 2 contexts. For all Request
+ messages the TransactionId is allocated by the Service Layer and
+ passed down to the DE. In all Indication messages the TransactionId
+ field is allocated by the DE. There is no correlation between the
+ TransactionIds allocated by the Service Layer and those allocated by the DE
+ */
+ u16 transaction_id;
+} NanHeader;
+
+/*
+ Enable Request Message Structure
+ The NanEnableReq message instructs the Discovery Engine to enter an operational state
+*/
+typedef struct {
+ NanHeader header;
+ u8 support_5g; /* default = 0 */
+ u16 cluster_low; /* default = 0 */
+ u16 cluster_high; /* default = 0 */
+ u8 sid_beacon; /* default = 0x80 */
+ u8 sync_disc_5g; /* default = 1 i.e 5G Discovery frames only*/
+ u8 rssi_close; /* default = 60 (-60 dBm) */
+ u8 rssi_middle; /* default = 70 (-70 dBm) */
+ u8 rssi_proximity; /* default = 70 (-70 dBm) */
+ u8 hop_count_limit; /* default = 2 */
+ u8 random_time; /* default = 120 (DWs) */
+ u8 master_pref; /* default = 0 */
+ u8 periodic_scan_interval; /* default = 20 seconds */
+ /* TBD: Google specific IE */
+}NanEnableRequest;
+
+/*
+ Disable Request Message Structure
+ The NanDisableReq message instructs the Discovery Engine to exit an operational state.
+*/
+typedef struct {
+ NanHeader header;
+}NanDisableRequest;
+
+/*
+ Publish Msg Structure
+ Message is used to request the DE to publish the Service Name
+ using the parameters passed into the Discovery Window
+*/
+typedef struct {
+ NanHeader header;
+ u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+ u16 period; /* periodicity of OTA unsolicited publish. Specified in increments of 500 ms */
+ u8 replied_event_flag; /* 1= RepliedEventInd needed, 0 = Not needed */
+ NanPublishType publish_type;/* 0= unsolicited, solicited = 1, 2= both */
+ NanTxType tx_type; /* 0 = broadcast, 1= unicast if solicited publish */
+ u8 publish_count; /* number of OTA Publish, 0 means forever until canceled */
+ u16 service_name_len; /* length of service name */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN];/* UTF-8 encoded string identifying the service */
+
+ /* Sequence of values which should be conveyed to the Discovery Engine of a
+ NAN Device that has invoked a Subscribe method corresponding to this Publish method
+ */
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /* Ordered sequence of <length, value> pairs which specify further response conditions
+ beyond the service name used to filter subscribe messages to respond to.
+ This is only needed when the PT is set to NAN_SOLICITED or NAN_SOLICITED_UNSOLICITED.
+ */
+ u16 rx_match_filter_len;
+ u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /* Ordered sequence of <length, value> pairs to be included in the Discovery Frame.
+ If present it is always sent in a Discovery Frame
+ */
+ u16 tx_match_filter_len;
+ u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanPublishRequest;
+
+/*
+ Publish Cancel Msg Structure
+ The PublishServiceCancelReq Message is used to request the DE to stop publishing
+ the Service Name identified by the handle in the message.
+*/
+typedef struct {
+ NanHeader header;
+}NanPublishCancelRequest;
+
+/*
+ NAN Subscribe Structure
+ The SubscribeServiceReq message is sent to the Discovery Engine
+ whenever the Upper layers would like to listen for a Service Name
+*/
+typedef struct {
+ NanHeader header;
+ u16 ttl; /* how many seconds to run for. 0 means forever until canceled */
+ u16 period;/* periodicity of OTA Active Subscribe. Units in increments of 500 ms , 0 = attempt every DW*/
+
+ /* Flag which specifies how the Subscribe request shall be processed. */
+ u8 subscribe_type; /* 0 - PASSIVE , 1- ACTIVE */
+
+ /* Flag which specifies on Active Subscribes how the Service Response Filter attribute is populated.*/
+ u8 serviceResponseFilter; /* 0 - Bloom Filter, 1 - MAC Addr */
+
+ /* Flag which specifies how the Service Response Filter Include bit is populated.*/
+ u8 serviceResponseInclude; /* 0=Do not respond if in the Address Set, 1= Respond */
+
+ /* Flag which specifies if the Service Response Filter should be used when creating Subscribes.*/
+ u8 useServiceResponseFilter; /* 0=Do not send the Service Response Filter,1= send */
+
+ /* Flag which specifies if the Service Specific Info is needed in the Publish message before creating the MatchIndication*/
+ u8 ssiRequiredForMatchIndication; /* 0=Not needed, 1= Required */
+
+ /* Field which allows the matching behavior to be controlled. */
+ NanMatchAlg subscribe_match; /* 0 - Match Once, 1 - Match continuous */
+
+ /* The number of Subscribe Matches which should occur before the Subscribe request is automatically terminated.*/
+ u8 subscribe_count; /* If this value is 0 this field is not used by the DE.*/
+
+ u16 service_name_len;/* length of service name */
+ u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+
+ /* Sequence of values which further specify the published service beyond the service name*/
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+ /* Ordered sequence of <length, value> pairs used to filter out received publish discovery messages.
+ This can be sent both for a Passive or an Active Subscribe
+ */
+ u16 rx_match_filter_len;
+ u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+ /* Ordered sequence of <length, value> pairs included in the Discovery Frame when an Active Subscribe is used.*/
+ u16 tx_match_filter_len;
+ u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanSubscribeRequest;
+
+
+/*
+ NAN Subscribe Cancel Structure
+ The SubscribeCancelReq Message is used to request the DE to stop looking for the Service Name.
+*/
+typedef struct {
+ NanHeader header;
+}NanSubscribeCancelRequest;
+
+
+/*
+ Transmit follow up Structure
+ The TransmitFollowupReq message is sent to the DE to allow the sending of the Service_Specific_Info
+ to a particular MAC address.
+*/
+typedef struct {
+ NanHeader header;
+ u8 addr[NAN_MAC_ADDR_LEN]; /* Can be a broadcast/multicast or unicast address */
+ NanTxPriority priority; /* priority of the request 0 = low, 1=normal, 2=high */
+ u8 dw_or_faw; /* 0= send in a DW, 1=send in FAW */
+
+ /* Sequence of values which further specify the published service beyond the service name
+ Treated as service specific info in case dw_or_faw is set to 0
+ Treated as extended service specific info in case dw_or_faw is set to non-zero*/
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+}NanTransmitFollowupRequest;
+
+/*
+ Stats Request structure
+ The Discovery Engine can be queried at runtime by the Host processor for statistics
+ concerning various parts of the Discovery Engine.
+*/
+typedef struct {
+ NanHeader header;
+ NanStatsId stats_id; /* NAN Statistics Request ID Codes */
+ u8 clear; /* 0= Do not clear the stats and return the current contents , 1= Clear the associated stats */
+}NanStatsRequest;
+
+/*
+ Config Structure
+ The NanConfigurationReq message is sent by the Host to the
+ Discovery Engine in order to configure the Discovery Engine during runtime.
+*/
+typedef struct {
+ NanHeader header;
+ u8 sid_beacon; /* default = 0x80 */
+ u8 sync_disc_5g; /* default = 1 i.e 5G Discovery frames only*/
+ u8 rssi_proximity; /* default = 70 (-70 dBm) */
+ u8 random_time; /* default = 120 (DWs) */
+ u8 master_pref; /* default = 0 */
+ u8 periodic_scan_interval; /* default = 20 seconds */
+ /* The number of Additional Discovery Window slots in
+ increments of 16 ms. Since each DW is 512 TUs apart
+ and the DW takes up 1 slot, the maximum number of additional
+ slots which can be specified is 31. This is a hint to the
+ scheduler and there is no guarantee that all 31 slots will
+ be available because of MCC and BT Coexistence channel usage
+ */
+ u8 additional_disc_window_slots; /* default = 0.*/
+}NanConfigRequest;
+
+/*
+ TCA Structure
+ The Discovery Engine can be configured to send up Events whenever a configured
+ Threshold Crossing Alert (TCA) Id crosses an integral threshold in a particular direction.
+*/
+typedef struct {
+ NanHeader header;
+ NanTcaId tca_id; /* Nan Protocol Threshold Crossing Alert (TCA) Codes */
+
+ /* flag which control whether or not an event is generated for the Rising direction */
+ u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+ /* flag which control whether or not an event is generated for the Falling direction */
+ u8 falling_direction_evt_flag;/* 0 - no event, 1 - event */
+
+ /* flag which requests a previous TCA request to be cleared from the DE */
+ u8 clear;/*0= Do not clear the TCA, 1=Clear the TCA */
+
+ /* 32 bit value which represents the threshold to be used.*/
+ u32 threshold;
+}NanTCARequest;
+
+/* Publish statistics. */
+typedef struct
+{
+ u32 validPublishServiceReqMsgs;
+ u32 validPublishServiceRspMsgs;
+ u32 validPublishServiceCancelReqMsgs;
+ u32 validPublishServiceCancelRspMsgs;
+ u32 validPublishRepliedIndMsgs;
+ u32 validPublishTerminatedIndMsgs;
+ u32 validActiveSubscribes;
+ u32 validMatches;
+ u32 validFollowups;
+ u32 invalidPublishServiceReqMsgs;
+ u32 invalidPublishServiceCancelReqMsgs;
+ u32 invalidActiveSubscribes;
+ u32 invalidMatches;
+ u32 invalidFollowups;
+ u32 publishCount;
+} NanPublishStats;
+
+/* Subscribe statistics. */
+typedef struct
+{
+ u32 validSubscribeServiceReqMsgs;
+ u32 validSubscribeServiceRspMsgs;
+ u32 validSubscribeServiceCancelReqMsgs;
+ u32 validSubscribeServiceCancelRspMsgs;
+ u32 validSubscribeTerminatedIndMsgs;
+ u32 validSubscribeMatchIndMsgs;
+ u32 validSubscribeUnmatchIndMsgs;
+ u32 validSolicitedPublishes;
+ u32 validMatches;
+ u32 validFollowups;
+ u32 invalidSubscribeServiceReqMsgs;
+ u32 invalidSubscribeServiceCancelReqMsgs;
+ u32 invalidSubscribeFollowupReqMsgs;
+ u32 invalidSolicitedPublishes;
+ u32 invalidMatches;
+ u32 invalidFollowups;
+ u32 subscribeCount;
+ u32 bloomFilterIndex;
+} NanSubscribeStats;
+
+/* NAN MAC Statistics. Used for MAC and DW statistics. */
+typedef struct
+{
+ /* RX stats */
+ u32 validFrames;
+ u32 validActionFrames;
+ u32 validBeaconFrames;
+ u32 ignoredActionFrames;
+ u32 ignoredBeaconFrames;
+ u32 invalidFrames;
+ u32 invalidActionFrames;
+ u32 invalidBeaconFrames;
+ u32 invalidMacHeaders;
+ u32 invalidPafHeaders;
+ u32 nonNanBeaconFrames;
+
+ u32 earlyActionFrames;
+ u32 inDwActionFrames;
+ u32 lateActionFrames;
+
+ /* TX stats */
+ u32 framesQueued;
+ u32 totalTRSpUpdates;
+ u32 completeByTRSp;
+ u32 completeByTp75DW;
+ u32 completeByTendDW;
+ u32 lateActionFramesTx;
+
+ /* Misc stats - ignored for DW. */
+ u32 twIncreases;
+ u32 twDecreases;
+ u32 twChanges;
+ u32 twHighwater;
+ u32 bloomFilterIndex;
+} NanMacStats;
+
+/* NAN Sync Statistics*/
+typedef struct
+{
+ u64 currTsf;
+ u64 myRank;
+ u64 currAmRank;
+ u64 lastAmRank;
+ u32 currAmBTT;
+ u32 lastAmBTT;
+ u8 currAmHopCount;
+ u8 currRole;
+ u16 currClusterId;
+
+ u64 timeSpentInCurrRole;
+ u64 totalTimeSpentAsMaster;
+ u64 totalTimeSpentAsNonMasterSync;
+ u64 totalTimeSpentAsNonMasterNonSync;
+ u32 transitionsToAnchorMaster;
+ u32 transitionsToMaster;
+ u32 transitionsToNonMasterSync;
+ u32 transitionsToNonMasterNonSync;
+ u32 amrUpdateCount;
+ u32 amrUpdateRankChangedCount;
+ u32 amrUpdateBTTChangedCount;
+ u32 amrUpdateHcChangedCount;
+ u32 amrUpdateNewDeviceCount;
+ u32 amrExpireCount;
+ u32 mergeCount;
+ u32 beaconsAboveHcLimit;
+ u32 beaconsBelowRssiThresh;
+ u32 beaconsIgnoredNoSpace;
+ u32 beaconsForOurCluster;
+ u32 beaconsForOtherCluster;
+ u32 beaconCancelRequests;
+ u32 beaconCancelFailures;
+ u32 beaconUpdateRequests;
+ u32 beaconUpdateFailures;
+ u32 syncBeaconTxAttempts;
+ u32 discBeaconTxAttempts;
+} NanSyncStats;
+
+/* NAN Misc DE Statistics */
+typedef struct
+{
+ u32 validErrorRspMsgs;
+ u32 validTransmitFollowupReqMsgs;
+ u32 validTransmitFollowupRspMsgs;
+ u32 validFollowupIndMsgs;
+ u32 validConfigurationReqMsgs;
+ u32 validConfigurationRspMsgs;
+ u32 validStatsReqMsgs;
+ u32 validStatsRspMsgs;
+ u32 validEnableReqMsgs;
+ u32 validEnableRspMsgs;
+ u32 validDisableReqMsgs;
+ u32 validDisableRspMsgs;
+ u32 validDisableIndMsgs;
+ u32 validEventIndMsgs;
+ u32 validTcaReqMsgs;
+ u32 validTcaRspMsgs;
+ u32 validTcaIndMsgs;
+ u32 invalidTransmitFollowupReqMsgs;
+ u32 invalidConfigurationReqMsgs;
+ u32 invalidStatsReqMsgs;
+ u32 invalidEnableReqMsgs;
+ u32 invalidDisableReqMsgs;
+ u32 invalidTcaReqMsgs;
+} NanDeStats;
+
+/*
+ Stats Response Message structure
+ The Discovery Engine response to a request by the Host for statistics.
+*/
+typedef struct {
+ NanStatsId stats_id;
+ union {
+ NanPublishStats publish_stats;
+ NanSubscribeStats subscribe_stats;
+ NanMacStats mac_stats;
+ NanSyncStats sync_stats;
+ NanDeStats de_stats;
+ }data;
+}NanStatsResponse;
+
+/*
+ NAN Response messages
+*/
+typedef struct {
+ NanHeader header;
+ u16 status; /* contains the result code */
+ u16 value; /* For error returns the value is returned which was in error */
+ NanResponseType response_type; /* NanResponseType Definitions */
+ union {
+ NanStatsResponse stats_response;
+ }body;
+}NanResponseMsg;
+
+
+/*
+ Publish Replied Indication
+ The PublishRepliedInd Message is sent by the DE when an Active Subscribe is
+ received over the air and it matches a Solicited PublishServiceReq which had
+ been created with the replied_event_flag set.
+*/
+typedef struct {
+ NanHeader header;
+ u8 addr[NAN_MAC_ADDR_LEN];
+}NanPublishRepliedInd;
+
+/*
+ Publish Terminated
+ The PublishTerminatedInd message is sent by the DE whenever a Publish
+ terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+ NanHeader header;
+ NanTerminatedStatus reason;
+}NanPublishTerminatedInd;
+
+/*
+ Subscribe Match Indication
+ The SubscribeMatchInd message is sent once per responding MAC address whenever
+ the Discovery Engine detects a match for a previous SubscribeServiceReq.
+*/
+typedef struct {
+ NanHeader header;
+
+ /* a 16 bit Handle which is sent to the Application. This handle will be sent in any subsequent
+ UnmatchInd messages rather than resending the Match_Filter/Service_Specific_Info TLVs
+ The Match_Handle is a DE resource and it is of limited quantity. In the event that the DE
+ runs out of Match_Handles the DE will still send the SubscribeMatchInd message but will
+ set the Match_Handle to MATCH_HANDLE_MATCH_POOL_EXHAUSTED=0xFFFF
+ */
+ u16 match_handle;
+ u8 addr[NAN_MAC_ADDR_LEN];
+
+ /* Sequence of octets which were received in a Discovery Frame matching this
+ Subscribe Request.*/
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_NAME_LEN];
+
+ /* Ordered sequence of <length, value> pairs received in the Discovery Frame
+ matching this Subscribe Request.*/
+ u16 sdf_match_filter_len;
+ u8 sdf_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+}NanSubscribeMatchInd;
+
+/*
+ Subscribe UnMatch
+ The SubscribeUnmatchInd message is sent whenever the Discovery Engine detects that
+ a previously Matched Subscribed Service Name has been gone for too long.
+ If the previous SubscribeMatchInd message contained a Match_Handle equal to
+ MATCH_HANDLE_MATCH_POOL_EXHAUSTED then this message will not be sent to the Host.
+*/
+typedef struct {
+ NanHeader header;
+ /* 16 bit value sent by the DE in a previous SubscribeMatchInd to the application. */
+ u16 match_handle;
+}NanSubscribeUnmatchInd;
+
+/*
+ Subscribe Terminated
+ The SubscribeTerminatedInd message is sent by the DE whenever a
+ Subscribe terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+ NanHeader header;
+ NanTerminatedStatus reason;
+}NanSubscribeTerminatedInd;
+
+/*
+ Followup Indication Message
+ The FollowupInd message is sent by the DE to the Host whenever it receives a
+ Followup message from another peer.
+*/
+typedef struct {
+ NanHeader header;
+ u8 addr[NAN_MAC_ADDR_LEN];
+
+ /* Flag which the DE uses to decide if received in a DW or a FAW*/
+ u8 dw_or_faw; /* 0=Received in a DW, 1 = Received in a FAW*/
+
+ /* Sequence of values which further specify the published service beyond the service name
+ Service specific info in case dw_or_faw is set to 0
+ Extended service specific info in case dw_or_faw is set to non-zero*/
+ u16 service_specific_info_len;
+ u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+}NanFollowupInd;
+
+/* Selfstaevent data*/
+typedef struct {
+ u8 addr[NAN_MAC_ADDR_LEN];
+}NanSelfStaEvent;
+
+/* joined or Started cluster data*/
+typedef struct {
+ u8 addr[NAN_MAC_ADDR_LEN];
+}NanClusterEventData;
+
+/*
+ Discovery Engine Event Indication
+ The Discovery Engine can inform the Host when significant events occur
+ The data following the EventId is dependent upon the EventId type.
+ In other words, each new event defined will carry a different
+ structure of information back to the host.
+*/
+typedef struct {
+ NanHeader header;
+ NanEventId event_id; /* NAN Protocol Event Codes */
+ union {
+ /* SelfStaEvent which will have 6 byte mac address
+ of the Discovery engine.*/
+ NanSelfStaEvent self_sta;
+ /* Cluster Event Data which will be obtained when the
+ device starts a new cluster or joins a cluster.
+ The event data will have 6 byte octet string of the
+ cluster started or joined.*/
+ NanClusterEventData cluster;
+ }data;
+}NanDiscEngEventInd;
+
+/* Cluster size TCA data*/
+typedef struct {
+ u16 cluster_size;
+}NanTcaClusterData;
+
+/*
+ NAN TCA Indication
+ The Discovery Engine can inform the Host when significant events occur.
+ The data following the TcaId is dependent upon the TcaId type.
+ In other words, each new event defined will carry a different structure
+ of information back to the host.
+*/
+typedef struct {
+ NanHeader header;
+ NanTcaId tca_id;
+ union {
+ /* This event in obtained when the cluser size threshold
+ is crossed. Event will have the cluster size */
+ NanTcaClusterData cluster;
+ }data;
+}NanTCAInd;
+
+/*
+ NAN Disabled Indication
+ The NanDisableInd message indicates to the upper layers that the Discovery
+ Engine has flushed all state and has been shutdown. When this message is received
+ the DE is guaranteed to have left the NAN cluster it was part of and will have terminated
+ any in progress Publishes or Subscribes.
+*/
+typedef struct {
+ NanHeader header;
+ NanStatusType reason;
+}NanDisabledInd;
+
+/* Response and Event Callbacks */
+typedef struct {
+ /* NotifyResponse invoked to notify the status of the Request */
+ void (*NotifyResponse)(NanResponseMsg* rsp_data);
+ /* Various Events Callback */
+ void (*EventPublishReplied)(NanPublishRepliedInd* event);
+ void (*EventPublishTerminated)(NanPublishTerminatedInd* event);
+ void (*EventSubscribeMatch) (NanSubscribeMatchInd* event);
+ void (*EventSubscribeUnMatch) (NanSubscribeUnmatchInd* event);
+ void (*EventSubscribeTerminated) (NanSubscribeTerminatedInd* event);
+ void (*EventFollowup) (NanFollowupInd* event);
+ void (*EventDiscEngEvent) (NanDiscEngEventInd* event);
+ void (*EventDisabled) (NanDisabledInd* event);
+ void (*EventTca) (NanTCAInd* event);
+} NanCallbackHandler;
+
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_enable_request(wifi_request_id id,
+ wifi_handle handle,
+ NanEnableRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_disable_request(wifi_request_id id,
+ wifi_handle handle,
+ NanDisableRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_publish_request(wifi_request_id id,
+ wifi_handle handle,
+ NanPublishRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_publish_cancel_request(wifi_request_id id,
+ wifi_handle handle,
+ NanPublishCancelRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_subscribe_request(wifi_request_id id,
+ wifi_handle handle,
+ NanSubscribeRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_subscribe_cancel_request(wifi_request_id id,
+ wifi_handle handle,
+ NanSubscribeCancelRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_transmit_followup_request(wifi_request_id id,
+ wifi_handle handle,
+ NanTransmitFollowupRequest* msg);
+
+/* Function to send NAN statistics request to the wifi driver.*/
+wifi_error nan_stats_request(wifi_request_id id,
+ wifi_handle handle,
+ NanStatsRequest* msg);
+
+/* Function to send NAN configuration request to the wifi driver.*/
+wifi_error nan_config_request(wifi_request_id id,
+ wifi_handle handle,
+ NanConfigRequest* msg);
+
+/* Function to send NAN request to the wifi driver.*/
+wifi_error nan_tca_request(wifi_request_id id,
+ wifi_handle handle,
+ NanTCARequest* msg);
+
+/* Function to register NAN callback */
+wifi_error nan_register_handler(wifi_handle handle,
+ NanCallbackHandler handlers);
+
+/* Function to get version of the NAN HAL */
+wifi_error nan_get_version(wifi_handle handle,
+ NanVersion* version);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NAN_H__ */
diff --git a/libhardware_legacy/include/hardware_legacy/wifi_offload.h b/libhardware_legacy/include/hardware_legacy/wifi_offload.h
new file mode 100644
index 0000000..f0326f1
--- /dev/null
+++ b/libhardware_legacy/include/hardware_legacy/wifi_offload.h
@@ -0,0 +1,31 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_OFFLOAD_H
+#define __WIFI_HAL_OFFLOAD_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#define ETHER_ADDR_LEN 6 // Ethernet frame address length
+#define N_AVAIL_ID 3 // available mkeep_alive IDs from 1 to 3
+#define MKEEP_ALIVE_IP_PKT_MAX 256 // max size of IP packet for keep alive
+
+/**
+ * Send specified keep alive packet periodically.
+ */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface,
+ u8 *ip_packet, u16 ip_packet_len, u8 *src_mac_addr, u8 *dst_mac_addr, u32 period_msec);
+
+/**
+ * Stop sending keep alive packet.
+ */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_OFFLOAD_H */
diff --git a/libhardware_legacy/power/Android.mk b/libhardware_legacy/power/Android.mk
new file mode 100644
index 0000000..3e3ff5d
--- /dev/null
+++ b/libhardware_legacy/power/Android.mk
@@ -0,0 +1,3 @@
+# Copyright 2006 The Android Open Source Project
+
+LOCAL_SRC_FILES += power/power.c
diff --git a/libhardware_legacy/power/power.c b/libhardware_legacy/power/power.c
new file mode 100644
index 0000000..368de5b
--- /dev/null
+++ b/libhardware_legacy/power/power.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <hardware_legacy/power.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#define LOG_TAG "power"
+#include <utils/Log.h>
+
+enum {
+ ACQUIRE_PARTIAL_WAKE_LOCK = 0,
+ RELEASE_WAKE_LOCK,
+ OUR_FD_COUNT
+};
+
+const char * const OLD_PATHS[] = {
+ "/sys/android_power/acquire_partial_wake_lock",
+ "/sys/android_power/release_wake_lock",
+};
+
+const char * const NEW_PATHS[] = {
+ "/sys/power/wake_lock",
+ "/sys/power/wake_unlock",
+};
+
+//XXX static pthread_once_t g_initialized = THREAD_ONCE_INIT;
+static int g_initialized = 0;
+static int g_fds[OUR_FD_COUNT];
+static int g_error = -1;
+
+static int
+open_file_descriptors(const char * const paths[])
+{
+ int i;
+ for (i=0; i<OUR_FD_COUNT; i++) {
+ int fd = open(paths[i], O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ g_error = -errno;
+ fprintf(stderr, "fatal error opening \"%s\": %s\n", paths[i],
+ strerror(errno));
+ return -1;
+ }
+ g_fds[i] = fd;
+ }
+
+ g_error = 0;
+ return 0;
+}
+
+static inline void
+initialize_fds(void)
+{
+ // XXX: should be this:
+ //pthread_once(&g_initialized, open_file_descriptors);
+ // XXX: not this:
+ if (g_initialized == 0) {
+ if(open_file_descriptors(NEW_PATHS) < 0)
+ open_file_descriptors(OLD_PATHS);
+ g_initialized = 1;
+ }
+}
+
+int
+acquire_wake_lock(int lock, const char* id)
+{
+ initialize_fds();
+
+// ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);
+
+ if (g_error) return g_error;
+
+ int fd;
+ size_t len;
+ ssize_t ret;
+
+ if (lock != PARTIAL_WAKE_LOCK) {
+ return -EINVAL;
+ }
+
+ fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
+
+ ret = write(fd, id, strlen(id));
+ if (ret < 0) {
+ return -errno;
+ }
+
+ return ret;
+}
+
+int
+release_wake_lock(const char* id)
+{
+ initialize_fds();
+
+// ALOGI("release_wake_lock id='%s'\n", id);
+
+ if (g_error) return g_error;
+
+ ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));
+ if (len < 0) {
+ return -errno;
+ }
+ return len;
+}
diff --git a/libhardware_legacy/uevent/Android.mk b/libhardware_legacy/uevent/Android.mk
new file mode 100644
index 0000000..2d8b524
--- /dev/null
+++ b/libhardware_legacy/uevent/Android.mk
@@ -0,0 +1,3 @@
+# Copyright 2008 The Android Open Source Project
+
+LOCAL_SRC_FILES += uevent/uevent.c
diff --git a/libhardware_legacy/uevent/uevent.c b/libhardware_legacy/uevent/uevent.c
new file mode 100644
index 0000000..e40aa2e
--- /dev/null
+++ b/libhardware_legacy/uevent/uevent.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware_legacy/uevent.h>
+
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#include <pthread.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/queue.h>
+#include <linux/netlink.h>
+
+
+LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
+pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+struct uevent_handler {
+ void (*handler)(void *data, const char *msg, int msg_len);
+ void *handler_data;
+ LIST_ENTRY(uevent_handler) list;
+};
+
+static int fd = -1;
+
+/* Returns 0 on failure, 1 on success */
+int uevent_init()
+{
+ struct sockaddr_nl addr;
+ int sz = 64*1024;
+ int s;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = getpid();
+ addr.nl_groups = 0xffffffff;
+
+ s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ if(s < 0)
+ return 0;
+
+ setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+ if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(s);
+ return 0;
+ }
+
+ fd = s;
+ return (fd > 0);
+}
+
+int uevent_get_fd()
+{
+ return fd;
+}
+
+int uevent_next_event(char* buffer, int buffer_length)
+{
+ while (1) {
+ struct pollfd fds;
+ int nr;
+
+ fds.fd = fd;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ nr = poll(&fds, 1, -1);
+
+ if(nr > 0 && (fds.revents & POLLIN)) {
+ int count = recv(fd, buffer, buffer_length, 0);
+ if (count > 0) {
+ struct uevent_handler *h;
+ pthread_mutex_lock(&uevent_handler_list_lock);
+ LIST_FOREACH(h, &uevent_handler_list, list)
+ h->handler(h->handler_data, buffer, buffer_length);
+ pthread_mutex_unlock(&uevent_handler_list_lock);
+
+ return count;
+ }
+ }
+ }
+
+ // won't get here
+ return 0;
+}
+
+int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
+ void *handler_data)
+{
+ struct uevent_handler *h;
+
+ h = malloc(sizeof(struct uevent_handler));
+ if (h == NULL)
+ return -1;
+ h->handler = handler;
+ h->handler_data = handler_data;
+
+ pthread_mutex_lock(&uevent_handler_list_lock);
+ LIST_INSERT_HEAD(&uevent_handler_list, h, list);
+ pthread_mutex_unlock(&uevent_handler_list_lock);
+
+ return 0;
+}
+
+int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len))
+{
+ struct uevent_handler *h;
+ int err = -1;
+
+ pthread_mutex_lock(&uevent_handler_list_lock);
+ LIST_FOREACH(h, &uevent_handler_list, list) {
+ if (h->handler == handler) {
+ LIST_REMOVE(h, list);
+ err = 0;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&uevent_handler_list_lock);
+
+ return err;
+}
diff --git a/libhardware_legacy/wifi/Android.mk b/libhardware_legacy/wifi/Android.mk
new file mode 100644
index 0000000..ed59b40
--- /dev/null
+++ b/libhardware_legacy/wifi/Android.mk
@@ -0,0 +1,44 @@
+# Copyright 2006 The Android Open Source Project
+
+ifdef WIFI_DRIVER_MODULE_PATH
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_PATH=\"$(WIFI_DRIVER_MODULE_PATH)\"
+endif
+ifdef WIFI_DRIVER_MODULE_ARG
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_ARG=\"$(WIFI_DRIVER_MODULE_ARG)\"
+endif
+ifdef WIFI_DRIVER_MODULE_NAME
+LOCAL_CFLAGS += -DWIFI_DRIVER_MODULE_NAME=\"$(WIFI_DRIVER_MODULE_NAME)\"
+endif
+ifdef WIFI_FIRMWARE_LOADER
+LOCAL_CFLAGS += -DWIFI_FIRMWARE_LOADER=\"$(WIFI_FIRMWARE_LOADER)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_STA
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_STA=\"$(WIFI_DRIVER_FW_PATH_STA)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_AP
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_AP=\"$(WIFI_DRIVER_FW_PATH_AP)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_P2P
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_P2P=\"$(WIFI_DRIVER_FW_PATH_P2P)\"
+endif
+ifdef WIFI_DRIVER_FW_PATH_PARAM
+LOCAL_CFLAGS += -DWIFI_DRIVER_FW_PATH_PARAM=\"$(WIFI_DRIVER_FW_PATH_PARAM)\"
+endif
+
+ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_CTRL_PARAM=\"$(WIFI_DRIVER_STATE_CTRL_PARAM)\"
+endif
+ifdef WIFI_DRIVER_STATE_ON
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_ON=\"$(WIFI_DRIVER_STATE_ON)\"
+endif
+ifdef WIFI_DRIVER_STATE_OFF
+LOCAL_CFLAGS += -DWIFI_DRIVER_STATE_OFF=\"$(WIFI_DRIVER_STATE_OFF)\"
+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/libhardware_legacy/wifi/wifi.c b/libhardware_legacy/wifi/wifi.c
new file mode 100644
index 0000000..880f6fc
--- /dev/null
+++ b/libhardware_legacy/wifi/wifi.c
@@ -0,0 +1,834 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#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"
+#include "cutils/memory.h"
+#include "cutils/misc.h"
+#include "cutils/properties.h"
+#include "private/android_filesystem_config.h"
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+extern int do_dhcp();
+extern int ifc_init();
+extern void ifc_close();
+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
+// sockets is in
+
+#ifndef WIFI_DRIVER_MODULE_ARG
+#define WIFI_DRIVER_MODULE_ARG ""
+#endif
+#ifndef WIFI_FIRMWARE_LOADER
+#define WIFI_FIRMWARE_LOADER ""
+#endif
+#define WIFI_TEST_INTERFACE "sta"
+
+#ifndef WIFI_DRIVER_FW_PATH_STA
+#define WIFI_DRIVER_FW_PATH_STA NULL
+#endif
+#ifndef WIFI_DRIVER_FW_PATH_AP
+#define WIFI_DRIVER_FW_PATH_AP NULL
+#endif
+#ifndef WIFI_DRIVER_FW_PATH_P2P
+#define WIFI_DRIVER_FW_PATH_P2P NULL
+#endif
+
+#ifndef WIFI_DRIVER_FW_PATH_PARAM
+#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath"
+#endif
+
+#define WIFI_DRIVER_LOADER_DELAY 1000000
+
+static const char IFACE_DIR[] = "/data/system/wpa_supplicant";
+#ifdef WIFI_DRIVER_MODULE_PATH
+static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME;
+static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " ";
+static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH;
+static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG;
+#endif
+static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER;
+static const char DRIVER_PROP_NAME[] = "wlan.driver.status";
+static const char SUPPLICANT_NAME[] = "wpa_supplicant";
+static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant";
+static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant";
+static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant";
+static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
+static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf";
+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,
+ 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
+ 0xf3, 0xf4, 0xf5 };
+
+/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */
+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 insmod(const char *filename, const char *args)
+{
+ void *module;
+ unsigned int size;
+ int ret;
+
+ module = load_file(filename, &size);
+ if (!module)
+ return -1;
+
+ ret = init_module(module, size, args);
+
+ free(module);
+
+ return ret;
+}
+
+static int rmmod(const char *modname)
+{
+ int ret = -1;
+ int maxtry = 10;
+
+ while (maxtry-- > 0) {
+ ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+ if (ret < 0 && errno == EAGAIN)
+ usleep(500000);
+ else
+ break;
+ }
+
+ if (ret != 0)
+ ALOGD("Unable to unload driver module \"%s\": %s\n",
+ modname, strerror(errno));
+ return ret;
+}
+
+int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
+ int *dns1, int *dns2, int *server, int *lease) {
+ /* For test driver, always report success */
+ if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
+ return 0;
+
+ if (ifc_init() < 0)
+ return -1;
+
+ if (do_dhcp(primary_iface) < 0) {
+ ifc_close();
+ return -1;
+ }
+ ifc_close();
+ get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
+ return 0;
+}
+
+const char *get_dhcp_error_string() {
+ return dhcp_lasterror();
+}
+
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+int wifi_change_driver_state(const char *state)
+{
+ int len;
+ int fd;
+ int ret = 0;
+
+ if (!state)
+ return -1;
+ fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
+ if (fd < 0) {
+ ALOGE("Failed to open driver state control param (%s)", strerror(errno));
+ return -1;
+ }
+ len = strlen(state) + 1;
+ if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
+ ALOGE("Failed to write driver state control param (%s)", strerror(errno));
+ ret = -1;
+ }
+ close(fd);
+ return ret;
+}
+#endif
+
+int is_wifi_driver_loaded() {
+ char driver_status[PROPERTY_VALUE_MAX];
+#ifdef WIFI_DRIVER_MODULE_PATH
+ FILE *proc;
+ char line[sizeof(DRIVER_MODULE_TAG)+10];
+#endif
+
+ if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
+ || strcmp(driver_status, "ok") != 0) {
+ return 0; /* driver not loaded */
+ }
+#ifdef WIFI_DRIVER_MODULE_PATH
+ /*
+ * If the property says the driver is loaded, check to
+ * make sure that the property setting isn't just left
+ * over from a previous manual shutdown or a runtime
+ * crash.
+ */
+ if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
+ ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
+ property_set(DRIVER_PROP_NAME, "unloaded");
+ return 0;
+ }
+ while ((fgets(line, sizeof(line), proc)) != NULL) {
+ if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
+ fclose(proc);
+ return 1;
+ }
+ }
+ fclose(proc);
+ property_set(DRIVER_PROP_NAME, "unloaded");
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+int wifi_load_driver()
+{
+#ifdef WIFI_DRIVER_MODULE_PATH
+ char driver_status[PROPERTY_VALUE_MAX];
+ int count = 100; /* wait at most 20 seconds for completion */
+
+ if (is_wifi_driver_loaded()) {
+ return 0;
+ }
+
+ if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
+ return -1;
+
+ if (strcmp(FIRMWARE_LOADER,"") == 0) {
+ /* usleep(WIFI_DRIVER_LOADER_DELAY); */
+ property_set(DRIVER_PROP_NAME, "ok");
+ }
+ else {
+ property_set("ctl.start", FIRMWARE_LOADER);
+ }
+ sched_yield();
+ while (count-- > 0) {
+ if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
+ if (strcmp(driver_status, "ok") == 0)
+ return 0;
+ else if (strcmp(driver_status, "failed") == 0) {
+ wifi_unload_driver();
+ return -1;
+ }
+ }
+ usleep(200000);
+ }
+ property_set(DRIVER_PROP_NAME, "timeout");
+ wifi_unload_driver();
+ return -1;
+#else
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+ if (is_wifi_driver_loaded()) {
+ return 0;
+ }
+
+ if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0)
+ return -1;
+#endif
+ property_set(DRIVER_PROP_NAME, "ok");
+ return 0;
+#endif
+}
+
+int wifi_unload_driver()
+{
+ usleep(200000); /* allow to finish interface down */
+#ifdef WIFI_DRIVER_MODULE_PATH
+ if (rmmod(DRIVER_MODULE_NAME) == 0) {
+ int count = 20; /* wait at most 10 seconds for completion */
+ while (count-- > 0) {
+ if (!is_wifi_driver_loaded())
+ break;
+ usleep(500000);
+ }
+ usleep(500000); /* allow card removal */
+ if (count) {
+ return 0;
+ }
+ return -1;
+ } else
+ return -1;
+#else
+#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
+ if (is_wifi_driver_loaded()) {
+ if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0)
+ return -1;
+ }
+#endif
+ property_set(DRIVER_PROP_NAME, "unloaded");
+ return 0;
+#endif
+}
+
+int ensure_entropy_file_exists()
+{
+ int ret;
+ int destfd;
+
+ ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
+ if ((ret == 0) || (errno == EACCES)) {
+ if ((ret != 0) &&
+ (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
+ ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+ return -1;
+ }
+ return 0;
+ }
+ destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
+ if (destfd < 0) {
+ ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+ return -1;
+ }
+
+ if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
+ ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
+ close(destfd);
+ return -1;
+ }
+ close(destfd);
+
+ /* chmod is needed because open() didn't set permisions properly */
+ if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
+ ALOGE("Error changing permissions of %s to 0660: %s",
+ SUPP_ENTROPY_FILE, strerror(errno));
+ unlink(SUPP_ENTROPY_FILE);
+ return -1;
+ }
+
+ if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
+ ALOGE("Error changing group ownership of %s to %d: %s",
+ SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
+ unlink(SUPP_ENTROPY_FILE);
+ return -1;
+ }
+ return 0;
+}
+
+int ensure_config_file_exists(const char *config_file)
+{
+ char buf[2048];
+ int srcfd, destfd;
+ struct stat sb;
+ int nread;
+ int ret;
+
+ ret = access(config_file, R_OK|W_OK);
+ if ((ret == 0) || (errno == EACCES)) {
+ if ((ret != 0) &&
+ (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
+ ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
+ return -1;
+ }
+ return 0;
+ } else if (errno != ENOENT) {
+ ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
+ return -1;
+ }
+
+ srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
+ if (srcfd < 0) {
+ ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+ return -1;
+ }
+
+ destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
+ if (destfd < 0) {
+ close(srcfd);
+ ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
+ return -1;
+ }
+
+ while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
+ if (nread < 0) {
+ ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
+ close(srcfd);
+ close(destfd);
+ unlink(config_file);
+ return -1;
+ }
+ TEMP_FAILURE_RETRY(write(destfd, buf, nread));
+ }
+
+ close(destfd);
+ close(srcfd);
+
+ /* chmod is needed because open() didn't set permisions properly */
+ if (chmod(config_file, 0660) < 0) {
+ ALOGE("Error changing permissions of %s to 0660: %s",
+ config_file, strerror(errno));
+ unlink(config_file);
+ return -1;
+ }
+
+ if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
+ ALOGE("Error changing group ownership of %s to %d: %s",
+ config_file, AID_WIFI, strerror(errno));
+ unlink(config_file);
+ return -1;
+ }
+ return 0;
+}
+
+int wifi_start_supplicant(int p2p_supported)
+{
+ char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+ int count = 200; /* wait at most 20 seconds for completion */
+ const prop_info *pi;
+ unsigned serial = 0, i;
+
+ if (p2p_supported) {
+ strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
+ strcpy(supplicant_prop_name, P2P_PROP_NAME);
+
+ /* Ensure p2p config file is created */
+ if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
+ ALOGE("Failed to create a p2p config file");
+ return -1;
+ }
+
+ } else {
+ strcpy(supplicant_name, SUPPLICANT_NAME);
+ strcpy(supplicant_prop_name, SUPP_PROP_NAME);
+ }
+
+ /* Check whether already running */
+ if (property_get(supplicant_prop_name, supp_status, NULL)
+ && strcmp(supp_status, "running") == 0) {
+ return 0;
+ }
+
+ /* Before starting the daemon, make sure its config file exists */
+ if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
+ ALOGE("Wi-Fi will not be enabled");
+ return -1;
+ }
+
+ if (ensure_entropy_file_exists() < 0) {
+ ALOGE("Wi-Fi entropy file was not created");
+ }
+
+ /* Clear out any stale socket files that might be left over. */
+ wpa_ctrl_cleanup();
+
+ /* Reset sockets used for exiting from hung state */
+ exit_sockets[0] = exit_sockets[1] = -1;
+
+ /*
+ * Get a reference to the status property, so we can distinguish
+ * the case where it goes stopped => running => stopped (i.e.,
+ * it start up, but fails right away) from the case in which
+ * it starts in the stopped state and never manages to start
+ * running at all.
+ */
+ pi = __system_property_find(supplicant_prop_name);
+ if (pi != NULL) {
+ serial = __system_property_serial(pi);
+ }
+ property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
+
+ property_set("ctl.start", supplicant_name);
+ sched_yield();
+
+ while (count-- > 0) {
+ if (pi == NULL) {
+ pi = __system_property_find(supplicant_prop_name);
+ }
+ if (pi != NULL) {
+ /*
+ * property serial updated means that init process is scheduled
+ * after we sched_yield, further property status checking is based on this */
+ if (__system_property_serial(pi) != serial) {
+ __system_property_read(pi, NULL, supp_status);
+ if (strcmp(supp_status, "running") == 0) {
+ return 0;
+ } else if (strcmp(supp_status, "stopped") == 0) {
+ return -1;
+ }
+ }
+ }
+ usleep(100000);
+ }
+ return -1;
+}
+
+int wifi_stop_supplicant(int p2p_supported)
+{
+ char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+ int count = 50; /* wait at most 5 seconds for completion */
+
+ if (p2p_supported) {
+ strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
+ strcpy(supplicant_prop_name, P2P_PROP_NAME);
+ } else {
+ strcpy(supplicant_name, SUPPLICANT_NAME);
+ strcpy(supplicant_prop_name, SUPP_PROP_NAME);
+ }
+
+ /* Check whether supplicant already stopped */
+ if (property_get(supplicant_prop_name, supp_status, NULL)
+ && strcmp(supp_status, "stopped") == 0) {
+ return 0;
+ }
+
+ property_set("ctl.stop", supplicant_name);
+ sched_yield();
+
+ while (count-- > 0) {
+ if (property_get(supplicant_prop_name, supp_status, NULL)) {
+ if (strcmp(supp_status, "stopped") == 0)
+ return 0;
+ }
+ usleep(100000);
+ }
+ ALOGE("Failed to stop supplicant");
+ return -1;
+}
+
+int wifi_connect_on_socket_path(const char *path)
+{
+ char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+
+ /* Make sure supplicant is running */
+ if (!property_get(supplicant_prop_name, supp_status, NULL)
+ || strcmp(supp_status, "running") != 0) {
+ ALOGE("Supplicant not running, cannot connect");
+ return -1;
+ }
+
+ 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 = wpa_ctrl_open(path);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ return -1;
+ }
+ 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) == -1) {
+ wpa_ctrl_close(monitor_conn);
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = monitor_conn = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Establishes the control and monitor socket connections on the interface */
+int wifi_connect_to_supplicant()
+{
+ static char path[PATH_MAX];
+
+ if (access(IFACE_DIR, F_OK) == 0) {
+ snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
+ } else {
+ snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
+ }
+ return wifi_connect_on_socket_path(path);
+}
+
+int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
+{
+ int ret;
+ if (ctrl_conn == NULL) {
+ ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
+ return -1;
+ }
+ 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[0], "T", 1));
+ return -2;
+ } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
+ return -1;
+ }
+ if (strncmp(cmd, "PING", 4) == 0) {
+ reply[*reply_len] = '\0';
+ }
+ return 0;
+}
+
+int wifi_supplicant_connection_active()
+{
+ char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
+
+ if (property_get(supplicant_prop_name, supp_status, NULL)) {
+ if (strcmp(supp_status, "stopped") == 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int wifi_ctrl_recv(char *reply, size_t *reply_len)
+{
+ int res;
+ 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[1];
+ rfds[1].events |= POLLIN;
+ do {
+ res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
+ if (res < 0) {
+ ALOGE("Error poll = %d", res);
+ return res;
+ } else if (res == 0) {
+ /* timed out, check if supplicant is active
+ * or not ..
+ */
+ res = wifi_supplicant_connection_active();
+ if (res < 0)
+ return -2;
+ }
+ } while (res == 0);
+
+ if (rfds[0].revents & POLLIN) {
+ 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(char *buf, size_t buflen)
+{
+ size_t nread = buflen - 1;
+ int result;
+ char *match, *match2;
+
+ if (monitor_conn == NULL) {
+ return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
+ primary_iface, WPA_EVENT_TERMINATING);
+ }
+
+ result = wifi_ctrl_recv(buf, &nread);
+
+ /* Terminate reception on exit socket */
+ if (result == -2) {
+ return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
+ primary_iface, WPA_EVENT_TERMINATING);
+ }
+
+ if (result < 0) {
+ ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
+ return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
+ primary_iface, WPA_EVENT_TERMINATING);
+ }
+ 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");
+ return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
+ primary_iface, WPA_EVENT_TERMINATING);
+ }
+ /*
+ * 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 (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);
+ 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(char *buf, size_t buflen)
+{
+ return wifi_wait_on_socket(buf, buflen);
+}
+
+void wifi_close_sockets()
+{
+ if (ctrl_conn != NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (monitor_conn != NULL) {
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+
+ if (exit_sockets[0] >= 0) {
+ close(exit_sockets[0]);
+ exit_sockets[0] = -1;
+ }
+
+ if (exit_sockets[1] >= 0) {
+ close(exit_sockets[1]);
+ exit_sockets[1] = -1;
+ }
+}
+
+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 */
+
+ wifi_close_sockets();
+
+ while (count-- > 0) {
+ if (property_get(supplicant_prop_name, supp_status, NULL)) {
+ if (strcmp(supp_status, "stopped") == 0)
+ return;
+ }
+ usleep(100000);
+ }
+}
+
+int wifi_command(const char *command, char *reply, size_t *reply_len)
+{
+ return wifi_send_command(command, reply, reply_len);
+}
+
+const char *wifi_get_fw_path(int fw_type)
+{
+ switch (fw_type) {
+ case WIFI_GET_FW_PATH_STA:
+ return WIFI_DRIVER_FW_PATH_STA;
+ case WIFI_GET_FW_PATH_AP:
+ return WIFI_DRIVER_FW_PATH_AP;
+ case WIFI_GET_FW_PATH_P2P:
+ return WIFI_DRIVER_FW_PATH_P2P;
+ }
+ return NULL;
+}
+
+int wifi_change_fw_path(const char *fwpath)
+{
+ int len;
+ int fd;
+ int ret = 0;
+
+ if (!fwpath)
+ return ret;
+ fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
+ if (fd < 0) {
+ ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
+ return -1;
+ }
+ len = strlen(fwpath) + 1;
+ if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
+ ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
+ ret = -1;
+ }
+ close(fd);
+ return ret;
+}