aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org>2011-07-05 23:04:16 +0000
committerBernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org>2011-07-05 23:04:16 +0000
commite29b1bc59560d5b1150111d30e49919b6d6f889d (patch)
tree395ba93a905845ea3bc16b7b00752c7e4ff87314
downloadimx53-e29b1bc59560d5b1150111d30e49919b6d6f889d.tar.gz
Initial configs, based on the pandaboard ones
-rw-r--r--AndroidBoard.mk36
-rw-r--r--AndroidProducts.mk2
-rw-r--r--BoardConfig.mk33
-rw-r--r--Logitech_Logitech_USB_Keyboard.kcm64
-rw-r--r--Logitech_Logitech_USB_Keyboard.kl90
-rw-r--r--MLObin0 -> 22072 bytes
-rw-r--r--README.txt11
-rw-r--r--device.mk16
-rw-r--r--gpio-keys.kcm64
-rw-r--r--gpio-keys.kl1
-rw-r--r--iMX53.mk7
-rw-r--r--init.omap4.rc9
-rw-r--r--initlogo.rlebin0 -> 27288 bytes
-rw-r--r--libaudio/Android.mk53
-rw-r--r--libaudio/AudioHardware.cpp2014
-rw-r--r--libaudio/AudioHardware.h348
-rw-r--r--libaudio/AudioPolicyManager.cpp74
-rw-r--r--libaudio/AudioPolicyManager.h47
-rw-r--r--libaudio/alsa_audio.h77
-rw-r--r--libaudio/alsa_mixer.c371
-rw-r--r--libaudio/alsa_pcm.c405
-rw-r--r--libaudio/amix.c78
-rw-r--r--libaudio/aplay.c140
-rw-r--r--libaudio/arec.c128
-rw-r--r--libaudio/asound.h814
-rw-r--r--libaudio/secril-client.h175
-rw-r--r--system.prop6
-rwxr-xr-xvendorsetup.sh1
-rw-r--r--vold.fstab15
29 files changed, 5079 insertions, 0 deletions
diff --git a/AndroidBoard.mk b/AndroidBoard.mk
new file mode 100644
index 0000000..4dfe386
--- /dev/null
+++ b/AndroidBoard.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH := $(call my-dir)
+
+file := $(TARGET_OUT_KEYLAYOUT)/gpio-keys.kl
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/gpio-keys.kl | $(ACP)
+ $(transform-prebuilt-to-target)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := gpio-keys.kcm
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_KEY_CHAR_MAP)
+
+file := $(TARGET_OUT_KEYLAYOUT)/Logitech_Logitech_USB_Keyboard.kl
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/Logitech_Logitech_USB_Keyboard.kl | $(ACP)
+ $(transform-prebuilt-to-target)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := Logitech_Logitech_USB_Keyboard.kcm
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_KEY_CHAR_MAP)
+
+file := $(TARGET_ROOT_OUT)/init.rc
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/../common/init.rc | $(ACP)
+ $(transform-prebuilt-to-target)
+
+file := $(TARGET_ROOT_OUT)/init.omap4.rc
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/init.omap4.rc | $(ACP)
+ $(transform-prebuilt-to-target)
+
+file := $(TARGET_ROOT_OUT)/initlogo.rle
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/initlogo.rle | $(ACP)
+ $(transform-prebuilt-to-target)
diff --git a/AndroidProducts.mk b/AndroidProducts.mk
new file mode 100644
index 0000000..613c007
--- /dev/null
+++ b/AndroidProducts.mk
@@ -0,0 +1,2 @@
+PRODUCT_MAKEFILES := \
+ $(LOCAL_DIR)/iMX53.mk
diff --git a/BoardConfig.mk b/BoardConfig.mk
new file mode 100644
index 0000000..4c646e8
--- /dev/null
+++ b/BoardConfig.mk
@@ -0,0 +1,33 @@
+# config.mk
+#
+# Product-specific compile-time definitions.
+#
+
+TARGET_BOARD_PLATFORM := omap4
+TARGET_NO_BOOTLOADER := true # Uses u-boot instead
+TARGET_NO_KERNEL := false
+KERNEL_CONFIG := android_omap4_defconfig
+TARGET_USE_UBOOT := true
+UBOOT_CONFIG := omap4_panda_config
+TARGET_USE_XLOADER := true
+XLOADER_BINARY := device/linaro/iMX53/MLO
+TARGET_NO_RECOVERY := true
+TARGET_NO_RADIOIMAGE := true
+TARGET_PROVIDES_INIT_RC := true
+BOARD_USES_GENERIC_AUDIO := false
+USE_CAMERA_STUB := true
+
+BOARD_HAVE_BLUETOOTH := false
+BOARD_HAVE_BLUETOOTH_BCM := false
+
+TARGET_CPU_ABI := armeabi-v7a
+TARGET_CPU_ABI2 := armeabi
+
+# Enable NEON feature
+TARGET_ARCH_VARIANT := armv7-a-neon
+ARCH_ARM_HAVE_TLS_REGISTER := true
+
+EXTRA_PACKAGE_MANAGEMENT := false
+
+TARGET_USERIMAGES_USE_EXT4 := true
+TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
diff --git a/Logitech_Logitech_USB_Keyboard.kcm b/Logitech_Logitech_USB_Keyboard.kcm
new file mode 100644
index 0000000..8056364
--- /dev/null
+++ b/Logitech_Logitech_USB_Keyboard.kcm
@@ -0,0 +1,64 @@
+[type=QWERTY]
+
+# keycode display number base caps fn caps_fn
+
+A 'A' '2' 'a' 'A' '#' 0x00
+B 'B' '2' 'b' 'B' '<' 0x00
+C 'C' '2' 'c' 'C' '9' 0x00E7
+D 'D' '3' 'd' 'D' '5' 0x00
+E 'E' '3' 'e' 'E' '2' 0x0301
+F 'F' '3' 'f' 'F' '6' 0x00A5
+G 'G' '4' 'g' 'G' '-' '_'
+H 'H' '4' 'h' 'H' '[' '{'
+I 'I' '4' 'i' 'I' '$' 0x0302
+J 'J' '5' 'j' 'J' ']' '}'
+K 'K' '5' 'k' 'K' '"' '~'
+L 'L' '5' 'l' 'L' ''' '`'
+M 'M' '6' 'm' 'M' '!' 0x00
+N 'N' '6' 'n' 'N' '>' 0x0303
+O 'O' '6' 'o' 'O' '(' 0x00
+P 'P' '7' 'p' 'P' ')' 0x00
+Q 'Q' '7' 'q' 'Q' '*' 0x0300
+R 'R' '7' 'r' 'R' '3' 0x20AC
+S 'S' '7' 's' 'S' '4' 0x00DF
+T 'T' '8' 't' 'T' '+' 0x00A3
+U 'U' '8' 'u' 'U' '&' 0x0308
+V 'V' '8' 'v' 'V' '=' '^'
+W 'W' '9' 'w' 'W' '1' 0x00
+X 'X' '9' 'x' 'X' '8' 0xEF00
+Y 'Y' '9' 'y' 'Y' '%' 0x00A1
+Z 'Z' '9' 'z' 'Z' '7' 0x00
+
+# on pc keyboards
+COMMA ',' ',' ',' ';' ';' '|'
+PERIOD '.' '.' '.' ':' ':' 0x2026
+AT '@' '0' '@' '0' '0' 0x2022
+SLASH '/' '/' '/' '?' '?' '\'
+
+SPACE 0x20 0x20 0x20 0x20 0xEF01 0xEF01
+ENTER 0xa 0xa 0xa 0xa 0xa 0xa
+
+TAB 0x9 0x9 0x9 0x9 0x9 0x9
+0 '0' '0' '0' ')' ')' ')'
+1 '1' '1' '1' '!' '!' '!'
+2 '2' '2' '2' '@' '@' '@'
+3 '3' '3' '3' '#' '#' '#'
+4 '4' '4' '4' '$' '$' '$'
+5 '5' '5' '5' '%' '%' '%'
+6 '6' '6' '6' '^' '^' '^'
+7 '7' '7' '7' '&' '&' '&'
+8 '8' '8' '8' '*' '*' '*'
+9 '9' '9' '9' '(' '(' '('
+
+GRAVE '`' '`' '`' '~' '`' '~'
+MINUS '-' '-' '-' '_' '-' '_'
+EQUALS '=' '=' '=' '+' '=' '+'
+LEFT_BRACKET '[' '[' '[' '{' '[' '{'
+RIGHT_BRACKET ']' ']' ']' '}' ']' '}'
+BACKSLASH '\' '\' '\' '|' '\' '|'
+SEMICOLON ';' ';' ';' ':' ';' ':'
+APOSTROPHE ''' ''' ''' '"' ''' '"'
+STAR '*' '*' '*' '*' '*' '*'
+POUND '#' '#' '#' '#' '#' '#'
+PLUS '+' '+' '+' '+' '+' '+'
+
diff --git a/Logitech_Logitech_USB_Keyboard.kl b/Logitech_Logitech_USB_Keyboard.kl
new file mode 100644
index 0000000..fef2d92
--- /dev/null
+++ b/Logitech_Logitech_USB_Keyboard.kl
@@ -0,0 +1,90 @@
+key 399 GRAVE
+key 2 1
+key 3 2
+key 4 3
+key 5 4
+key 6 5
+key 7 6
+key 8 7
+key 9 8
+key 10 9
+key 11 0
+key 158 BACK WAKE_DROPPED
+key 230 SOFT_RIGHT WAKE
+key 60 SOFT_RIGHT WAKE
+key 107 ENDCALL WAKE_DROPPED
+key 62 ENDCALL WAKE_DROPPED
+key 229 MENU WAKE_DROPPED
+key 139 MENU WAKE_DROPPED
+key 59 MENU WAKE_DROPPED
+key 88 MENU WAKE_DROPPED
+key 127 SEARCH WAKE_DROPPED
+key 217 SEARCH WAKE_DROPPED
+key 228 POUND
+key 227 STAR
+key 231 CALL WAKE_DROPPED
+key 61 CALL WAKE_DROPPED
+key 232 DPAD_CENTER WAKE_DROPPED
+key 108 DPAD_DOWN WAKE_DROPPED
+key 103 DPAD_UP WAKE_DROPPED
+key 102 HOME WAKE
+key 105 DPAD_LEFT WAKE_DROPPED
+key 106 DPAD_RIGHT WAKE_DROPPED
+key 115 VOLUME_UP
+key 114 VOLUME_DOWN
+key 116 POWER WAKE
+key 212 CAMERA
+
+key 16 Q
+key 17 W
+key 18 E
+key 19 R
+key 20 T
+key 21 Y
+key 22 U
+key 23 I
+key 24 O
+key 25 P
+key 26 LEFT_BRACKET
+key 27 RIGHT_BRACKET
+key 43 BACKSLASH
+
+key 30 A
+key 31 S
+key 32 D
+key 33 F
+key 34 G
+key 35 H
+key 36 J
+key 37 K
+key 38 L
+key 39 SEMICOLON
+key 40 APOSTROPHE
+key 14 DEL
+
+key 44 Z
+key 45 X
+key 46 C
+key 47 V
+key 48 B
+key 49 N
+key 50 M
+key 51 COMMA
+key 52 PERIOD
+key 53 SLASH
+key 28 ENTER
+
+key 56 ALT_LEFT
+key 100 ALT_RIGHT
+key 42 SHIFT_LEFT
+key 54 SHIFT_RIGHT
+key 15 TAB
+key 57 SPACE
+key 150 EXPLORER
+key 155 ENVELOPE
+
+key 12 MINUS
+key 13 EQUALS
+key 215 AT
+
+
diff --git a/MLO b/MLO
new file mode 100644
index 0000000..f8b99fc
--- /dev/null
+++ b/MLO
Binary files differ
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..0fd2438
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,11 @@
+Summary: Linaro Evaluation Build for Android
+
+Author: Linaro Limited
+
+Description:
+ In order to ensure that Software Components developed and improved work
+ well and really matter in a production like environment, Linaro Platform
+ Releases introduced a concept called "Evaluation Builds".
+
+ Evaluation Builds are images that can be installed on high volume member
+ boards supported by Linaro Platform and Landing Teams.
diff --git a/device.mk b/device.mk
new file mode 100644
index 0000000..9382c34
--- /dev/null
+++ b/device.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2011 Linaro Limited
+#
+# 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.
+
+PRODUCT_COPY_FILES := \
+ device/linaro/iMX53/vold.fstab:system/etc/vold.fstab
diff --git a/gpio-keys.kcm b/gpio-keys.kcm
new file mode 100644
index 0000000..8056364
--- /dev/null
+++ b/gpio-keys.kcm
@@ -0,0 +1,64 @@
+[type=QWERTY]
+
+# keycode display number base caps fn caps_fn
+
+A 'A' '2' 'a' 'A' '#' 0x00
+B 'B' '2' 'b' 'B' '<' 0x00
+C 'C' '2' 'c' 'C' '9' 0x00E7
+D 'D' '3' 'd' 'D' '5' 0x00
+E 'E' '3' 'e' 'E' '2' 0x0301
+F 'F' '3' 'f' 'F' '6' 0x00A5
+G 'G' '4' 'g' 'G' '-' '_'
+H 'H' '4' 'h' 'H' '[' '{'
+I 'I' '4' 'i' 'I' '$' 0x0302
+J 'J' '5' 'j' 'J' ']' '}'
+K 'K' '5' 'k' 'K' '"' '~'
+L 'L' '5' 'l' 'L' ''' '`'
+M 'M' '6' 'm' 'M' '!' 0x00
+N 'N' '6' 'n' 'N' '>' 0x0303
+O 'O' '6' 'o' 'O' '(' 0x00
+P 'P' '7' 'p' 'P' ')' 0x00
+Q 'Q' '7' 'q' 'Q' '*' 0x0300
+R 'R' '7' 'r' 'R' '3' 0x20AC
+S 'S' '7' 's' 'S' '4' 0x00DF
+T 'T' '8' 't' 'T' '+' 0x00A3
+U 'U' '8' 'u' 'U' '&' 0x0308
+V 'V' '8' 'v' 'V' '=' '^'
+W 'W' '9' 'w' 'W' '1' 0x00
+X 'X' '9' 'x' 'X' '8' 0xEF00
+Y 'Y' '9' 'y' 'Y' '%' 0x00A1
+Z 'Z' '9' 'z' 'Z' '7' 0x00
+
+# on pc keyboards
+COMMA ',' ',' ',' ';' ';' '|'
+PERIOD '.' '.' '.' ':' ':' 0x2026
+AT '@' '0' '@' '0' '0' 0x2022
+SLASH '/' '/' '/' '?' '?' '\'
+
+SPACE 0x20 0x20 0x20 0x20 0xEF01 0xEF01
+ENTER 0xa 0xa 0xa 0xa 0xa 0xa
+
+TAB 0x9 0x9 0x9 0x9 0x9 0x9
+0 '0' '0' '0' ')' ')' ')'
+1 '1' '1' '1' '!' '!' '!'
+2 '2' '2' '2' '@' '@' '@'
+3 '3' '3' '3' '#' '#' '#'
+4 '4' '4' '4' '$' '$' '$'
+5 '5' '5' '5' '%' '%' '%'
+6 '6' '6' '6' '^' '^' '^'
+7 '7' '7' '7' '&' '&' '&'
+8 '8' '8' '8' '*' '*' '*'
+9 '9' '9' '9' '(' '(' '('
+
+GRAVE '`' '`' '`' '~' '`' '~'
+MINUS '-' '-' '-' '_' '-' '_'
+EQUALS '=' '=' '=' '+' '=' '+'
+LEFT_BRACKET '[' '[' '[' '{' '[' '{'
+RIGHT_BRACKET ']' ']' ']' '}' ']' '}'
+BACKSLASH '\' '\' '\' '|' '\' '|'
+SEMICOLON ';' ';' ';' ':' ';' ':'
+APOSTROPHE ''' ''' ''' '"' ''' '"'
+STAR '*' '*' '*' '*' '*' '*'
+POUND '#' '#' '#' '#' '#' '#'
+PLUS '+' '+' '+' '+' '+' '+'
+
diff --git a/gpio-keys.kl b/gpio-keys.kl
new file mode 100644
index 0000000..d19ab04
--- /dev/null
+++ b/gpio-keys.kl
@@ -0,0 +1 @@
+key 276 MENU WAKE
diff --git a/iMX53.mk b/iMX53.mk
new file mode 100644
index 0000000..045eb2a
--- /dev/null
+++ b/iMX53.mk
@@ -0,0 +1,7 @@
+# The iMX53 product that is specialized for i.MX53.
+$(call inherit-product, device/linaro/common/common.mk)
+$(call inherit-product, device/linaro/iMX53/device.mk)
+
+PRODUCT_BRAND := iMX53
+PRODUCT_DEVICE := iMX53
+PRODUCT_NAME := iMX53
diff --git a/init.omap4.rc b/init.omap4.rc
new file mode 100644
index 0000000..c867e9e
--- /dev/null
+++ b/init.omap4.rc
@@ -0,0 +1,9 @@
+on boot
+ # create dhcpcd dir
+ mkdir /data/misc/dhcp 0770 dhcp dhcp
+ chmod 0770 /data/misc/dhcp
+
+service faketsd /system/bin/faketsd
+ user bluetooth
+ group bluetooth
+ oneshot
diff --git a/initlogo.rle b/initlogo.rle
new file mode 100644
index 0000000..9bf8bef
--- /dev/null
+++ b/initlogo.rle
Binary files differ
diff --git a/libaudio/Android.mk b/libaudio/Android.mk
new file mode 100644
index 0000000..e14d7d6
--- /dev/null
+++ b/libaudio/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+ifeq ($(TARGET_DEVICE),pandaboard)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c
+LOCAL_MODULE:= aplay
+LOCAL_SHARED_LIBRARIES:= libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= arec.c alsa_pcm.c
+LOCAL_MODULE:= arec
+LOCAL_SHARED_LIBRARIES:= libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= amix.c alsa_mixer.c
+LOCAL_MODULE:= amix
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_MODULE_TAGS:= debug
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= AudioHardware.cpp alsa_mixer.c alsa_pcm.c
+LOCAL_MODULE:= libaudio
+LOCAL_STATIC_LIBRARIES:= libaudiointerface
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia libhardware_legacy
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_SHARED_LIBRARIES += liba2dp
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= AudioPolicyManager.cpp
+LOCAL_MODULE:= libaudiopolicy
+LOCAL_STATIC_LIBRARIES:= libaudiopolicybase
+LOCAL_SHARED_LIBRARIES:= libc libcutils libutils libmedia
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/libaudio/AudioHardware.cpp b/libaudio/AudioHardware.cpp
new file mode 100644
index 0000000..2ade94b
--- /dev/null
+++ b/libaudio/AudioHardware.cpp
@@ -0,0 +1,2014 @@
+/*
+** Copyright 2010, 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 "AudioHardware"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#include "AudioHardware.h"
+#include <media/AudioRecord.h>
+#include <hardware_legacy/power.h>
+
+extern "C" {
+#include "alsa_audio.h"
+}
+
+
+namespace android {
+
+const uint32_t AudioHardware::inputSamplingRates[] = {
+ 8000, 11025, 16000, 22050, 44100
+};
+
+// trace driver operations for dump
+//
+#define DRIVER_TRACE
+
+enum {
+ DRV_NONE,
+ DRV_PCM_OPEN,
+ DRV_PCM_CLOSE,
+ DRV_PCM_WRITE,
+ DRV_PCM_READ,
+ DRV_MIXER_OPEN,
+ DRV_MIXER_CLOSE,
+ DRV_MIXER_GET,
+ DRV_MIXER_SEL
+};
+
+#ifdef DRIVER_TRACE
+#define TRACE_DRIVER_IN(op) mDriverOp = op;
+#define TRACE_DRIVER_OUT mDriverOp = DRV_NONE;
+#else
+#define TRACE_DRIVER_IN(op)
+#define TRACE_DRIVER_OUT
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardware::AudioHardware() :
+ mInit(false),
+ mMicMute(false),
+ mPcm(NULL),
+ mMixer(NULL),
+ mPcmOpenCnt(0),
+ mMixerOpenCnt(0),
+ mInCallAudioMode(false),
+ mInputSource("Default"),
+ mBluetoothNrec(true),
+ mSecRilLibHandle(NULL),
+ mRilClient(0),
+ mActivatedCP(false),
+ mDriverOp(DRV_NONE)
+{
+ //loadRILD();
+ mInit = true;
+}
+
+AudioHardware::~AudioHardware()
+{
+ for (size_t index = 0; index < mInputs.size(); index++) {
+ closeInputStream(mInputs[index].get());
+ }
+ mInputs.clear();
+ closeOutputStream((AudioStreamOut*)mOutput.get());
+
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
+ mixer_close(mMixer);
+ TRACE_DRIVER_OUT
+ }
+ if (mPcm) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ }
+
+ if (mSecRilLibHandle) {
+ if (disconnectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
+ LOGE("Disconnect_RILD() error");
+
+ if (closeClientRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS)
+ LOGE("CloseClient_RILD() error");
+
+ mRilClient = 0;
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ }
+
+ mInit = false;
+}
+
+status_t AudioHardware::initCheck()
+{
+ return mInit ? NO_ERROR : NO_INIT;
+}
+
+void AudioHardware::loadRILD(void)
+{
+ mSecRilLibHandle = dlopen("libsecril-client.so", RTLD_NOW);
+
+ if (mSecRilLibHandle) {
+ LOGV("libsecril-client.so is loaded");
+
+ openClientRILD = (HRilClient (*)(void))
+ dlsym(mSecRilLibHandle, "OpenClient_RILD");
+ disconnectRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "Disconnect_RILD");
+ closeClientRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "CloseClient_RILD");
+ isConnectedRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "isConnected_RILD");
+ connectRILD = (int (*)(HRilClient))
+ dlsym(mSecRilLibHandle, "Connect_RILD");
+ setCallVolume = (int (*)(HRilClient, SoundType, int))
+ dlsym(mSecRilLibHandle, "SetCallVolume");
+ setCallAudioPath = (int (*)(HRilClient, AudioPath))
+ dlsym(mSecRilLibHandle, "SetCallAudioPath");
+ setCallClockSync = (int (*)(HRilClient, SoundClockCondition))
+ dlsym(mSecRilLibHandle, "SetCallClockSync");
+
+ if (!openClientRILD || !disconnectRILD || !closeClientRILD ||
+ !isConnectedRILD || !connectRILD ||
+ !setCallVolume || !setCallAudioPath || !setCallClockSync) {
+ LOGE("Can't load all functions from libsecril-client.so");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ } else {
+ mRilClient = openClientRILD();
+ if (!mRilClient) {
+ LOGE("OpenClient_RILD() error");
+
+ dlclose(mSecRilLibHandle);
+ mSecRilLibHandle = NULL;
+ }
+ }
+ } else {
+ LOGE("Can't load libsecril-client.so");
+ }
+}
+
+status_t AudioHardware::connectRILDIfRequired(void)
+{
+ if (!mSecRilLibHandle) {
+ LOGE("connectIfRequired() lib is not loaded");
+ return INVALID_OPERATION;
+ }
+
+ if (isConnectedRILD(mRilClient)) {
+ return OK;
+ }
+
+ if (connectRILD(mRilClient) != RIL_CLIENT_ERR_SUCCESS) {
+ LOGE("Connect_RILD() error");
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
+AudioStreamOut* AudioHardware::openOutputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status)
+{
+ sp <AudioStreamOutALSA> out;
+ status_t rc;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mLock);
+
+ // only one output stream allowed
+ if (mOutput != 0) {
+ if (status) {
+ *status = INVALID_OPERATION;
+ }
+ return NULL;
+ }
+
+ out = new AudioStreamOutALSA();
+
+ rc = out->set(this, devices, format, channels, sampleRate);
+ if (rc == NO_ERROR) {
+ mOutput = out;
+ }
+ }
+
+ if (rc != NO_ERROR) {
+ if (out != 0) {
+ out.clear();
+ }
+ }
+ if (status) {
+ *status = rc;
+ }
+
+ return out.get();
+}
+
+void AudioHardware::closeOutputStream(AudioStreamOut* out) {
+ sp <AudioStreamOutALSA> spOut;
+ {
+ Mutex::Autolock lock(mLock);
+ if (mOutput == 0 || mOutput.get() != out) {
+ LOGW("Attempt to close invalid output stream");
+ return;
+ }
+ spOut = mOutput;
+ mOutput.clear();
+ }
+ spOut.clear();
+}
+
+AudioStreamIn* AudioHardware::openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustic_flags)
+{
+ // check for valid input source
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
+ if (status) {
+ *status = BAD_VALUE;
+ }
+ return NULL;
+ }
+
+ status_t rc = NO_ERROR;
+ sp <AudioStreamInALSA> in;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mLock);
+
+ in = new AudioStreamInALSA();
+ rc = in->set(this, devices, format, channels, sampleRate, acoustic_flags);
+ if (rc == NO_ERROR) {
+ mInputs.add(in);
+ }
+ }
+
+ if (rc != NO_ERROR) {
+ if (in != 0) {
+ in.clear();
+ }
+ }
+ if (status) {
+ *status = rc;
+ }
+
+ LOGV("AudioHardware::openInputStream()%p", in.get());
+ return in.get();
+}
+
+void AudioHardware::closeInputStream(AudioStreamIn* in) {
+
+ sp<AudioStreamInALSA> spIn;
+ {
+ Mutex::Autolock lock(mLock);
+
+ ssize_t index = mInputs.indexOf((AudioStreamInALSA *)in);
+ if (index < 0) {
+ LOGW("Attempt to close invalid input stream");
+ return;
+ }
+ spIn = mInputs[index];
+ mInputs.removeAt(index);
+ }
+ LOGV("AudioHardware::closeInputStream()%p", in);
+ spIn.clear();
+}
+
+
+status_t AudioHardware::setMode(int mode)
+{
+ sp<AudioStreamOutALSA> spOut;
+ sp<AudioStreamInALSA> spIn;
+ status_t status;
+
+ // bump thread priority to speed up mutex acquisition
+ int priority = getpriority(PRIO_PROCESS, 0);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_URGENT_AUDIO);
+
+ // Mutex acquisition order is always out -> in -> hw
+ AutoMutex lock(mLock);
+
+ spOut = mOutput;
+ while (spOut != 0) {
+ if (!spOut->checkStandby()) {
+ int cnt = spOut->standbyCnt();
+ mLock.unlock();
+ spOut->lock();
+ mLock.lock();
+ // make sure that another thread did not change output state while the
+ // mutex is released
+ if ((spOut == mOutput) && (cnt == spOut->standbyCnt())) {
+ break;
+ }
+ spOut->unlock();
+ spOut = mOutput;
+ } else {
+ spOut.clear();
+ }
+ }
+ // spOut is not 0 here only if the output is active
+
+ spIn = getActiveInput_l();
+ while (spIn != 0) {
+ int cnt = spIn->standbyCnt();
+ mLock.unlock();
+ spIn->lock();
+ mLock.lock();
+ // make sure that another thread did not change input state while the
+ // mutex is released
+ if ((spIn == getActiveInput_l()) && (cnt == spIn->standbyCnt())) {
+ break;
+ }
+ spIn->unlock();
+ spIn = getActiveInput_l();
+ }
+ // spIn is not 0 here only if the input is active
+
+ setpriority(PRIO_PROCESS, 0, priority);
+
+ int prevMode = mMode;
+ status = AudioHardwareBase::setMode(mode);
+ LOGV("setMode() : new %d, old %d", mMode, prevMode);
+ if (status == NO_ERROR) {
+ // activate call clock in radio when entering in call or ringtone mode
+ if (prevMode == AudioSystem::MODE_NORMAL)
+ {
+ if ((!mActivatedCP) && (mSecRilLibHandle) && (connectRILDIfRequired() == OK)) {
+ setCallClockSync(mRilClient, SOUND_CLOCK_START);
+ mActivatedCP = true;
+ }
+ }
+
+ if (mMode == AudioSystem::MODE_IN_CALL && !mInCallAudioMode) {
+ if (spOut != 0) {
+ LOGV("setMode() in call force output standby");
+ spOut->doStandby_l();
+ }
+ if (spIn != 0) {
+ LOGV("setMode() in call force input standby");
+ spIn->doStandby_l();
+ }
+
+ LOGV("setMode() openPcmOut_l()");
+ openPcmOut_l();
+ openMixer_l();
+ setInputSource_l(String8("Default"));
+ mInCallAudioMode = true;
+ }
+ if (mMode == AudioSystem::MODE_NORMAL && mInCallAudioMode) {
+ setInputSource_l(mInputSource);
+ if (mMixer != NULL) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Playback Path", 0);
+ TRACE_DRIVER_OUT
+ if (ctl != NULL) {
+ LOGV("setMode() reset Playback Path to RCV");
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, "RCV");
+ TRACE_DRIVER_OUT
+ }
+ }
+ LOGV("setMode() closePcmOut_l()");
+ closeMixer_l();
+ closePcmOut_l();
+
+ if (spOut != 0) {
+ LOGV("setMode() off call force output standby");
+ spOut->doStandby_l();
+ }
+ if (spIn != 0) {
+ LOGV("setMode() off call force input standby");
+ spIn->doStandby_l();
+ }
+
+ mInCallAudioMode = false;
+ }
+
+ if (mMode == AudioSystem::MODE_NORMAL) {
+ if(mActivatedCP)
+ mActivatedCP = false;
+ }
+ }
+
+ if (spIn != 0) {
+ spIn->unlock();
+ }
+ if (spOut != 0) {
+ spOut->unlock();
+ }
+
+ return status;
+}
+
+status_t AudioHardware::setMicMute(bool state)
+{
+ LOGV("setMicMute(%d) mMicMute %d", state, mMicMute);
+ sp<AudioStreamInALSA> spIn;
+ {
+ AutoMutex lock(mLock);
+ if (mMicMute != state) {
+ mMicMute = state;
+ // in call mute is handled by RIL
+ if (mMode != AudioSystem::MODE_IN_CALL) {
+ spIn = getActiveInput_l();
+ }
+ }
+ }
+
+ if (spIn != 0) {
+ spIn->standby();
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::getMicMute(bool* state)
+{
+ *state = mMicMute;
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ const char BT_NREC_KEY[] = "bt_headset_nrec";
+ const char BT_NREC_VALUE_ON[] = "on";
+
+ key = String8(BT_NREC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == BT_NREC_VALUE_ON) {
+ mBluetoothNrec = true;
+ } else {
+ mBluetoothNrec = false;
+ LOGD("Turning noise reduction and echo cancellation off for BT "
+ "headset");
+ }
+ }
+
+ return NO_ERROR;
+}
+
+String8 AudioHardware::getParameters(const String8& keys)
+{
+ AudioParameter request = AudioParameter(keys);
+ AudioParameter reply = AudioParameter();
+
+ LOGV("getParameters() %s", keys.string());
+
+ return reply.toString();
+}
+
+size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ if (format != AudioSystem::PCM_16_BIT) {
+ LOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if (channelCount < 1 || channelCount > 2) {
+ LOGW("getInputBufferSize bad channel count: %d", channelCount);
+ return 0;
+ }
+ if (sampleRate != 8000 && sampleRate != 11025 && sampleRate != 16000 &&
+ sampleRate != 22050 && sampleRate != 44100) {
+ LOGW("getInputBufferSize bad sample rate: %d", sampleRate);
+ return 0;
+ }
+
+ return AudioStreamInALSA::getBufferSize(sampleRate, channelCount);
+}
+
+
+status_t AudioHardware::setVoiceVolume(float volume)
+{
+ LOGD("### setVoiceVolume");
+
+ AutoMutex lock(mLock);
+ if ( (AudioSystem::MODE_IN_CALL == mMode) && (mSecRilLibHandle) &&
+ (connectRILDIfRequired() == OK) ) {
+
+ uint32_t device = AudioSystem::DEVICE_OUT_EARPIECE;
+ if (mOutput != 0) {
+ device = mOutput->device();
+ }
+ int int_volume = (int)(volume * 5);
+ SoundType type;
+
+ LOGD("### route(%d) call volume(%f)", device, volume);
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ LOGD("### earpiece call volume");
+ type = SOUND_TYPE_VOICE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ LOGD("### speaker call volume");
+ type = SOUND_TYPE_SPEAKER;
+ break;
+
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ LOGD("### bluetooth call volume");
+ type = SOUND_TYPE_BTVOICE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: // Use receive path with 3 pole headset.
+ LOGD("### headset call volume");
+ type = SOUND_TYPE_HEADSET;
+ break;
+
+ default:
+ LOGW("### Call volume setting error!!!0x%08x \n", device);
+ type = SOUND_TYPE_VOICE;
+ break;
+ }
+ setCallVolume(mRilClient, type, int_volume);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setMasterVolume(float volume)
+{
+ LOGV("Set master volume to %f.\n", volume);
+ // We return an error code here to let the audioflinger do in-software
+ // volume on top of the maximum volume that we set through the SND API.
+ // return error - software mixer will handle it
+ return -1;
+}
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+static bool tryLock(Mutex& mutex)
+{
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mutex.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleep);
+ }
+ return locked;
+}
+
+status_t AudioHardware::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ snprintf(buffer, SIZE, "\n\tAudioHardware maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\tInit %s\n", (mInit) ? "OK" : "Failed");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tMic Mute %s\n", (mMicMute) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmPcmOpenCnt: %d\n", mPcmOpenCnt);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMixer: %p\n", mMixer);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmMixerOpenCnt: %d\n", mMixerOpenCnt);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tIn Call Audio Mode %s\n",
+ (mInCallAudioMode) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tInput source %s\n", mInputSource.string());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmSecRilLibHandle: %p\n", mSecRilLibHandle);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmRilClient: %p\n", mRilClient);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tCP %s\n",
+ (mActivatedCP) ? "Activated" : "Deactivated");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "\n\tmOutput %p dump:\n", mOutput.get());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ if (mOutput != 0) {
+ mOutput->dump(fd, args);
+ }
+
+ snprintf(buffer, SIZE, "\n\t%d inputs opened:\n", mInputs.size());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ snprintf(buffer, SIZE, "\t- input %d dump:\n", i);
+ write(fd, buffer, strlen(buffer));
+ mInputs[i]->dump(fd, args);
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::setIncallPath_l(uint32_t device)
+{
+ LOGV("setIncallPath_l: device %x", device);
+
+ // Setup sound path for CP clocking
+ if ((mSecRilLibHandle) &&
+ (connectRILDIfRequired() == OK)) {
+
+ if (mMode == AudioSystem::MODE_IN_CALL) {
+ LOGD("### incall mode route (%d)", device);
+ AudioPath path;
+ switch(device){
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ LOGD("### incall mode earpiece route");
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ LOGD("### incall mode speaker route");
+ path = SOUND_AUDIO_PATH_SPEAKER;
+ break;
+
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ LOGD("### incall mode bluetooth route %s NR", mBluetoothNrec ? "" : "NO");
+ if (mBluetoothNrec) {
+ path = SOUND_AUDIO_PATH_BLUETOOTH;
+ } else {
+ path = SOUND_AUDIO_PATH_BLUETOOTH_NO_NR;
+ }
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE :
+ LOGD("### incall mode headphone route");
+ path = SOUND_AUDIO_PATH_HEADPHONE;
+ break;
+
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET :
+ LOGD("### incall mode headset route");
+ path = SOUND_AUDIO_PATH_HEADSET;
+ break;
+
+ default:
+ LOGW("### incall mode Error!! route = [%d]", device);
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+ }
+
+ setCallAudioPath(mRilClient, path);
+
+ if (mMixer != NULL) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Voice Call Path", 0);
+ TRACE_DRIVER_OUT
+ LOGE_IF(ctl == NULL, "setIncallPath_l() could not get mixer ctl");
+ if (ctl != NULL) {
+ LOGV("setIncallPath_l() Voice Call Path, (%x)", device);
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, getVoiceRouteFromDevice(device));
+ TRACE_DRIVER_OUT
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+struct pcm *AudioHardware::openPcmOut_l()
+{
+ LOGD("openPcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt++ == 0) {
+ if (mPcm != NULL) {
+ LOGE("openPcmOut_l() mPcmOpenCnt == 0 and mPcm == %p\n", mPcm);
+ mPcmOpenCnt--;
+ return NULL;
+ }
+ unsigned flags = PCM_OUT;
+
+ flags |= (AUDIO_HW_OUT_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT;
+ flags |= (AUDIO_HW_OUT_PERIOD_CNT - PCM_PERIOD_CNT_MIN) << PCM_PERIOD_CNT_SHIFT;
+
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = pcm_open(flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ LOGE("openPcmOut_l() cannot open pcm_out driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcmOpenCnt--;
+ mPcm = NULL;
+ }
+ }
+ return mPcm;
+}
+
+void AudioHardware::closePcmOut_l()
+{
+ LOGD("closePcmOut_l() mPcmOpenCnt: %d", mPcmOpenCnt);
+ if (mPcmOpenCnt == 0) {
+ LOGE("closePcmOut_l() mPcmOpenCnt == 0");
+ return;
+ }
+
+ if (--mPcmOpenCnt == 0) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+struct mixer *AudioHardware::openMixer_l()
+{
+ LOGV("openMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt);
+ if (mMixerOpenCnt++ == 0) {
+ if (mMixer != NULL) {
+ LOGE("openMixer_l() mMixerOpenCnt == 0 and mMixer == %p\n", mMixer);
+ mMixerOpenCnt--;
+ return NULL;
+ }
+ TRACE_DRIVER_IN(DRV_MIXER_OPEN)
+ mMixer = mixer_open();
+ TRACE_DRIVER_OUT
+ if (mMixer == NULL) {
+ LOGE("openMixer_l() cannot open mixer");
+ mMixerOpenCnt--;
+ return NULL;
+ }
+ }
+ return mMixer;
+}
+
+void AudioHardware::closeMixer_l()
+{
+ LOGV("closeMixer_l() mMixerOpenCnt: %d", mMixerOpenCnt);
+ if (mMixerOpenCnt == 0) {
+ LOGE("closeMixer_l() mMixerOpenCnt == 0");
+ return;
+ }
+
+ if (--mMixerOpenCnt == 0) {
+ TRACE_DRIVER_IN(DRV_MIXER_CLOSE)
+ mixer_close(mMixer);
+ TRACE_DRIVER_OUT
+ mMixer = NULL;
+ }
+}
+
+const char *AudioHardware::getOutputRouteFromDevice(uint32_t device)
+{
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ return "RCV";
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_SPK";
+ else return "SPK";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_NO_MIC";
+ else return "HP_NO_MIC";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_HP";
+ else return "HP";
+ case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADPHONE):
+ case (AudioSystem::DEVICE_OUT_SPEAKER|AudioSystem::DEVICE_OUT_WIRED_HEADSET):
+ if (mMode == AudioSystem::MODE_RINGTONE) return "RING_SPK_HP";
+ else return "SPK_HP";
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ return "BT";
+ default:
+ return "OFF";
+ }
+}
+
+const char *AudioHardware::getVoiceRouteFromDevice(uint32_t device)
+{
+ switch (device) {
+ case AudioSystem::DEVICE_OUT_EARPIECE:
+ return "RCV";
+ case AudioSystem::DEVICE_OUT_SPEAKER:
+ return "SPK";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE:
+ return "HP_NO_MIC";
+ case AudioSystem::DEVICE_OUT_WIRED_HEADSET:
+ return "HP";
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ return "BT";
+ default:
+ return "OFF";
+ }
+}
+
+const char *AudioHardware::getInputRouteFromDevice(uint32_t device)
+{
+ if (mMicMute) {
+ return "MIC OFF";
+ }
+
+ switch (device) {
+ case AudioSystem::DEVICE_IN_BUILTIN_MIC:
+ return "Main Mic";
+ case AudioSystem::DEVICE_IN_WIRED_HEADSET:
+ return "Hands Free Mic";
+ case AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ return "BT Sco Mic";
+ default:
+ return "MIC OFF";
+ }
+}
+
+uint32_t AudioHardware::getInputSampleRate(uint32_t sampleRate)
+{
+ uint32_t i;
+ uint32_t prevDelta;
+ uint32_t delta;
+
+ for (i = 0, prevDelta = 0xFFFFFFFF; i < sizeof(inputSamplingRates)/sizeof(uint32_t); i++, prevDelta = delta) {
+ delta = abs(sampleRate - inputSamplingRates[i]);
+ if (delta > prevDelta) break;
+ }
+ // i is always > 0 here
+ return inputSamplingRates[i-1];
+}
+
+// getActiveInput_l() must be called with mLock held
+sp <AudioHardware::AudioStreamInALSA> AudioHardware::getActiveInput_l()
+{
+ sp< AudioHardware::AudioStreamInALSA> spIn;
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ // return first input found not being in standby mode
+ // as only one input can be in this state
+ if (!mInputs[i]->checkStandby()) {
+ spIn = mInputs[i];
+ break;
+ }
+ }
+
+ return spIn;
+}
+
+status_t AudioHardware::setInputSource_l(String8 source)
+{
+ LOGV("setInputSource_l(%s)", source.string());
+ if (source != mInputSource) {
+ if ((source == "Default") || (mMode != AudioSystem::MODE_IN_CALL)) {
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ struct mixer_ctl *ctl= mixer_get_control(mMixer, "Input Source", 0);
+ TRACE_DRIVER_OUT
+ if (ctl == NULL) {
+ return NO_INIT;
+ }
+ LOGV("mixer_ctl_select, Input Source, (%s)", source.string());
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(ctl, source.string());
+ TRACE_DRIVER_OUT
+ }
+ }
+ mInputSource = source;
+ }
+
+ return NO_ERROR;
+}
+
+
+//------------------------------------------------------------------------------
+// AudioStreamOutALSA
+//------------------------------------------------------------------------------
+
+AudioHardware::AudioStreamOutALSA::AudioStreamOutALSA() :
+ mHardware(0), mPcm(0), mMixer(0), mRouteCtl(0),
+ mStandby(true), mDevices(0), mChannels(AUDIO_HW_OUT_CHANNELS),
+ mSampleRate(AUDIO_HW_OUT_SAMPLERATE), mBufferSize(AUDIO_HW_OUT_PERIOD_BYTES),
+ mDriverOp(DRV_NONE), mStandbyCnt(0)
+{
+}
+
+status_t AudioHardware::AudioStreamOutALSA::set(
+ AudioHardware* hw, 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;
+
+ mHardware = hw;
+ mDevices = devices;
+
+ // 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;
+
+ mChannels = lChannels;
+ mSampleRate = lRate;
+ mBufferSize = AUDIO_HW_OUT_PERIOD_BYTES;
+
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamOutALSA::~AudioStreamOutALSA()
+{
+ standby();
+}
+
+ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
+{
+ // LOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ const uint8_t* p = static_cast<const uint8_t*>(buffer);
+ int ret;
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+
+ AutoMutex lock(mLock);
+
+ if (mStandby) {
+ AutoMutex hwLock(mHardware->lock());
+
+ LOGD("AudioHardware pcm playback is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
+
+ sp<AudioStreamInALSA> spIn = mHardware->getActiveInput_l();
+ while (spIn != 0) {
+ int cnt = spIn->standbyCnt();
+ mHardware->lock().unlock();
+ // Mutex acquisition order is always out -> in -> hw
+ spIn->lock();
+ mHardware->lock().lock();
+ // make sure that another thread did not change input state
+ // while the mutex is released
+ if ((spIn == mHardware->getActiveInput_l()) &&
+ (cnt == spIn->standbyCnt())) {
+ LOGV("AudioStreamOutALSA::write() force input standby");
+ spIn->close_l();
+ break;
+ }
+ spIn->unlock();
+ spIn = mHardware->getActiveInput_l();
+ }
+ // spIn is not 0 here only if the input was active and has been
+ // closed above
+
+ // open output before input
+ open_l();
+
+ if (spIn != 0) {
+ if (spIn->open_l() != NO_ERROR) {
+ spIn->doStandby_l();
+ }
+ spIn->unlock();
+ }
+ if (mPcm == NULL) {
+ release_wake_lock("AudioOutLock");
+ goto Error;
+ }
+ mStandby = false;
+ }
+
+ TRACE_DRIVER_IN(DRV_PCM_WRITE)
+ ret = pcm_write(mPcm,(void*) p, bytes);
+ TRACE_DRIVER_OUT
+
+ if (ret == 0) {
+ return bytes;
+ }
+ LOGW("write error: %d", errno);
+ status = -errno;
+ }
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
+
+ return status;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::standby()
+{
+ if (mHardware == NULL) return NO_INIT;
+
+ AutoMutex lock(mLock);
+
+ { // scope for the AudioHardware lock
+ AutoMutex hwLock(mHardware->lock());
+
+ doStandby_l();
+ }
+
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamOutALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ LOGD("AudioHardware pcm playback is going to standby.");
+ release_wake_lock("AudioOutLock");
+ mStandby = true;
+ }
+
+ close_l();
+}
+
+void AudioHardware::AudioStreamOutALSA::close_l()
+{
+ if (mMixer) {
+ mHardware->closeMixer_l();
+ mMixer = NULL;
+ mRouteCtl = NULL;
+ }
+ if (mPcm) {
+ mHardware->closePcmOut_l();
+ mPcm = NULL;
+ }
+}
+
+status_t AudioHardware::AudioStreamOutALSA::open_l()
+{
+ LOGV("open pcm_out driver");
+ mPcm = mHardware->openPcmOut_l();
+ if (mPcm == NULL) {
+ return NO_INIT;
+ }
+
+ mMixer = mHardware->openMixer_l();
+ if (mMixer) {
+ LOGV("open playback normal");
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ mRouteCtl = mixer_get_control(mMixer, "Playback Path", 0);
+ TRACE_DRIVER_OUT
+ }
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ const char *route = mHardware->getOutputRouteFromDevice(mDevices);
+ LOGV("write() wakeup setting route %s", route);
+ if (mRouteCtl) {
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(mRouteCtl, route);
+ TRACE_DRIVER_OUT
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ snprintf(buffer, SIZE, "\n\t\tAudioStreamOutALSA maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmRouteCtl: %p\n", mRouteCtl);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+
+ ::write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamOutALSA::checkStandby()
+{
+ return mStandby;
+}
+
+status_t AudioHardware::AudioStreamOutALSA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ status_t status = NO_ERROR;
+ int device;
+ LOGD("AudioStreamOutALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ AutoMutex lock(mLock);
+
+ if (param.getInt(String8(AudioParameter::keyRouting), device) == NO_ERROR)
+ {
+ AutoMutex hwLock(mHardware->lock());
+
+ if (mDevices != (uint32_t)device) {
+ mDevices = (uint32_t)device;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ doStandby_l();
+ }
+ }
+ if (mHardware->mode() == AudioSystem::MODE_IN_CALL) {
+ mHardware->setIncallPath_l(device);
+ }
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+
+
+ return status;
+
+}
+
+String8 AudioHardware::AudioStreamOutALSA::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)mDevices);
+ }
+
+ LOGV("AudioStreamOutALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamOutALSA::getRenderPosition(uint32_t *dspFrames)
+{
+ //TODO
+ return INVALID_OPERATION;
+}
+
+//------------------------------------------------------------------------------
+// AudioStreamInALSA
+//------------------------------------------------------------------------------
+
+AudioHardware::AudioStreamInALSA::AudioStreamInALSA() :
+ mHardware(0), mPcm(0), mMixer(0), mRouteCtl(0),
+ mStandby(true), mDevices(0), mChannels(AUDIO_HW_IN_CHANNELS), mChannelCount(1),
+ mSampleRate(AUDIO_HW_IN_SAMPLERATE), mBufferSize(AUDIO_HW_IN_PERIOD_BYTES),
+ mDownSampler(NULL), mReadStatus(NO_ERROR), mDriverOp(DRV_NONE),
+ mStandbyCnt(0)
+{
+}
+
+status_t AudioHardware::AudioStreamInALSA::set(
+ AudioHardware* hw, uint32_t devices, int *pFormat,
+ uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics)
+{
+ if (pFormat == 0 || *pFormat != AUDIO_HW_IN_FORMAT) {
+ *pFormat = AUDIO_HW_IN_FORMAT;
+ return BAD_VALUE;
+ }
+ if (pRate == 0) {
+ return BAD_VALUE;
+ }
+ uint32_t rate = AudioHardware::getInputSampleRate(*pRate);
+ if (rate != *pRate) {
+ *pRate = rate;
+ return BAD_VALUE;
+ }
+
+ if (pChannels == 0 || (*pChannels != AudioSystem::CHANNEL_IN_MONO &&
+ *pChannels != AudioSystem::CHANNEL_IN_STEREO)) {
+ *pChannels = AUDIO_HW_IN_CHANNELS;
+ return BAD_VALUE;
+ }
+
+ mHardware = hw;
+
+ LOGV("AudioStreamInALSA::set(%d, %d, %u)", *pFormat, *pChannels, *pRate);
+
+ mBufferSize = getBufferSize(*pRate, AudioSystem::popCount(*pChannels));
+ mDevices = devices;
+ mChannels = *pChannels;
+ mChannelCount = AudioSystem::popCount(mChannels);
+ mSampleRate = rate;
+ if (mSampleRate != AUDIO_HW_OUT_SAMPLERATE) {
+ mDownSampler = new AudioHardware::DownSampler(mSampleRate,
+ mChannelCount,
+ AUDIO_HW_IN_PERIOD_SZ,
+ this);
+ status_t status = mDownSampler->initCheck();
+ if (status != NO_ERROR) {
+ delete mDownSampler;
+ LOGW("AudioStreamInALSA::set() downsampler init failed: %d", status);
+ return status;
+ }
+
+ mPcmIn = new int16_t[AUDIO_HW_IN_PERIOD_SZ * mChannelCount];
+ }
+ return NO_ERROR;
+}
+
+AudioHardware::AudioStreamInALSA::~AudioStreamInALSA()
+{
+ standby();
+ if (mDownSampler != NULL) {
+ delete mDownSampler;
+ if (mPcmIn != NULL) {
+ delete[] mPcmIn;
+ }
+ }
+}
+
+ssize_t AudioHardware::AudioStreamInALSA::read(void* buffer, ssize_t bytes)
+{
+ // LOGV("AudioStreamInALSA::read(%p, %u)", buffer, bytes);
+ status_t status = NO_INIT;
+ int ret;
+
+ if (mHardware == NULL) return NO_INIT;
+
+ { // scope for the lock
+ AutoMutex lock(mLock);
+
+ if (mStandby) {
+ AutoMutex hwLock(mHardware->lock());
+
+ LOGD("AudioHardware pcm capture is exiting standby.");
+ acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
+
+ sp<AudioStreamOutALSA> spOut = mHardware->output();
+ while (spOut != 0) {
+ if (!spOut->checkStandby()) {
+ int cnt = spOut->standbyCnt();
+ mHardware->lock().unlock();
+ mLock.unlock();
+ // Mutex acquisition order is always out -> in -> hw
+ spOut->lock();
+ mLock.lock();
+ mHardware->lock().lock();
+ // make sure that another thread did not change output state
+ // while the mutex is released
+ if ((spOut == mHardware->output()) && (cnt == spOut->standbyCnt())) {
+ LOGV("AudioStreamInALSA::read() force output standby");
+ spOut->close_l();
+ break;
+ }
+ spOut->unlock();
+ spOut = mHardware->output();
+ } else {
+ spOut.clear();
+ }
+ }
+ // spOut is not 0 here only if the output was active and has been
+ // closed above
+
+ // open output before input
+ if (spOut != 0) {
+ if (spOut->open_l() != NO_ERROR) {
+ spOut->doStandby_l();
+ }
+ spOut->unlock();
+ }
+
+ open_l();
+
+ if (mPcm == NULL) {
+ release_wake_lock("AudioInLock");
+ goto Error;
+ }
+ mStandby = false;
+ }
+
+
+ if (mDownSampler != NULL) {
+ size_t frames = bytes / frameSize();
+ size_t framesIn = 0;
+ mReadStatus = 0;
+ do {
+ size_t outframes = frames - framesIn;
+ mDownSampler->resample(
+ (int16_t *)buffer + (framesIn * mChannelCount),
+ &outframes);
+ framesIn += outframes;
+ } while ((framesIn < frames) && mReadStatus == 0);
+ ret = mReadStatus;
+ bytes = framesIn * frameSize();
+ } else {
+ TRACE_DRIVER_IN(DRV_PCM_READ)
+ ret = pcm_read(mPcm, buffer, bytes);
+ TRACE_DRIVER_OUT
+ }
+
+ if (ret == 0) {
+ return bytes;
+ }
+
+ LOGW("read error: %d", ret);
+ status = ret;
+ }
+
+Error:
+
+ standby();
+
+ // Simulate audio output timing in case of error
+ usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());
+
+ return status;
+}
+
+status_t AudioHardware::AudioStreamInALSA::standby()
+{
+ if (mHardware == NULL) return NO_INIT;
+
+ AutoMutex lock(mLock);
+
+ { // scope for AudioHardware lock
+ AutoMutex hwLock(mHardware->lock());
+
+ doStandby_l();
+ }
+ return NO_ERROR;
+}
+
+void AudioHardware::AudioStreamInALSA::doStandby_l()
+{
+ mStandbyCnt++;
+
+ if (!mStandby) {
+ LOGD("AudioHardware pcm capture is going to standby.");
+ release_wake_lock("AudioInLock");
+ mStandby = true;
+ }
+ close_l();
+}
+
+void AudioHardware::AudioStreamInALSA::close_l()
+{
+ if (mMixer) {
+ mHardware->closeMixer_l();
+ mMixer = NULL;
+ mRouteCtl = NULL;
+ }
+
+ if (mPcm) {
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ }
+}
+
+status_t AudioHardware::AudioStreamInALSA::open_l()
+{
+ unsigned flags = PCM_IN;
+ if (mChannels == AudioSystem::CHANNEL_IN_MONO) {
+ flags |= PCM_MONO;
+ }
+ flags |= (AUDIO_HW_IN_PERIOD_MULT - 1) << PCM_PERIOD_SZ_SHIFT;
+ flags |= (AUDIO_HW_IN_PERIOD_CNT - PCM_PERIOD_CNT_MIN)
+ << PCM_PERIOD_CNT_SHIFT;
+
+ LOGV("open pcm_in driver");
+ TRACE_DRIVER_IN(DRV_PCM_OPEN)
+ mPcm = pcm_open(flags);
+ TRACE_DRIVER_OUT
+ if (!pcm_ready(mPcm)) {
+ LOGE("cannot open pcm_in driver: %s\n", pcm_error(mPcm));
+ TRACE_DRIVER_IN(DRV_PCM_CLOSE)
+ pcm_close(mPcm);
+ TRACE_DRIVER_OUT
+ mPcm = NULL;
+ return NO_INIT;
+ }
+
+ if (mDownSampler != NULL) {
+ mInPcmInBuf = 0;
+ mDownSampler->reset();
+ }
+
+ mMixer = mHardware->openMixer_l();
+ if (mMixer) {
+ TRACE_DRIVER_IN(DRV_MIXER_GET)
+ mRouteCtl = mixer_get_control(mMixer, "Capture MIC Path", 0);
+ TRACE_DRIVER_OUT
+ }
+
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ const char *route = mHardware->getInputRouteFromDevice(mDevices);
+ LOGV("read() wakeup setting route %s", route);
+ if (mRouteCtl) {
+ TRACE_DRIVER_IN(DRV_MIXER_SEL)
+ mixer_ctl_select(mRouteCtl, route);
+ TRACE_DRIVER_OUT
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t AudioHardware::AudioStreamInALSA::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ bool locked = tryLock(mLock);
+ if (!locked) {
+ snprintf(buffer, SIZE, "\n\t\tAudioStreamInALSA maybe deadlocked\n");
+ } else {
+ mLock.unlock();
+ }
+
+ snprintf(buffer, SIZE, "\t\tmHardware: %p\n", mHardware);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmPcm: %p\n", mPcm);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmMixer: %p\n", mMixer);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tStandby %s\n", (mStandby) ? "ON" : "OFF");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDevices: 0x%08x\n", mDevices);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmChannels: 0x%08x\n", mChannels);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmSampleRate: %d\n", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmBufferSize: %d\n", mBufferSize);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t\tmDriverOp: %d\n", mDriverOp);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ return NO_ERROR;
+}
+
+bool AudioHardware::AudioStreamInALSA::checkStandby()
+{
+ return mStandby;
+}
+
+status_t AudioHardware::AudioStreamInALSA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ status_t status = NO_ERROR;
+ int value;
+ String8 source;
+
+ LOGD("AudioStreamInALSA::setParameters() %s", keyValuePairs.string());
+
+ if (mHardware == NULL) return NO_INIT;
+
+ {
+ AutoMutex lock(mLock);
+
+ if (param.get(String8(INPUT_SOURCE_KEY), source) == NO_ERROR) {
+ AutoMutex hwLock(mHardware->lock());
+
+ mHardware->openMixer_l();
+ mHardware->setInputSource_l(source);
+ mHardware->closeMixer_l();
+
+ param.remove(String8(INPUT_SOURCE_KEY));
+ }
+
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR)
+ {
+ if (value != 0) {
+ AutoMutex hwLock(mHardware->lock());
+
+ if (mDevices != (uint32_t)value) {
+ mDevices = (uint32_t)value;
+ if (mHardware->mode() != AudioSystem::MODE_IN_CALL) {
+ doStandby_l();
+ }
+ }
+ }
+ param.remove(String8(AudioParameter::keyRouting));
+ }
+ }
+
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+
+ return status;
+
+}
+
+String8 AudioHardware::AudioStreamInALSA::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)mDevices);
+ }
+
+ LOGV("AudioStreamInALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+status_t AudioHardware::AudioStreamInALSA::getNextBuffer(AudioHardware::BufferProvider::Buffer* buffer)
+{
+ if (mPcm == NULL) {
+ buffer->raw = NULL;
+ buffer->frameCount = 0;
+ mReadStatus = NO_INIT;
+ return NO_INIT;
+ }
+
+ if (mInPcmInBuf == 0) {
+ TRACE_DRIVER_IN(DRV_PCM_READ)
+ mReadStatus = pcm_read(mPcm,(void*) mPcmIn, AUDIO_HW_IN_PERIOD_SZ * frameSize());
+ TRACE_DRIVER_OUT
+ if (mReadStatus != 0) {
+ buffer->raw = NULL;
+ buffer->frameCount = 0;
+ return mReadStatus;
+ }
+ mInPcmInBuf = AUDIO_HW_IN_PERIOD_SZ;
+ }
+
+ buffer->frameCount = (buffer->frameCount > mInPcmInBuf) ? mInPcmInBuf : buffer->frameCount;
+ buffer->i16 = mPcmIn + (AUDIO_HW_IN_PERIOD_SZ - mInPcmInBuf) * mChannelCount;
+
+ return mReadStatus;
+}
+
+void AudioHardware::AudioStreamInALSA::releaseBuffer(Buffer* buffer)
+{
+ mInPcmInBuf -= buffer->frameCount;
+}
+
+size_t AudioHardware::AudioStreamInALSA::getBufferSize(uint32_t sampleRate, int channelCount)
+{
+ size_t ratio;
+
+ switch (sampleRate) {
+ case 8000:
+ case 11025:
+ ratio = 4;
+ break;
+ case 16000:
+ case 22050:
+ ratio = 2;
+ break;
+ case 44100:
+ default:
+ ratio = 1;
+ break;
+ }
+
+ return (AUDIO_HW_IN_PERIOD_SZ*channelCount*sizeof(int16_t)) / ratio ;
+}
+
+//------------------------------------------------------------------------------
+// DownSampler
+//------------------------------------------------------------------------------
+
+/*
+ * 2.30 fixed point FIR filter coefficients for conversion 44100 -> 22050.
+ * (Works equivalently for 22010 -> 11025 or any other halving, of course.)
+ *
+ * Transition band from about 18 kHz, passband ripple < 0.1 dB,
+ * stopband ripple at about -55 dB, linear phase.
+ *
+ * Design and display in MATLAB or Octave using:
+ *
+ * filter = fir1(19, 0.5); filter = round(filter * 2**30); freqz(filter * 2**-30);
+ */
+static const int32_t filter_22khz_coeff[] = {
+ 2089257, 2898328, -5820678, -10484531,
+ 19038724, 30542725, -50469415, -81505260,
+ 152544464, 478517512, 478517512, 152544464,
+ -81505260, -50469415, 30542725, 19038724,
+ -10484531, -5820678, 2898328, 2089257,
+};
+#define NUM_COEFF_22KHZ (sizeof(filter_22khz_coeff) / sizeof(filter_22khz_coeff[0]))
+#define OVERLAP_22KHZ (NUM_COEFF_22KHZ - 2)
+
+/*
+ * Convolution of signals A and reverse(B). (In our case, the filter response
+ * is symmetric, so the reversing doesn't matter.)
+ * A is taken to be in 0.16 fixed-point, and B is taken to be in 2.30 fixed-point.
+ * The answer will be in 16.16 fixed-point, unclipped.
+ *
+ * This function would probably be the prime candidate for SIMD conversion if
+ * you want more speed.
+ */
+int32_t fir_convolve(const int16_t* a, const int32_t* b, int num_samples)
+{
+ int32_t sum = 1 << 13;
+ for (int i = 0; i < num_samples; ++i) {
+ sum += a[i] * (b[i] >> 16);
+ }
+ return sum >> 14;
+}
+
+/* Clip from 16.16 fixed-point to 0.16 fixed-point. */
+int16_t clip(int32_t x)
+{
+ if (x < -32768) {
+ return -32768;
+ } else if (x > 32767) {
+ return 32767;
+ } else {
+ return x;
+ }
+}
+
+/*
+ * Convert a chunk from 44 kHz to 22 kHz. Will update num_samples_in and num_samples_out
+ * accordingly, since it may leave input samples in the buffer due to overlap.
+ *
+ * Input and output are taken to be in 0.16 fixed-point.
+ */
+void resample_2_1(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
+{
+ if (*num_samples_in < (int)NUM_COEFF_22KHZ) {
+ *num_samples_out = 0;
+ return;
+ }
+
+ int odd_smp = *num_samples_in & 0x1;
+ int num_samples = *num_samples_in - odd_smp - OVERLAP_22KHZ;
+
+ for (int i = 0; i < num_samples; i += 2) {
+ output[i / 2] = clip(fir_convolve(input + i, filter_22khz_coeff, NUM_COEFF_22KHZ));
+ }
+
+ memmove(input, input + num_samples, (OVERLAP_22KHZ + odd_smp) * sizeof(*input));
+ *num_samples_out = num_samples / 2;
+ *num_samples_in = OVERLAP_22KHZ + odd_smp;
+}
+
+/*
+ * 2.30 fixed point FIR filter coefficients for conversion 22050 -> 16000,
+ * or 11025 -> 8000.
+ *
+ * Transition band from about 14 kHz, passband ripple < 0.1 dB,
+ * stopband ripple at about -50 dB, linear phase.
+ *
+ * Design and display in MATLAB or Octave using:
+ *
+ * filter = fir1(23, 16000 / 22050); filter = round(filter * 2**30); freqz(filter * 2**-30);
+ */
+static const int32_t filter_16khz_coeff[] = {
+ 2057290, -2973608, 1880478, 4362037,
+ -14639744, 18523609, -1609189, -38502470,
+ 78073125, -68353935, -59103896, 617555440,
+ 617555440, -59103896, -68353935, 78073125,
+ -38502470, -1609189, 18523609, -14639744,
+ 4362037, 1880478, -2973608, 2057290,
+};
+#define NUM_COEFF_16KHZ (sizeof(filter_16khz_coeff) / sizeof(filter_16khz_coeff[0]))
+#define OVERLAP_16KHZ (NUM_COEFF_16KHZ - 1)
+
+/*
+ * Convert a chunk from 22 kHz to 16 kHz. Will update num_samples_in and
+ * num_samples_out accordingly, since it may leave input samples in the buffer
+ * due to overlap.
+ *
+ * This implementation is rather ad-hoc; it first low-pass filters the data
+ * into a temporary buffer, and then converts chunks of 441 input samples at a
+ * time into 320 output samples by simple linear interpolation. A better
+ * implementation would use a polyphase filter bank to do these two operations
+ * in one step.
+ *
+ * Input and output are taken to be in 0.16 fixed-point.
+ */
+
+#define RESAMPLE_16KHZ_SAMPLES_IN 441
+#define RESAMPLE_16KHZ_SAMPLES_OUT 320
+
+void resample_441_320(int16_t* input, int16_t* output, int* num_samples_in, int* num_samples_out)
+{
+ const int num_blocks = (*num_samples_in - OVERLAP_16KHZ) / RESAMPLE_16KHZ_SAMPLES_IN;
+ if (num_blocks < 1) {
+ *num_samples_out = 0;
+ return;
+ }
+
+ for (int i = 0; i < num_blocks; ++i) {
+ uint32_t tmp[RESAMPLE_16KHZ_SAMPLES_IN];
+ for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_IN; ++j) {
+ tmp[j] = fir_convolve(input + i * RESAMPLE_16KHZ_SAMPLES_IN + j,
+ filter_16khz_coeff,
+ NUM_COEFF_16KHZ);
+ }
+
+ const float step_float = (float)RESAMPLE_16KHZ_SAMPLES_IN / (float)RESAMPLE_16KHZ_SAMPLES_OUT;
+
+ uint32_t in_sample_num = 0; // 16.16 fixed point
+ const uint32_t step = (uint32_t)(step_float * 65536.0f + 0.5f); // 16.16 fixed point
+ for (int j = 0; j < RESAMPLE_16KHZ_SAMPLES_OUT; ++j, in_sample_num += step) {
+ const uint32_t whole = in_sample_num >> 16;
+ const uint32_t frac = (in_sample_num & 0xffff); // 0.16 fixed point
+ const int32_t s1 = tmp[whole];
+ const int32_t s2 = tmp[whole + 1];
+ *output++ = clip(s1 + (((s2 - s1) * (int32_t)frac) >> 16));
+ }
+ }
+
+ const int samples_consumed = num_blocks * RESAMPLE_16KHZ_SAMPLES_IN;
+ memmove(input, input + samples_consumed, (*num_samples_in - samples_consumed) * sizeof(*input));
+ *num_samples_in -= samples_consumed;
+ *num_samples_out = RESAMPLE_16KHZ_SAMPLES_OUT * num_blocks;
+}
+
+
+AudioHardware::DownSampler::DownSampler(uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t frameCount,
+ AudioHardware::BufferProvider* provider)
+ : mStatus(NO_INIT), mProvider(provider), mSampleRate(outSampleRate),
+ mChannelCount(channelCount), mFrameCount(frameCount),
+ mInLeft(NULL), mInRight(NULL), mTmpLeft(NULL), mTmpRight(NULL),
+ mTmp2Left(NULL), mTmp2Right(NULL), mOutLeft(NULL), mOutRight(NULL)
+
+{
+ LOGV("AudioHardware::DownSampler() cstor %p SR %d channels %d frames %d",
+ this, mSampleRate, mChannelCount, mFrameCount);
+
+ if (mSampleRate != 8000 && mSampleRate != 11025 && mSampleRate != 16000 &&
+ mSampleRate != 22050) {
+ LOGW("AudioHardware::DownSampler cstor: bad sampling rate: %d", mSampleRate);
+ return;
+ }
+
+ mInLeft = new int16_t[mFrameCount];
+ mInRight = new int16_t[mFrameCount];
+ mTmpLeft = new int16_t[mFrameCount];
+ mTmpRight = new int16_t[mFrameCount];
+ mTmp2Left = new int16_t[mFrameCount];
+ mTmp2Right = new int16_t[mFrameCount];
+ mOutLeft = new int16_t[mFrameCount];
+ mOutRight = new int16_t[mFrameCount];
+
+ mStatus = NO_ERROR;
+}
+
+AudioHardware::DownSampler::~DownSampler()
+{
+ if (mInLeft) delete[] mInLeft;
+ if (mInRight) delete[] mInRight;
+ if (mTmpLeft) delete[] mTmpLeft;
+ if (mTmpRight) delete[] mTmpRight;
+ if (mTmp2Left) delete[] mTmp2Left;
+ if (mTmp2Right) delete[] mTmp2Right;
+ if (mOutLeft) delete[] mOutLeft;
+ if (mOutRight) delete[] mOutRight;
+}
+
+void AudioHardware::DownSampler::reset()
+{
+ mInInBuf = 0;
+ mInTmpBuf = 0;
+ mInTmp2Buf = 0;
+ mOutBufPos = 0;
+ mInOutBuf = 0;
+}
+
+
+int AudioHardware::DownSampler::resample(int16_t* out, size_t *outFrameCount)
+{
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+
+ if (out == NULL || outFrameCount == NULL) {
+ return BAD_VALUE;
+ }
+
+ int16_t *outLeft = mTmp2Left;
+ int16_t *outRight = mTmp2Left;
+ if (mSampleRate == 22050) {
+ outLeft = mTmpLeft;
+ outRight = mTmpRight;
+ } else if (mSampleRate == 8000){
+ outLeft = mOutLeft;
+ outRight = mOutRight;
+ }
+
+ int outFrames = 0;
+ int remaingFrames = *outFrameCount;
+
+ if (mInOutBuf) {
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ for (int i = 0; i < frames; ++i) {
+ out[i] = outLeft[mOutBufPos + i];
+ }
+ if (mChannelCount == 2) {
+ for (int i = 0; i < frames; ++i) {
+ out[i * 2] = outLeft[mOutBufPos + i];
+ out[i * 2 + 1] = outRight[mOutBufPos + i];
+ }
+ }
+ remaingFrames -= frames;
+ mInOutBuf -= frames;
+ mOutBufPos += frames;
+ outFrames += frames;
+ }
+
+ while (remaingFrames) {
+ LOGW_IF((mInOutBuf != 0), "mInOutBuf should be 0 here");
+
+ AudioHardware::BufferProvider::Buffer buf;
+ buf.frameCount = mFrameCount - mInInBuf;
+ int ret = mProvider->getNextBuffer(&buf);
+ if (buf.raw == NULL) {
+ *outFrameCount = outFrames;
+ return ret;
+ }
+
+ for (size_t i = 0; i < buf.frameCount; ++i) {
+ mInLeft[i + mInInBuf] = buf.i16[i];
+ }
+ if (mChannelCount == 2) {
+ for (size_t i = 0; i < buf.frameCount; ++i) {
+ mInLeft[i + mInInBuf] = buf.i16[i * 2];
+ mInRight[i + mInInBuf] = buf.i16[i * 2 + 1];
+ }
+ }
+ mInInBuf += buf.frameCount;
+ mProvider->releaseBuffer(&buf);
+
+ /* 44010 -> 22050 */
+ {
+ int samples_in_left = mInInBuf;
+ int samples_out_left;
+ resample_2_1(mInLeft, mTmpLeft + mInTmpBuf, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInInBuf;
+ int samples_out_right;
+ resample_2_1(mInRight, mTmpRight + mInTmpBuf, &samples_in_right, &samples_out_right);
+ }
+
+ mInInBuf = samples_in_left;
+ mInTmpBuf += samples_out_left;
+ mInOutBuf = samples_out_left;
+ }
+
+ if (mSampleRate == 11025 || mSampleRate == 8000) {
+ /* 22050 - > 11025 */
+ int samples_in_left = mInTmpBuf;
+ int samples_out_left;
+ resample_2_1(mTmpLeft, mTmp2Left + mInTmp2Buf, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmpBuf;
+ int samples_out_right;
+ resample_2_1(mTmpRight, mTmp2Right + mInTmp2Buf, &samples_in_right, &samples_out_right);
+ }
+
+
+ mInTmpBuf = samples_in_left;
+ mInTmp2Buf += samples_out_left;
+ mInOutBuf = samples_out_left;
+
+ if (mSampleRate == 8000) {
+ /* 11025 -> 8000*/
+ int samples_in_left = mInTmp2Buf;
+ int samples_out_left;
+ resample_441_320(mTmp2Left, mOutLeft, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmp2Buf;
+ int samples_out_right;
+ resample_441_320(mTmp2Right, mOutRight, &samples_in_right, &samples_out_right);
+ }
+
+ mInTmp2Buf = samples_in_left;
+ mInOutBuf = samples_out_left;
+ } else {
+ mInTmp2Buf = 0;
+ }
+
+ } else if (mSampleRate == 16000) {
+ /* 22050 -> 16000*/
+ int samples_in_left = mInTmpBuf;
+ int samples_out_left;
+ resample_441_320(mTmpLeft, mTmp2Left, &samples_in_left, &samples_out_left);
+
+ if (mChannelCount == 2) {
+ int samples_in_right = mInTmpBuf;
+ int samples_out_right;
+ resample_441_320(mTmpRight, mTmp2Right, &samples_in_right, &samples_out_right);
+ }
+
+ mInTmpBuf = samples_in_left;
+ mInOutBuf = samples_out_left;
+ } else {
+ mInTmpBuf = 0;
+ }
+
+ int frames = (remaingFrames > mInOutBuf) ? mInOutBuf : remaingFrames;
+
+ for (int i = 0; i < frames; ++i) {
+ out[outFrames + i] = outLeft[i];
+ }
+ if (mChannelCount == 2) {
+ for (int i = 0; i < frames; ++i) {
+ out[(outFrames + i) * 2] = outLeft[i];
+ out[(outFrames + i) * 2 + 1] = outRight[i];
+ }
+ }
+ remaingFrames -= frames;
+ outFrames += frames;
+ mOutBufPos = frames;
+ mInOutBuf -= frames;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+//------------------------------------------------------------------------------
+// Factory
+//------------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void) {
+ return new AudioHardware();
+}
+
+}; // namespace android
diff --git a/libaudio/AudioHardware.h b/libaudio/AudioHardware.h
new file mode 100644
index 0000000..1379495
--- /dev/null
+++ b/libaudio/AudioHardware.h
@@ -0,0 +1,348 @@
+/*
+** 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_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+#include "secril-client.h"
+
+extern "C" {
+ struct pcm;
+ struct mixer;
+ struct mixer_ctl;
+};
+
+namespace android {
+
+// TODO: determine actual audio DSP and hardware latency
+// Additionnal latency introduced by audio DSP and hardware in ms
+#define AUDIO_HW_OUT_LATENCY_MS 0
+// Default audio output sample rate
+#define AUDIO_HW_OUT_SAMPLERATE 44100
+// Default audio output channel mask
+#define AUDIO_HW_OUT_CHANNELS (AudioSystem::CHANNEL_OUT_STEREO)
+// Default audio output sample format
+#define AUDIO_HW_OUT_FORMAT (AudioSystem::PCM_16_BIT)
+// Kernel pcm out buffer size in frames at 44.1kHz
+#define AUDIO_HW_OUT_PERIOD_MULT 8 // (8 * 128 = 1024 frames)
+#define AUDIO_HW_OUT_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_OUT_PERIOD_MULT)
+#define AUDIO_HW_OUT_PERIOD_CNT 4
+// Default audio output buffer size in bytes
+#define AUDIO_HW_OUT_PERIOD_BYTES (AUDIO_HW_OUT_PERIOD_SZ * 2 * sizeof(int16_t))
+
+// Default audio input sample rate
+#define AUDIO_HW_IN_SAMPLERATE 8000
+// Default audio input channel mask
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO)
+// Default audio input sample format
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT)
+// Number of buffers in audio driver for input
+#define AUDIO_HW_NUM_IN_BUF 2
+// Kernel pcm in buffer size in frames at 44.1kHz (before resampling)
+#define AUDIO_HW_IN_PERIOD_MULT 16 // (16 * 128 = 2048 frames)
+#define AUDIO_HW_IN_PERIOD_SZ (PCM_PERIOD_SZ_MIN * AUDIO_HW_IN_PERIOD_MULT)
+#define AUDIO_HW_IN_PERIOD_CNT 2
+// Default audio input buffer size in bytes (8kHz mono)
+#define AUDIO_HW_IN_PERIOD_BYTES ((AUDIO_HW_IN_PERIOD_SZ*sizeof(int16_t))/8)
+
+#define INPUT_SOURCE_KEY "Input Source"
+
+class AudioHardware : public AudioHardwareBase
+{
+ class AudioStreamOutALSA;
+ class AudioStreamInALSA;
+public:
+
+ AudioHardware();
+ virtual ~AudioHardware();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+ virtual status_t setMasterVolume(float volume);
+
+ virtual status_t setMode(int mode);
+
+ 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 AudioStreamOut* openOutputStream(
+ uint32_t devices, int *format=0, uint32_t *channels=0,
+ uint32_t *sampleRate=0, status_t *status=0);
+
+ virtual AudioStreamIn* openInputStream(
+ uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual void closeOutputStream(AudioStreamOut* out);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual size_t getInputBufferSize(
+ uint32_t sampleRate, int format, int channelCount);
+
+ int mode() { return mMode; }
+ const char *getOutputRouteFromDevice(uint32_t device);
+ const char *getInputRouteFromDevice(uint32_t device);
+ const char *getVoiceRouteFromDevice(uint32_t device);
+
+ status_t setIncallPath_l(uint32_t device);
+
+ status_t setInputSource_l(String8 source);
+
+ static uint32_t getInputSampleRate(uint32_t sampleRate);
+ sp <AudioStreamInALSA> getActiveInput_l();
+
+ Mutex& lock() { return mLock; }
+
+ struct pcm *openPcmOut_l();
+ void closePcmOut_l();
+
+ struct mixer *openMixer_l();
+ void closeMixer_l();
+
+ sp <AudioStreamOutALSA> output() { return mOutput; }
+
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ bool mInit;
+ bool mMicMute;
+ sp <AudioStreamOutALSA> mOutput;
+ SortedVector < sp<AudioStreamInALSA> > mInputs;
+ Mutex mLock;
+ struct pcm* mPcm;
+ struct mixer* mMixer;
+ uint32_t mPcmOpenCnt;
+ uint32_t mMixerOpenCnt;
+ bool mInCallAudioMode;
+
+ String8 mInputSource;
+ bool mBluetoothNrec;
+ void* mSecRilLibHandle;
+ HRilClient mRilClient;
+ bool mActivatedCP;
+ HRilClient (*openClientRILD) (void);
+ int (*disconnectRILD) (HRilClient);
+ int (*closeClientRILD) (HRilClient);
+ int (*isConnectedRILD) (HRilClient);
+ int (*connectRILD) (HRilClient);
+ int (*setCallVolume) (HRilClient, SoundType, int);
+ int (*setCallAudioPath)(HRilClient, AudioPath);
+ int (*setCallClockSync)(HRilClient, SoundClockCondition);
+ void loadRILD(void);
+ status_t connectRILDIfRequired(void);
+
+ // trace driver operations for dump
+ int mDriverOp;
+
+ static uint32_t checkInputSampleRate(uint32_t sampleRate);
+ static const uint32_t inputSamplingRates[];
+
+ class AudioStreamOutALSA : public AudioStreamOut, public RefBase
+ {
+ public:
+ AudioStreamOutALSA();
+ virtual ~AudioStreamOutALSA();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate()
+ const { return mSampleRate; }
+ virtual size_t bufferSize()
+ const { return mBufferSize; }
+ virtual uint32_t channels()
+ const { return mChannels; }
+ virtual int format()
+ const { return AUDIO_HW_OUT_FORMAT; }
+ virtual uint32_t latency()
+ const { return (1000 * AUDIO_HW_OUT_PERIOD_CNT *
+ (bufferSize()/frameSize()))/sampleRate() +
+ AUDIO_HW_OUT_LATENCY_MS; }
+ 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();
+ bool checkStandby();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t device() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ private:
+
+ Mutex mLock;
+ AudioHardware* mHardware;
+ struct pcm *mPcm;
+ struct mixer *mMixer;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ };
+
+ class DownSampler;
+
+ class BufferProvider
+ {
+ public:
+
+ struct Buffer {
+ union {
+ void* raw;
+ short* i16;
+ int8_t* i8;
+ };
+ size_t frameCount;
+ };
+
+ virtual ~BufferProvider() {}
+
+ virtual status_t getNextBuffer(Buffer* buffer) = 0;
+ virtual void releaseBuffer(Buffer* buffer) = 0;
+ };
+
+ class DownSampler {
+ public:
+ DownSampler(uint32_t outSampleRate,
+ uint32_t channelCount,
+ uint32_t frameCount,
+ BufferProvider* provider);
+
+ virtual ~DownSampler();
+
+ void reset();
+ status_t initCheck() { return mStatus; }
+ int resample(int16_t* out, size_t *outFrameCount);
+
+ private:
+ status_t mStatus;
+ BufferProvider* mProvider;
+ uint32_t mSampleRate;
+ uint32_t mChannelCount;
+ uint32_t mFrameCount;
+ int16_t *mInLeft;
+ int16_t *mInRight;
+ int16_t *mTmpLeft;
+ int16_t *mTmpRight;
+ int16_t *mTmp2Left;
+ int16_t *mTmp2Right;
+ int16_t *mOutLeft;
+ int16_t *mOutRight;
+ int mInInBuf;
+ int mInTmpBuf;
+ int mInTmp2Buf;
+ int mOutBufPos;
+ int mInOutBuf;
+ };
+
+
+ class AudioStreamInALSA : public AudioStreamIn, public BufferProvider, public RefBase
+ {
+
+ public:
+ AudioStreamInALSA();
+ virtual ~AudioStreamInALSA();
+ status_t set(AudioHardware* hw,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return AUDIO_HW_IN_FORMAT; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ 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();
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t device() { return mDevices; }
+ void doStandby_l();
+ void close_l();
+ status_t open_l();
+ int standbyCnt() { return mStandbyCnt; }
+
+ static size_t getBufferSize(uint32_t sampleRate, int channelCount);
+
+ // BufferProvider
+ virtual status_t getNextBuffer(BufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(BufferProvider::Buffer* buffer);
+
+ void lock() { mLock.lock(); }
+ void unlock() { mLock.unlock(); }
+
+ private:
+ Mutex mLock;
+ AudioHardware* mHardware;
+ struct pcm *mPcm;
+ struct mixer *mMixer;
+ struct mixer_ctl *mRouteCtl;
+ const char *next_route;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mChannelCount;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ DownSampler *mDownSampler;
+ status_t mReadStatus;
+ size_t mInPcmInBuf;
+ int16_t *mPcmIn;
+ // trace driver operations for dump
+ int mDriverOp;
+ int mStandbyCnt;
+ };
+
+};
+
+}; // namespace android
+
+#endif
diff --git a/libaudio/AudioPolicyManager.cpp b/libaudio/AudioPolicyManager.cpp
new file mode 100644
index 0000000..93d70d8
--- /dev/null
+++ b/libaudio/AudioPolicyManager.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "AudioPolicyManager"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <media/mediarecorder.h>
+
+namespace android {
+
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager for crespo platform
+// Common audio policy manager code is implemented in AudioPolicyManagerBase class
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+ status_t status = AudioPolicyManagerBase::startInput(input);
+
+ if (status == NO_ERROR) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(input);
+ String8 key = String8("Input Source");
+ String8 value;
+ switch(inputDesc->mInputSource) {
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ value = String8("Voice Recognition");
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ value = String8("Camcorder");
+ break;
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ value = String8("Default");
+ default:
+ break;
+ }
+ AudioParameter param = AudioParameter();
+ param.add(key, value);
+ mpClientInterface->setParameters(input, param.toString());
+ }
+ return status;
+}
+
+}; // namespace android
diff --git a/libaudio/AudioPolicyManager.h b/libaudio/AudioPolicyManager.h
new file mode 100644
index 0000000..ae283db
--- /dev/null
+++ b/libaudio/AudioPolicyManager.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+
+namespace android {
+
+class AudioPolicyManager: public AudioPolicyManagerBase
+{
+
+public:
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface) {}
+
+ virtual ~AudioPolicyManager() {}
+
+ virtual status_t startInput(audio_io_handle_t input);
+protected:
+ // true is current platform implements a back microphone
+ virtual bool hasBackMicrophone() const { return false; }
+#ifdef WITH_A2DP
+ // true is current platform supports duplication of notifications and ringtones over A2DP output
+ virtual bool a2dpUsedForSonification() const { return true; }
+#endif
+
+};
+};
diff --git a/libaudio/alsa_audio.h b/libaudio/alsa_audio.h
new file mode 100644
index 0000000..3cb86d9
--- /dev/null
+++ b/libaudio/alsa_audio.h
@@ -0,0 +1,77 @@
+/*
+** Copyright 2010, 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 _AUDIO_H_
+#define _AUDIO_H_
+
+struct pcm;
+
+#define PCM_OUT 0x00000000
+#define PCM_IN 0x10000000
+
+#define PCM_STEREO 0x00000000
+#define PCM_MONO 0x01000000
+
+#define PCM_44100HZ 0x00000000
+#define PCM_48000HZ 0x00100000
+#define PCM_8000HZ 0x00200000
+#define PCM_RATE_MASK 0x00F00000
+
+#define PCM_PERIOD_CNT_MIN 2
+#define PCM_PERIOD_CNT_SHIFT 16
+#define PCM_PERIOD_CNT_MASK (0xF << PCM_PERIOD_CNT_SHIFT)
+#define PCM_PERIOD_SZ_MIN 128
+#define PCM_PERIOD_SZ_SHIFT 12
+#define PCM_PERIOD_SZ_MASK (0xF << PCM_PERIOD_SZ_SHIFT)
+
+/* Acquire/release a pcm channel.
+ * Returns non-zero on error
+ */
+struct pcm *pcm_open(unsigned flags);
+int pcm_close(struct pcm *pcm);
+int pcm_ready(struct pcm *pcm);
+
+/* Returns a human readable reason for the last error. */
+const char *pcm_error(struct pcm *pcm);
+
+/* Returns the buffer size (int bytes) that should be used for pcm_write.
+ * This will be 1/2 of the actual fifo size.
+ */
+unsigned pcm_buffer_size(struct pcm *pcm);
+
+/* Write data to the fifo.
+ * Will start playback on the first write or on a write that
+ * occurs after a fifo underrun.
+ */
+int pcm_write(struct pcm *pcm, void *data, unsigned count);
+int pcm_read(struct pcm *pcm, void *data, unsigned count);
+
+struct mixer;
+struct mixer_ctl;
+
+struct mixer *mixer_open(void);
+void mixer_close(struct mixer *mixer);
+void mixer_dump(struct mixer *mixer);
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index);
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n);
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent);
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value);
+void mixer_ctl_print(struct mixer_ctl *ctl);
+
+#endif
diff --git a/libaudio/alsa_mixer.c b/libaudio/alsa_mixer.c
new file mode 100644
index 0000000..3036ef8
--- /dev/null
+++ b/libaudio/alsa_mixer.c
@@ -0,0 +1,371 @@
+/*
+** Copyright 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <linux/ioctl.h>
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#include "alsa_audio.h"
+
+static const char *elem_iface_name(snd_ctl_elem_iface_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_IFACE_CARD: return "CARD";
+ case SNDRV_CTL_ELEM_IFACE_HWDEP: return "HWDEP";
+ case SNDRV_CTL_ELEM_IFACE_MIXER: return "MIXER";
+ case SNDRV_CTL_ELEM_IFACE_PCM: return "PCM";
+ case SNDRV_CTL_ELEM_IFACE_RAWMIDI: return "MIDI";
+ case SNDRV_CTL_ELEM_IFACE_TIMER: return "TIMER";
+ case SNDRV_CTL_ELEM_IFACE_SEQUENCER: return "SEQ";
+ default: return "???";
+ }
+}
+
+static const char *elem_type_name(snd_ctl_elem_type_t n)
+{
+ switch (n) {
+ case SNDRV_CTL_ELEM_TYPE_NONE: return "NONE";
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT32";
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
+ case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTES";
+ case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
+ default: return "???";
+ }
+}
+
+
+struct mixer_ctl {
+ struct mixer *mixer;
+ struct snd_ctl_elem_info *info;
+ char **ename;
+};
+
+struct mixer {
+ int fd;
+ struct snd_ctl_elem_info *info;
+ struct mixer_ctl *ctl;
+ unsigned count;
+};
+
+void mixer_close(struct mixer *mixer)
+{
+ unsigned n,m;
+
+ if (mixer->fd >= 0)
+ close(mixer->fd);
+
+ if (mixer->ctl) {
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->ctl[n].ename) {
+ unsigned max = mixer->ctl[n].info->value.enumerated.items;
+ for (m = 0; m < max; m++)
+ free(mixer->ctl[n].ename[m]);
+ free(mixer->ctl[n].ename);
+ }
+ }
+ free(mixer->ctl);
+ }
+
+ if (mixer->info)
+ free(mixer->info);
+
+ free(mixer);
+}
+
+struct mixer *mixer_open(void)
+{
+ struct snd_ctl_elem_list elist;
+ struct snd_ctl_elem_info tmp;
+ struct snd_ctl_elem_id *eid = NULL;
+ struct mixer *mixer = NULL;
+ unsigned n, m;
+ int fd;
+
+ fd = open("/dev/snd/controlC0", O_RDWR);
+ if (fd < 0)
+ return 0;
+
+ memset(&elist, 0, sizeof(elist));
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ mixer = calloc(1, sizeof(*mixer));
+ if (!mixer)
+ goto fail;
+
+ mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
+ mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
+ if (!mixer->ctl || !mixer->info)
+ goto fail;
+
+ eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
+ if (!eid)
+ goto fail;
+
+ mixer->count = elist.count;
+ mixer->fd = fd;
+ elist.space = mixer->count;
+ elist.pids = eid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
+ goto fail;
+
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+ ei->id.numid = eid[n].numid;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
+ goto fail;
+ mixer->ctl[n].info = ei;
+ mixer->ctl[n].mixer = mixer;
+ if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
+ if (!enames)
+ goto fail;
+ mixer->ctl[n].ename = enames;
+ for (m = 0; m < ei->value.enumerated.items; m++) {
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id.numid = ei->id.numid;
+ tmp.value.enumerated.item = m;
+ if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
+ goto fail;
+ enames[m] = strdup(tmp.value.enumerated.name);
+ if (!enames[m])
+ goto fail;
+ }
+ }
+ }
+
+ free(eid);
+ return mixer;
+
+fail:
+ if (eid)
+ free(eid);
+ if (mixer)
+ mixer_close(mixer);
+ else if (fd >= 0)
+ close(fd);
+ return 0;
+}
+
+void mixer_dump(struct mixer *mixer)
+{
+ unsigned n, m;
+
+ printf(" id iface dev sub idx num perms type name\n");
+ for (n = 0; n < mixer->count; n++) {
+ struct snd_ctl_elem_info *ei = mixer->info + n;
+
+ printf("%4d %5s %3d %3d %3d %3d %c%c%c%c%c%c%c%c%c %-6s %s",
+ ei->id.numid, elem_iface_name(ei->id.iface),
+ ei->id.device, ei->id.subdevice, ei->id.index,
+ ei->count,
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_READ) ? 'r' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ? 'w' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE) ? 'V' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TIMESTAMP) ? 'T' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) ? 'R' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) ? 'W' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) ? 'C' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) ? 'I' : ' ',
+ (ei->access & SNDRV_CTL_ELEM_ACCESS_LOCK) ? 'L' : ' ',
+ elem_type_name(ei->type),
+ ei->id.name);
+ switch (ei->type) {
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ printf(ei->value.integer.step ?
+ " { %ld-%ld, %ld }\n" : " { %ld-%ld }",
+ ei->value.integer.min,
+ ei->value.integer.max,
+ ei->value.integer.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ printf(ei->value.integer64.step ?
+ " { %lld-%lld, %lld }\n" : " { %lld-%lld }",
+ ei->value.integer64.min,
+ ei->value.integer64.max,
+ ei->value.integer64.step);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: {
+ unsigned m;
+ printf(" { %s=0", mixer->ctl[n].ename[0]);
+ for (m = 1; m < ei->value.enumerated.items; m++)
+ printf(", %s=%d", mixer->ctl[n].ename[m],m);
+ printf(" }");
+ break;
+ }
+ }
+ printf("\n");
+ }
+}
+
+struct mixer_ctl *mixer_get_control(struct mixer *mixer,
+ const char *name, unsigned index)
+{
+ unsigned n;
+ for (n = 0; n < mixer->count; n++) {
+ if (mixer->info[n].id.index == index) {
+ if (!strcmp(name, (char*) mixer->info[n].id.name)) {
+ return mixer->ctl + n;
+ }
+ }
+ }
+ return 0;
+}
+
+struct mixer_ctl *mixer_get_nth_control(struct mixer *mixer, unsigned n)
+{
+ if (n < mixer->count)
+ return mixer->ctl + n;
+ return 0;
+}
+
+void mixer_ctl_print(struct mixer_ctl *ctl)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev))
+ return;
+ printf("%s:", ctl->info->id.name);
+
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %s", ev.value.integer.value[n] ? "ON" : "OFF");
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %ld", ev.value.integer.value[n]);
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+ for (n = 0; n < ctl->info->count; n++)
+ printf(" %lld", ev.value.integer64.value[n]);
+ break;
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+ for (n = 0; n < ctl->info->count; n++) {
+ unsigned v = ev.value.enumerated.item[n];
+ printf(" %d (%s)", v,
+ (v < ctl->info->value.enumerated.items) ? ctl->ename[v] : "???");
+ }
+ break;
+ default:
+ printf(" ???");
+ }
+ printf("\n");
+}
+
+static long scale_int(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long percent;
+ long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min);
+
+ return ei->value.integer.min + (range * percent) / 100LL;
+}
+
+static long long scale_int64(struct snd_ctl_elem_info *ei, unsigned _percent)
+{
+ long long percent;
+ long long range;
+
+ if (_percent > 100)
+ percent = 100;
+ else
+ percent = (long) _percent;
+
+ range = (ei->value.integer.max - ei->value.integer.min) * 100LL;
+
+ return ei->value.integer.min + (range / percent);
+}
+
+int mixer_ctl_set(struct mixer_ctl *ctl, unsigned percent)
+{
+ struct snd_ctl_elem_value ev;
+ unsigned n;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.id.numid = ctl->info->id.numid;
+ switch (ctl->info->type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = !!percent;
+ break;
+ case SNDRV_CTL_ELEM_TYPE_INTEGER: {
+ long value = scale_int(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer.value[n] = value;
+ break;
+ }
+ case SNDRV_CTL_ELEM_TYPE_INTEGER64: {
+ long long value = scale_int64(ctl->info, percent);
+ for (n = 0; n < ctl->info->count; n++)
+ ev.value.integer64.value[n] = value;
+ break;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
+}
+
+int mixer_ctl_select(struct mixer_ctl *ctl, const char *value)
+{
+ unsigned n, max;
+ struct snd_ctl_elem_value ev;
+
+ if (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ max = ctl->info->value.enumerated.items;
+ for (n = 0; n < max; n++) {
+ if (!strcmp(value, ctl->ename[n])) {
+ memset(&ev, 0, sizeof(ev));
+ ev.value.enumerated.item[0] = n;
+ ev.id.numid = ctl->info->id.numid;
+ if (ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev) < 0)
+ return -1;
+ return 0;
+ }
+ }
+
+ errno = EINVAL;
+ return -1;
+}
diff --git a/libaudio/alsa_pcm.c b/libaudio/alsa_pcm.c
new file mode 100644
index 0000000..5673391
--- /dev/null
+++ b/libaudio/alsa_pcm.c
@@ -0,0 +1,405 @@
+/*
+** Copyright 2010, 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 "alsa_pcm"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <cutils/config_utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <linux/ioctl.h>
+
+#include "alsa_audio.h"
+
+#define __force
+#define __bitwise
+#define __user
+#include "asound.h"
+
+#define DEBUG 0
+
+/* alsa parameter manipulation cruft */
+
+#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
+
+static inline int param_is_mask(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
+}
+
+static inline int param_is_interval(int p)
+{
+ return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
+}
+
+static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ }
+}
+
+static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->max = val;
+ }
+}
+
+static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val)
+{
+ if (param_is_interval(n)) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = val;
+ i->max = val;
+ i->integer = 1;
+ }
+}
+
+static void param_init(struct snd_pcm_hw_params *p)
+{
+ int n;
+ memset(p, 0, sizeof(*p));
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = ~0;
+ m->bits[1] = ~0;
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ i->min = 0;
+ i->max = ~0;
+ }
+}
+
+/* debugging gunk */
+
+#if DEBUG
+static const char *param_name[PARAM_MAX+1] = {
+ [SNDRV_PCM_HW_PARAM_ACCESS] = "access",
+ [SNDRV_PCM_HW_PARAM_FORMAT] = "format",
+ [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat",
+
+ [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits",
+ [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits",
+ [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels",
+ [SNDRV_PCM_HW_PARAM_RATE] = "rate",
+ [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
+ [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
+ [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes",
+ [SNDRV_PCM_HW_PARAM_PERIODS] = "periods",
+ [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
+ [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
+ [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes",
+ [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time",
+};
+
+static void param_dump(struct snd_pcm_hw_params *p)
+{
+ int n;
+
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
+ n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
+ struct snd_mask *m = param_to_mask(p, n);
+ LOGV("%s = %08x%08x\n", param_name[n],
+ m->bits[1], m->bits[0]);
+ }
+ for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
+ n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
+ struct snd_interval *i = param_to_interval(p, n);
+ LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
+ param_name[n], i->min, i->max, i->openmin,
+ i->openmax, i->integer, i->empty);
+ }
+ LOGV("info = %08x\n", p->info);
+ LOGV("msbits = %d\n", p->msbits);
+ LOGV("rate = %d/%d\n", p->rate_num, p->rate_den);
+ LOGV("fifo = %d\n", (int) p->fifo_size);
+}
+
+static void info_dump(struct snd_pcm_info *info)
+{
+ LOGV("device = %d\n", info->device);
+ LOGV("subdevice = %d\n", info->subdevice);
+ LOGV("stream = %d\n", info->stream);
+ LOGV("card = %d\n", info->card);
+ LOGV("id = '%s'\n", info->id);
+ LOGV("name = '%s'\n", info->name);
+ LOGV("subname = '%s'\n", info->subname);
+ LOGV("dev_class = %d\n", info->dev_class);
+ LOGV("dev_subclass = %d\n", info->dev_subclass);
+ LOGV("subdevices_count = %d\n", info->subdevices_count);
+ LOGV("subdevices_avail = %d\n", info->subdevices_avail);
+}
+#else
+static void param_dump(struct snd_pcm_hw_params *p) {}
+static void info_dump(struct snd_pcm_info *info) {}
+#endif
+
+#define PCM_ERROR_MAX 128
+
+struct pcm {
+ int fd;
+ unsigned flags;
+ int running:1;
+ int underruns;
+ unsigned buffer_size;
+ char error[PCM_ERROR_MAX];
+};
+
+unsigned pcm_buffer_size(struct pcm *pcm)
+{
+ return pcm->buffer_size;
+}
+
+const char* pcm_error(struct pcm *pcm)
+{
+ return pcm->error;
+}
+
+static int oops(struct pcm *pcm, int e, const char *fmt, ...)
+{
+ va_list ap;
+ int sz;
+
+ va_start(ap, fmt);
+ vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap);
+ va_end(ap);
+ sz = strlen(pcm->error);
+
+ if (errno)
+ snprintf(pcm->error + sz, PCM_ERROR_MAX - sz,
+ ": %s", strerror(e));
+ return -1;
+}
+
+int pcm_write(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+
+ if (pcm->flags & PCM_IN)
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
+ return oops(pcm, errno, "cannot write initial data");
+ pcm->running = 1;
+ return 0;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot write stream data");
+ }
+ return 0;
+ }
+}
+
+int pcm_read(struct pcm *pcm, void *data, unsigned count)
+{
+ struct snd_xferi x;
+
+ if (!(pcm->flags & PCM_IN))
+ return -EINVAL;
+
+ x.buf = data;
+ x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+
+// LOGV("read() %d frames", x.frames);
+ for (;;) {
+ if (!pcm->running) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
+ return oops(pcm, errno, "cannot prepare channel");
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START))
+ return oops(pcm, errno, "cannot start channel");
+ pcm->running = 1;
+ }
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
+ pcm->running = 0;
+ if (errno == EPIPE) {
+ /* we failed to make our window -- try to restart */
+ pcm->underruns++;
+ continue;
+ }
+ return oops(pcm, errno, "cannot read stream data");
+ }
+// LOGV("read() got %d frames", x.frames);
+ return 0;
+ }
+}
+
+static struct pcm bad_pcm = {
+ .fd = -1,
+};
+
+int pcm_close(struct pcm *pcm)
+{
+ if (pcm == &bad_pcm)
+ return 0;
+
+ if (pcm->fd >= 0)
+ close(pcm->fd);
+ pcm->running = 0;
+ pcm->buffer_size = 0;
+ pcm->fd = -1;
+ return 0;
+}
+
+struct pcm *pcm_open(unsigned flags)
+{
+ const char *dname;
+ struct pcm *pcm;
+ struct snd_pcm_info info;
+ struct snd_pcm_hw_params params;
+ struct snd_pcm_sw_params sparams;
+ unsigned period_sz;
+ unsigned period_cnt;
+
+ LOGV("pcm_open(0x%08x)",flags);
+
+ pcm = calloc(1, sizeof(struct pcm));
+ if (!pcm)
+ return &bad_pcm;
+
+ if (flags & PCM_IN) {
+ dname = "/dev/snd/pcmC0D0c";
+ } else {
+ dname = "/dev/snd/pcmC0D0p";
+ }
+
+ LOGV("pcm_open() period sz multiplier %d",
+ ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1);
+ LOGV("pcm_open() period cnt %d",
+ ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN);
+ period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN;
+
+ pcm->flags = flags;
+ pcm->fd = open(dname, O_RDWR);
+ if (pcm->fd < 0) {
+ oops(pcm, errno, "cannot open device '%s'");
+ return pcm;
+ }
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) {
+ oops(pcm, errno, "cannot get info - %s");
+ goto fail;
+ }
+ info_dump(&info);
+
+ LOGV("pcm_open() period_cnt %d period_sz %d channels %d",
+ period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2);
+
+ param_init(&params);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S16_LE);
+ param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_SUBFORMAT_STD);
+ param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ (flags & PCM_MONO) ? 16 : 32);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ (flags & PCM_MONO) ? 1 : 2);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt);
+ param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, 44100);
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) {
+ oops(pcm, errno, "cannot set hw params");
+ goto fail;
+ }
+ param_dump(&params);
+
+ memset(&sparams, 0, sizeof(sparams));
+ sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ sparams.period_step = 1;
+ sparams.avail_min = 1;
+ sparams.start_threshold = period_cnt * period_sz;
+ sparams.stop_threshold = period_cnt * period_sz;
+ sparams.xfer_align = period_sz / 2; /* needed for old kernels */
+ sparams.silence_size = 0;
+ sparams.silence_threshold = 0;
+
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) {
+ oops(pcm, errno, "cannot set sw params");
+ goto fail;
+ }
+
+ pcm->buffer_size = period_cnt * period_sz;
+ pcm->underruns = 0;
+ return pcm;
+
+fail:
+ close(pcm->fd);
+ pcm->fd = -1;
+ return pcm;
+}
+
+int pcm_ready(struct pcm *pcm)
+{
+ return pcm->fd >= 0;
+}
diff --git a/libaudio/amix.c b/libaudio/amix.c
new file mode 100644
index 0000000..d978caa
--- /dev/null
+++ b/libaudio/amix.c
@@ -0,0 +1,78 @@
+/*
+** Copyright 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "alsa_audio.h"
+
+
+struct mixer_ctl *get_ctl(struct mixer *mixer, char *name)
+{
+ char *p;
+ unsigned idx = 0;
+
+ if (isdigit(name[0]))
+ return mixer_get_nth_control(mixer, atoi(name) - 1);
+
+ p = strrchr(name, '#');
+ if (p) {
+ *p++ = 0;
+ idx = atoi(p);
+ }
+
+ return mixer_get_control(mixer, name, idx);
+}
+
+int main(int argc, char **argv)
+{
+ struct mixer *mixer;
+ struct mixer_ctl *ctl;
+ int r;
+
+ mixer = mixer_open();
+ if (!mixer)
+ return -1;
+
+ if (argc == 1) {
+ mixer_dump(mixer);
+ return 0;
+ }
+
+ ctl = get_ctl(mixer, argv[1]);
+ argc -= 2;
+ argv += 2;
+
+ if (!ctl) {
+ fprintf(stderr,"can't find control\n");
+ return -1;
+ }
+
+ if (argc) {
+ if (isdigit(argv[0][0]))
+ r = mixer_ctl_set(ctl, atoi(argv[0]));
+ else
+ r = mixer_ctl_select(ctl, argv[0]);
+ if (r)
+ fprintf(stderr,"oops: %s\n", strerror(errno));
+ } else {
+ mixer_ctl_print(ctl);
+ }
+ return 0;
+}
diff --git a/libaudio/aplay.c b/libaudio/aplay.c
new file mode 100644
index 0000000..0ac0ac0
--- /dev/null
+++ b/libaudio/aplay.c
@@ -0,0 +1,140 @@
+/*
+** Copyright 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "alsa_audio.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+int play_file(unsigned rate, unsigned channels, int fd, unsigned count)
+{
+ struct pcm *pcm;
+ struct mixer *mixer;
+ struct pcm_ctl *ctl = NULL;
+ unsigned bufsize;
+ char *data;
+ unsigned flags = PCM_OUT;
+
+ if (channels == 1)
+ flags |= PCM_MONO;
+ else
+ flags |= PCM_STEREO;
+
+ pcm = pcm_open(flags);
+ if (!pcm_ready(pcm)) {
+ pcm_close(pcm);
+ return -1;
+ }
+
+ mixer = mixer_open();
+ if (mixer)
+ ctl = mixer_get_control(mixer,"Playback Path", 0);
+
+ bufsize = pcm_buffer_size(pcm);
+ data = malloc(bufsize);
+ if (!data) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return -1;
+ }
+
+ while (read(fd, data, bufsize) == bufsize) {
+ if (pcm_write(pcm, data, bufsize))
+ break;
+
+ /* HACK: remove */
+ if (ctl) {
+ //mixer_ctl_select(ctl, "SPK");
+ ctl = 0;
+ }
+ }
+ pcm_close(pcm);
+ return 0;
+}
+
+int play_wav(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "aplay: cannot open '%s'\n", fn);
+ return -1;
+ }
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "aplay: cannot read header\n");
+ return -1;
+ }
+ fprintf(stderr,"aplay: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+ if ((hdr.riff_id != ID_RIFF) ||
+ (hdr.riff_fmt != ID_WAVE) ||
+ (hdr.fmt_id != ID_FMT)) {
+ fprintf(stderr, "aplay: '%s' is not a riff/wave file\n", fn);
+ return -1;
+ }
+ if ((hdr.audio_format != FORMAT_PCM) ||
+ (hdr.fmt_sz != 16)) {
+ fprintf(stderr, "aplay: '%s' is not pcm format\n", fn);
+ return -1;
+ }
+ if (hdr.bits_per_sample != 16) {
+ fprintf(stderr, "aplay: '%s' is not 16bit per sample\n", fn);
+ return -1;
+ }
+
+ return play_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: aplay <file>\n");
+ return -1;
+ }
+
+ return play_wav(argv[1]);
+}
+
diff --git a/libaudio/arec.c b/libaudio/arec.c
new file mode 100644
index 0000000..b1e9eda
--- /dev/null
+++ b/libaudio/arec.c
@@ -0,0 +1,128 @@
+/*
+** Copyright 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "alsa_audio.h"
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+int record_file(unsigned rate, unsigned channels, int fd, unsigned count)
+{
+ struct pcm *pcm;
+ unsigned avail, xfer, bufsize;
+ char *data, *next;
+ int r;
+
+ pcm = pcm_open(PCM_IN|PCM_MONO);
+ if (!pcm_ready(pcm)) {
+ pcm_close(pcm);
+ goto fail;
+ }
+
+ bufsize = pcm_buffer_size(pcm);
+
+ data = malloc(bufsize);
+ if (!data) {
+ fprintf(stderr,"could not allocate %d bytes\n", count);
+ return -1;
+ }
+
+ while (!pcm_read(pcm, data, bufsize)) {
+ if (write(fd, data, bufsize) != bufsize) {
+ fprintf(stderr,"could not write %d bytes\n", bufsize);
+ return -1;
+ }
+ }
+
+ close(fd);
+ pcm_close(pcm);
+ return 0;
+
+fail:
+ fprintf(stderr,"pcm error: %s\n", pcm_error(pcm));
+ return -1;
+}
+
+int rec_wav(const char *fn)
+{
+ struct wav_header hdr;
+ unsigned rate, channels;
+ int fd;
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ if (fd < 0) {
+ fprintf(stderr, "arec: cannot open '%s'\n", fn);
+ return -1;
+ }
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.fmt_sz = 16;
+ hdr.bits_per_sample = 16;
+ hdr.num_channels = 1;
+ hdr.data_sz = 0;
+ hdr.sample_rate = 44100;
+
+ if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ fprintf(stderr, "arec: cannot write header\n");
+ return -1;
+ }
+ fprintf(stderr,"arec: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+
+
+ return record_file(hdr.sample_rate, hdr.num_channels, fd, hdr.data_sz);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr,"usage: arec <file>\n");
+ return -1;
+ }
+
+ return rec_wav(argv[1]);
+}
+
diff --git a/libaudio/asound.h b/libaudio/asound.h
new file mode 100644
index 0000000..6a17f29
--- /dev/null
+++ b/libaudio/asound.h
@@ -0,0 +1,814 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef __SOUND_ASOUND_H
+#define __SOUND_ASOUND_H
+
+#include <linux/types.h>
+
+#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
+#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
+#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
+#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
+#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
+
+struct snd_aes_iec958 {
+ unsigned char status[24];
+ unsigned char subcode[147];
+ unsigned char pad;
+ unsigned char dig_subframe[4];
+};
+
+#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
+enum {
+ SNDRV_HWDEP_IFACE_OPL2 = 0,
+ SNDRV_HWDEP_IFACE_OPL3,
+ SNDRV_HWDEP_IFACE_OPL4,
+ SNDRV_HWDEP_IFACE_SB16CSP,
+ SNDRV_HWDEP_IFACE_EMU10K1,
+ SNDRV_HWDEP_IFACE_YSS225,
+ SNDRV_HWDEP_IFACE_ICS2115,
+ SNDRV_HWDEP_IFACE_SSCAPE,
+ SNDRV_HWDEP_IFACE_VX,
+ SNDRV_HWDEP_IFACE_MIXART,
+ SNDRV_HWDEP_IFACE_USX2Y,
+ SNDRV_HWDEP_IFACE_EMUX_WAVETABLE,
+ SNDRV_HWDEP_IFACE_BLUETOOTH,
+ SNDRV_HWDEP_IFACE_USX2Y_PCM,
+ SNDRV_HWDEP_IFACE_PCXHR,
+ SNDRV_HWDEP_IFACE_SB_RC,
+ SNDRV_HWDEP_IFACE_HDA,
+ SNDRV_HWDEP_IFACE_USB_STREAM,
+
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
+};
+
+struct snd_hwdep_info {
+ unsigned int device;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ int iface;
+ unsigned char reserved[64];
+};
+
+struct snd_hwdep_dsp_status {
+ unsigned int version;
+ unsigned char id[32];
+ unsigned int num_dsps;
+ unsigned int dsp_loaded;
+ unsigned int chip_ready;
+ unsigned char reserved[16];
+};
+
+struct snd_hwdep_dsp_image {
+ unsigned int index;
+ unsigned char name[64];
+ unsigned char __user *image;
+ size_t length;
+ unsigned long driver_data;
+};
+
+#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
+#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
+#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
+#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
+
+#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
+
+typedef unsigned long snd_pcm_uframes_t;
+typedef signed long snd_pcm_sframes_t;
+
+enum {
+ SNDRV_PCM_CLASS_GENERIC = 0,
+ SNDRV_PCM_CLASS_MULTI,
+ SNDRV_PCM_CLASS_MODEM,
+ SNDRV_PCM_CLASS_DIGITIZER,
+
+ SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
+};
+
+enum {
+ SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0,
+ SNDRV_PCM_SUBCLASS_MULTI_MIX,
+
+ SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
+};
+
+enum {
+ SNDRV_PCM_STREAM_PLAYBACK = 0,
+ SNDRV_PCM_STREAM_CAPTURE,
+ SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
+};
+
+typedef int __bitwise snd_pcm_access_t;
+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0)
+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1)
+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2)
+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3)
+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4)
+#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
+
+typedef int __bitwise snd_pcm_format_t;
+#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
+#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
+#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
+#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
+#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
+#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
+#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6)
+#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7)
+#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8)
+#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9)
+#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
+#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
+#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
+#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
+#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14)
+#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15)
+#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16)
+#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18)
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19)
+#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
+#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
+#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
+#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
+#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
+#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
+#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32)
+#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33)
+#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34)
+#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35)
+#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36)
+#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37)
+#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38)
+#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39)
+#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40)
+#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41)
+#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42)
+#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43)
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE
+
+#ifdef SNDRV_LITTLE_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
+#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE
+#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE
+#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE
+#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE
+#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE
+#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
+#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
+#endif
+
+typedef int __bitwise snd_pcm_subformat_t;
+#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
+#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD
+
+#define SNDRV_PCM_INFO_MMAP 0x00000001
+#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002
+#define SNDRV_PCM_INFO_DOUBLE 0x00000004
+#define SNDRV_PCM_INFO_BATCH 0x00000010
+#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100
+#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200
+#define SNDRV_PCM_INFO_COMPLEX 0x00000400
+#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000
+#define SNDRV_PCM_INFO_OVERRANGE 0x00020000
+#define SNDRV_PCM_INFO_RESUME 0x00040000
+#define SNDRV_PCM_INFO_PAUSE 0x00080000
+#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000
+#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000
+#define SNDRV_PCM_INFO_SYNC_START 0x00400000
+#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000
+
+typedef int __bitwise snd_pcm_state_t;
+#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0)
+#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1)
+#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2)
+#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3)
+#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4)
+#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5)
+#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6)
+#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7)
+#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8)
+#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
+
+enum {
+ SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
+ SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
+ SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
+};
+
+union snd_pcm_sync_id {
+ unsigned char id[16];
+ unsigned short id16[8];
+ unsigned int id32[4];
+};
+
+struct snd_pcm_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ int dev_class;
+ int dev_subclass;
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ union snd_pcm_sync_id sync;
+ unsigned char reserved[64];
+};
+
+typedef int snd_pcm_hw_param_t;
+#define SNDRV_PCM_HW_PARAM_ACCESS 0
+#define SNDRV_PCM_HW_PARAM_FORMAT 1
+#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2
+#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS
+#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT
+
+#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8
+#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9
+#define SNDRV_PCM_HW_PARAM_CHANNELS 10
+#define SNDRV_PCM_HW_PARAM_RATE 11
+#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12
+#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13
+#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14
+#define SNDRV_PCM_HW_PARAM_PERIODS 15
+#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16
+#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17
+#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18
+#define SNDRV_PCM_HW_PARAM_TICK_TIME 19
+#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS
+#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
+
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)
+
+struct snd_interval {
+ unsigned int min, max;
+ unsigned int openmin:1,
+ openmax:1,
+ integer:1,
+ empty:1;
+};
+
+#define SNDRV_MASK_MAX 256
+
+struct snd_mask {
+ __u32 bits[(SNDRV_MASK_MAX+31)/32];
+};
+
+struct snd_pcm_hw_params {
+ unsigned int flags;
+ struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+ struct snd_mask mres[5];
+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
+ SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+ struct snd_interval ires[9];
+ unsigned int rmask;
+ unsigned int cmask;
+ unsigned int info;
+ unsigned int msbits;
+ unsigned int rate_num;
+ unsigned int rate_den;
+ snd_pcm_uframes_t fifo_size;
+ unsigned char reserved[64];
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_NONE = 0,
+ SNDRV_PCM_TSTAMP_ENABLE,
+ SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
+};
+
+struct snd_pcm_sw_params {
+ int tstamp_mode;
+ unsigned int period_step;
+ unsigned int sleep_min;
+ snd_pcm_uframes_t avail_min;
+ snd_pcm_uframes_t xfer_align;
+ snd_pcm_uframes_t start_threshold;
+ snd_pcm_uframes_t stop_threshold;
+ snd_pcm_uframes_t silence_threshold;
+ snd_pcm_uframes_t silence_size;
+ snd_pcm_uframes_t boundary;
+ unsigned char reserved[64];
+};
+
+struct snd_pcm_channel_info {
+ unsigned int channel;
+ __kernel_off_t offset;
+ unsigned int first;
+ unsigned int step;
+};
+
+struct snd_pcm_status {
+ snd_pcm_state_t state;
+ struct timespec trigger_tstamp;
+ struct timespec tstamp;
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t hw_ptr;
+ snd_pcm_sframes_t delay;
+ snd_pcm_uframes_t avail;
+ snd_pcm_uframes_t avail_max;
+ snd_pcm_uframes_t overrange;
+ snd_pcm_state_t suspended_state;
+ unsigned char reserved[60];
+};
+
+struct snd_pcm_mmap_status {
+ snd_pcm_state_t state;
+ int pad1;
+ snd_pcm_uframes_t hw_ptr;
+ struct timespec tstamp;
+ snd_pcm_state_t suspended_state;
+};
+
+struct snd_pcm_mmap_control {
+ snd_pcm_uframes_t appl_ptr;
+ snd_pcm_uframes_t avail_min;
+};
+
+#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0)
+#define SNDRV_PCM_SYNC_PTR_APPL (1<<1)
+#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2)
+
+struct snd_pcm_sync_ptr {
+ unsigned int flags;
+ union {
+ struct snd_pcm_mmap_status status;
+ unsigned char reserved[64];
+ } s;
+ union {
+ struct snd_pcm_mmap_control control;
+ unsigned char reserved[64];
+ } c;
+};
+
+struct snd_xferi {
+ snd_pcm_sframes_t result;
+ void __user *buf;
+ snd_pcm_uframes_t frames;
+};
+
+struct snd_xfern {
+ snd_pcm_sframes_t result;
+ void __user * __user *bufs;
+ snd_pcm_uframes_t frames;
+};
+
+enum {
+ SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,
+ SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+ SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+};
+
+#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
+#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
+#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
+#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
+#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
+#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
+#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
+#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
+#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
+#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
+#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
+#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
+#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
+#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
+#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
+#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
+#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
+#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
+#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
+#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
+#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
+#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
+#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
+#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
+
+#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0)
+
+enum {
+ SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
+};
+
+#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
+#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
+#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
+
+struct snd_rawmidi_info {
+ unsigned int device;
+ unsigned int subdevice;
+ int stream;
+ int card;
+ unsigned int flags;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned char subname[32];
+ unsigned int subdevices_count;
+ unsigned int subdevices_avail;
+ unsigned char reserved[64];
+};
+
+struct snd_rawmidi_params {
+ int stream;
+ size_t buffer_size;
+ size_t avail_min;
+ unsigned int no_active_sensing: 1;
+ unsigned char reserved[16];
+};
+
+struct snd_rawmidi_status {
+ int stream;
+ struct timespec tstamp;
+ size_t avail;
+ size_t xruns;
+ unsigned char reserved[16];
+};
+
+#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
+#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
+#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
+#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
+#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
+#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
+
+#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+enum {
+ SNDRV_TIMER_CLASS_NONE = -1,
+ SNDRV_TIMER_CLASS_SLAVE = 0,
+ SNDRV_TIMER_CLASS_GLOBAL,
+ SNDRV_TIMER_CLASS_CARD,
+ SNDRV_TIMER_CLASS_PCM,
+ SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
+};
+
+enum {
+ SNDRV_TIMER_SCLASS_NONE = 0,
+ SNDRV_TIMER_SCLASS_APPLICATION,
+ SNDRV_TIMER_SCLASS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+ SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+};
+
+#define SNDRV_TIMER_GLOBAL_SYSTEM 0
+#define SNDRV_TIMER_GLOBAL_RTC 1
+#define SNDRV_TIMER_GLOBAL_HPET 2
+#define SNDRV_TIMER_GLOBAL_HRTIMER 3
+
+#define SNDRV_TIMER_FLG_SLAVE (1<<0)
+
+struct snd_timer_id {
+ int dev_class;
+ int dev_sclass;
+ int card;
+ int device;
+ int subdevice;
+};
+
+struct snd_timer_ginfo {
+ struct snd_timer_id tid;
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned long resolution_min;
+ unsigned long resolution_max;
+ unsigned int clients;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gparams {
+ struct snd_timer_id tid;
+ unsigned long period_num;
+ unsigned long period_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_gstatus {
+ struct snd_timer_id tid;
+ unsigned long resolution;
+ unsigned long resolution_num;
+ unsigned long resolution_den;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_select {
+ struct snd_timer_id id;
+ unsigned char reserved[32];
+};
+
+struct snd_timer_info {
+ unsigned int flags;
+ int card;
+ unsigned char id[64];
+ unsigned char name[80];
+ unsigned long reserved0;
+ unsigned long resolution;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_PSFLG_AUTO (1<<0)
+#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1)
+#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2)
+
+struct snd_timer_params {
+ unsigned int flags;
+ unsigned int ticks;
+ unsigned int queue_size;
+ unsigned int reserved0;
+ unsigned int filter;
+ unsigned char reserved[60];
+};
+
+struct snd_timer_status {
+ struct timespec tstamp;
+ unsigned int resolution;
+ unsigned int lost;
+ unsigned int overrun;
+ unsigned int queue;
+ unsigned char reserved[64];
+};
+
+#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
+#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
+#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
+#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
+#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
+#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
+#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
+#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
+#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
+#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
+
+#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
+#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
+#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
+#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
+
+struct snd_timer_read {
+ unsigned int resolution;
+ unsigned int ticks;
+};
+
+enum {
+ SNDRV_TIMER_EVENT_RESOLUTION = 0,
+ SNDRV_TIMER_EVENT_TICK,
+ SNDRV_TIMER_EVENT_START,
+ SNDRV_TIMER_EVENT_STOP,
+ SNDRV_TIMER_EVENT_CONTINUE,
+ SNDRV_TIMER_EVENT_PAUSE,
+ SNDRV_TIMER_EVENT_EARLY,
+ SNDRV_TIMER_EVENT_SUSPEND,
+ SNDRV_TIMER_EVENT_RESUME,
+
+ SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
+ SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
+ SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
+ SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+ SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+ SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
+};
+
+struct snd_timer_tread {
+ int event;
+ struct timespec tstamp;
+ unsigned int val;
+};
+
+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
+
+struct snd_ctl_card_info {
+ int card;
+ int pad;
+ unsigned char id[16];
+ unsigned char driver[16];
+ unsigned char name[32];
+ unsigned char longname[80];
+ unsigned char reserved_[16];
+ unsigned char mixername[80];
+ unsigned char components[128];
+};
+
+typedef int __bitwise snd_ctl_elem_type_t;
+#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0)
+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2)
+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3)
+#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4)
+#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5)
+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6)
+#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
+
+typedef int __bitwise snd_ctl_elem_iface_t;
+#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0)
+#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1)
+#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2)
+#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3)
+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4)
+#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5)
+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6)
+#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
+
+#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
+#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
+#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2)
+#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6)
+#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8)
+#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9)
+#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28)
+#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29)
+
+#define SNDRV_CTL_POWER_D0 0x0000
+#define SNDRV_CTL_POWER_D1 0x0100
+#define SNDRV_CTL_POWER_D2 0x0200
+#define SNDRV_CTL_POWER_D3 0x0300
+#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000)
+#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001)
+
+struct snd_ctl_elem_id {
+ unsigned int numid;
+ snd_ctl_elem_iface_t iface;
+ unsigned int device;
+ unsigned int subdevice;
+ unsigned char name[44];
+ unsigned int index;
+};
+
+struct snd_ctl_elem_list {
+ unsigned int offset;
+ unsigned int space;
+ unsigned int used;
+ unsigned int count;
+ struct snd_ctl_elem_id __user *pids;
+ unsigned char reserved[50];
+};
+
+struct snd_ctl_elem_info {
+ struct snd_ctl_elem_id id;
+ snd_ctl_elem_type_t type;
+ unsigned int access;
+ unsigned int count;
+ __kernel_pid_t owner;
+ union {
+ struct {
+ long min;
+ long max;
+ long step;
+ } integer;
+ struct {
+ long long min;
+ long long max;
+ long long step;
+ } integer64;
+ struct {
+ unsigned int items;
+ unsigned int item;
+ char name[64];
+ } enumerated;
+ unsigned char reserved[128];
+ } value;
+ union {
+ unsigned short d[4];
+ unsigned short *d_ptr;
+ } dimen;
+ unsigned char reserved[64-4*sizeof(unsigned short)];
+};
+
+struct snd_ctl_elem_value {
+ struct snd_ctl_elem_id id;
+ unsigned int indirect: 1;
+ union {
+ union {
+ long value[128];
+ long *value_ptr;
+ } integer;
+ union {
+ long long value[64];
+ long long *value_ptr;
+ } integer64;
+ union {
+ unsigned int item[128];
+ unsigned int *item_ptr;
+ } enumerated;
+ union {
+ unsigned char data[512];
+ unsigned char *data_ptr;
+ } bytes;
+ struct snd_aes_iec958 iec958;
+ } value;
+ struct timespec tstamp;
+ unsigned char reserved[128-sizeof(struct timespec)];
+};
+
+struct snd_ctl_tlv {
+ unsigned int numid;
+ unsigned int length;
+ unsigned int tlv[0];
+};
+
+#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
+#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
+#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
+#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
+#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
+#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
+#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
+#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
+#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
+#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
+#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
+#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
+#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
+#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
+#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
+
+enum sndrv_ctl_event_type {
+ SNDRV_CTL_EVENT_ELEM = 0,
+ SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
+};
+
+#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0)
+#define SNDRV_CTL_EVENT_MASK_INFO (1<<1)
+#define SNDRV_CTL_EVENT_MASK_ADD (1<<2)
+#define SNDRV_CTL_EVENT_MASK_TLV (1<<3)
+#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U)
+
+struct snd_ctl_event {
+ int type;
+ union {
+ struct {
+ unsigned int mask;
+ struct snd_ctl_elem_id id;
+ } elem;
+ unsigned char data8[60];
+ } data;
+};
+
+#define SNDRV_CTL_NAME_NONE ""
+#define SNDRV_CTL_NAME_PLAYBACK "Playback "
+#define SNDRV_CTL_NAME_CAPTURE "Capture "
+
+#define SNDRV_CTL_NAME_IEC958_NONE ""
+#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch"
+#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume"
+#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default"
+#define SNDRV_CTL_NAME_IEC958_MASK "Mask"
+#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask"
+#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask"
+#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
+#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
+
+#endif
+
diff --git a/libaudio/secril-client.h b/libaudio/secril-client.h
new file mode 100644
index 0000000..7bbaa03
--- /dev/null
+++ b/libaudio/secril-client.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 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 __SECRIL_CLIENT_H__
+#define __SECRIL_CLIENT_H__
+
+#include <sys/types.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RilClient {
+ void *prv;
+};
+
+typedef struct RilClient * HRilClient;
+
+
+//---------------------------------------------------------------------------
+// Defines
+//---------------------------------------------------------------------------
+#define RIL_CLIENT_ERR_SUCCESS 0
+#define RIL_CLIENT_ERR_AGAIN 1
+#define RIL_CLIENT_ERR_INIT 2 // Client is not initialized
+#define RIL_CLIENT_ERR_INVAL 3 // Invalid value
+#define RIL_CLIENT_ERR_CONNECT 4 // Connection error
+#define RIL_CLIENT_ERR_IO 5 // IO error
+#define RIL_CLIENT_ERR_RESOURCE 6 // Resource not available
+#define RIL_CLIENT_ERR_UNKNOWN 7
+
+
+//---------------------------------------------------------------------------
+// Type definitions
+//---------------------------------------------------------------------------
+
+typedef int (*RilOnComplete)(HRilClient handle, const void *data, size_t datalen);
+
+typedef int (*RilOnUnsolicited)(HRilClient handle, const void *data, size_t datalen);
+
+typedef int (*RilOnError)(void *data, int error);
+
+
+//---------------------------------------------------------------------------
+// Client APIs
+//---------------------------------------------------------------------------
+
+/**
+ * Open RILD multi-client.
+ * Return is client handle, NULL on error.
+ */
+HRilClient OpenClient_RILD(void);
+
+/**
+ * Stop RILD multi-client. If client socket was connected,
+ * it will be disconnected.
+ */
+int CloseClient_RILD(HRilClient client);
+
+/**
+ * Connect to RIL deamon. One client task starts.
+ * Return is 0 or error code.
+ */
+int Connect_RILD(HRilClient client);
+
+/**
+ * check whether RILD is connected
+ * Returns 0 or 1
+ */
+int isConnected_RILD(HRilClient client);
+
+/**
+ * Disconnect connection to RIL deamon(socket close).
+ * Return is 0 or error code.
+ */
+int Disconnect_RILD(HRilClient client);
+
+/**
+ * Register unsolicited response handler. If handler is NULL,
+ * the handler for the request ID is unregistered.
+ * The response handler is invoked in the client task context.
+ * Return is 0 or error code.
+ */
+int RegisterUnsolicitedHandler(HRilClient client, uint32_t id, RilOnUnsolicited handler);
+
+/**
+ * Register solicited response handler. If handler is NULL,
+ * the handler for the ID is unregistered.
+ * The response handler is invoked in the client task context.
+ * Return is 0 or error code.
+ */
+int RegisterRequestCompleteHandler(HRilClient client, uint32_t id, RilOnComplete handler);
+
+/**
+ * Register error callback. If handler is NULL,
+ * the callback is unregistered.
+ * The response handler is invoked in the client task context.
+ * Return is 0 or error code.
+ */
+int RegisterErrorCallback(HRilClient client, RilOnError cb, void *data);
+
+/**
+ * Invoke OEM request. Request ID is RIL_REQUEST_OEM_HOOK_RAW.
+ * Return is 0 or error code. For RIL_CLIENT_ERR_AGAIN caller should retry.
+ */
+int InvokeOemRequestHookRaw(HRilClient client, char *data, size_t len);
+
+/**
+ * Sound device types.
+ */
+typedef enum _SoundType {
+ SOUND_TYPE_VOICE,
+ SOUND_TYPE_SPEAKER,
+ SOUND_TYPE_HEADSET,
+ SOUND_TYPE_BTVOICE
+} SoundType;
+
+/**
+ * External sound device path.
+ */
+typedef enum _AudioPath {
+ SOUND_AUDIO_PATH_HANDSET,
+ SOUND_AUDIO_PATH_HEADSET,
+ SOUND_AUDIO_PATH_SPEAKER,
+ SOUND_AUDIO_PATH_BLUETOOTH,
+ SOUND_AUDIO_PATH_BLUETOOTH_NO_NR,
+ SOUND_AUDIO_PATH_HEADPHONE
+} AudioPath;
+
+/**
+ * Clock adjustment parameters.
+ */
+typedef enum _SoundClockCondition {
+ SOUND_CLOCK_STOP,
+ SOUND_CLOCK_START
+} SoundClockCondition;
+
+/**
+ * Set in-call volume.
+ */
+int SetCallVolume(HRilClient client, SoundType type, int vol_level);
+
+/**
+ * Set external sound device path for noise reduction.
+ */
+int SetCallAudioPath(HRilClient client, AudioPath path);
+
+/**
+ * Set modem clock to master or slave.
+ */
+int SetCallClockSync(HRilClient client, SoundClockCondition condition);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // __SECRIL_CLIENT_H__
+
+// end of file
+
diff --git a/system.prop b/system.prop
new file mode 100644
index 0000000..91c3bcf
--- /dev/null
+++ b/system.prop
@@ -0,0 +1,6 @@
+#
+# system.prop
+#
+
+rild.libpath=/system/lib/libreference-ril.so
+rild.libargs=-d /dev/ttyUSB2
diff --git a/vendorsetup.sh b/vendorsetup.sh
new file mode 100755
index 0000000..3287f76
--- /dev/null
+++ b/vendorsetup.sh
@@ -0,0 +1 @@
+add_lunch_combo pandaboard-eng
diff --git a/vold.fstab b/vold.fstab
new file mode 100644
index 0000000..10fe0c4
--- /dev/null
+++ b/vold.fstab
@@ -0,0 +1,15 @@
+## Vold 2.0 Generic fstab
+## - San Mehat (san@android.com)
+##
+
+#######################
+## Regular device mount
+##
+## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
+## label - Label for the volume
+## mount_point - Where the volume will be mounted
+## part - Partition # (1 based), or 'auto' for first usable partition.
+## <sysfs_path> - List of sysfs paths to source devices
+######################
+
+dev_mount sdcard /mnt/sdcard 6 /devices/platform/omap/omap_hsmmc.0/mmc_host/mmc0