diff options
author | Nishanth Menon | 2014-11-11 17:28:38 -0600 |
---|---|---|
committer | Nishanth Menon | 2014-11-11 17:28:38 -0600 |
commit | 88fc70c0850794fb0bce52f63dfcc0d8f3d5062e (patch) | |
tree | bd2acd9a43827c481dfcca8049f0206c2f7979ef | |
download | device-ti-x15-88fc70c0850794fb0bce52f63dfcc0d8f3d5062e.tar.gz device-ti-x15-88fc70c0850794fb0bce52f63dfcc0d8f3d5062e.tar.xz device-ti-x15-88fc70c0850794fb0bce52f63dfcc0d8f3d5062e.zip |
initial baseline from TI's code
Signed-off-by: Nishanth Menon <nm@ti.com>
38 files changed, 6346 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..37d2bcb --- /dev/null +++ b/Android.mk | |||
@@ -0,0 +1,55 @@ | |||
1 | # | ||
2 | # Copyright (C) 2011 The Android Open-Source Project | ||
3 | # | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | # you may not use this file except in compliance with the License. | ||
6 | # You may obtain a copy of the License at | ||
7 | # | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | # | ||
10 | # Unless required by applicable law or agreed to in writing, software | ||
11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | # See the License for the specific language governing permissions and | ||
14 | # limitations under the License. | ||
15 | # | ||
16 | |||
17 | # WARNING: Everything listed here will be built on ALL platforms, | ||
18 | # including x86, the emulator, and the SDK. Modules must be uniquely | ||
19 | # named (liblights.panda), and must build everywhere, or limit themselves | ||
20 | # to only building on ARM if they include assembly. Individual makefiles | ||
21 | # are responsible for having their own logic, for fine-grained control. | ||
22 | |||
23 | LOCAL_PATH := $(call my-dir) | ||
24 | |||
25 | # protect makefile from other boards | ||
26 | # if some modules are built directly from this directory (not subdirectories), | ||
27 | # their rules should be written here. | ||
28 | ifeq ($(TARGET_DEVICE),jacinto6evm) | ||
29 | include $(CLEAR_VARS) | ||
30 | |||
31 | LOCAL_MODULE := jacinto6evm_hdcp_keys | ||
32 | LOCAL_MODULE_TAGS := optional | ||
33 | LOCAL_MODULE_CLASS := FAKE | ||
34 | LOCAL_MODULE_SUFFIX := -timestamp | ||
35 | |||
36 | include $(BUILD_SYSTEM)/base_rules.mk | ||
37 | |||
38 | $(LOCAL_BUILT_MODULE): HDCP_KEYS_FILE := /factory/hdcp.keys | ||
39 | $(LOCAL_BUILT_MODULE): SYMLINK := $(TARGET_OUT_VENDOR)/firmware/hdcp.keys | ||
40 | $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/Android.mk | ||
41 | $(LOCAL_BUILT_MODULE): | ||
42 | $(hide) echo "Symlink: $(SYMLINK) -> $(HDCP_KEYS_FILE)" | ||
43 | $(hide) mkdir -p $(dir $@) | ||
44 | $(hide) mkdir -p $(dir $(SYMLINK)) | ||
45 | $(hide) rm -rf $@ | ||
46 | $(hide) rm -rf $(SYMLINK) | ||
47 | $(hide) ln -sf $(HDCP_KEYS_FILE) $(SYMLINK) | ||
48 | $(hide) touch $@ | ||
49 | |||
50 | # if some modules are built directly from this directory (not subdirectories), | ||
51 | # their rules should be written here. | ||
52 | |||
53 | include $(call all-makefiles-under,$(LOCAL_PATH)) | ||
54 | |||
55 | endif | ||
diff --git a/AndroidProducts.mk b/AndroidProducts.mk new file mode 100644 index 0000000..26b97c7 --- /dev/null +++ b/AndroidProducts.mk | |||
@@ -0,0 +1,17 @@ | |||
1 | # | ||
2 | # Copyright (C) 2011 The Android Open-Source Project | ||
3 | # | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | # you may not use this file except in compliance with the License. | ||
6 | # You may obtain a copy of the License at | ||
7 | # | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | # | ||
10 | # Unless required by applicable law or agreed to in writing, software | ||
11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | # See the License for the specific language governing permissions and | ||
14 | # limitations under the License. | ||
15 | # | ||
16 | |||
17 | PRODUCT_MAKEFILES := $(LOCAL_DIR)/full_jacinto6evm.mk | ||
diff --git a/Atmel_maXTouch_Touchscreen.idc b/Atmel_maXTouch_Touchscreen.idc new file mode 100644 index 0000000..2d4c26a --- /dev/null +++ b/Atmel_maXTouch_Touchscreen.idc | |||
@@ -0,0 +1,25 @@ | |||
1 | # Copyright (C) 2010 The Android Open Source Project | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | # | ||
16 | # Input Device Configuration File for the Atmel Maxtouch touch screen. | ||
17 | # | ||
18 | # These calibration values are derived from empirical measurements | ||
19 | # and may not be appropriate for use with other touch screens. | ||
20 | # Refer to the input device configuration documentation for more details. | ||
21 | # | ||
22 | |||
23 | # Basic Parameters | ||
24 | touch.deviceType = touchScreen | ||
25 | touch.orientationAware = 1 | ||
diff --git a/BoardConfig.mk b/BoardConfig.mk new file mode 100644 index 0000000..ffc3bc0 --- /dev/null +++ b/BoardConfig.mk | |||
@@ -0,0 +1,80 @@ | |||
1 | # | ||
2 | # Copyright (C) 2011 The Android Open-Source Project | ||
3 | # | ||
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | # you may not use this file except in compliance with the License. | ||
6 | # You may obtain a copy of the License at | ||
7 | # | ||
8 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | # | ||
10 | # Unless required by applicable law or agreed to in writing, software | ||
11 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | # See the License for the specific language governing permissions and | ||
14 | # limitations under the License. | ||
15 | # | ||
16 | |||
17 | # These two variables are set first, so they can be overridden | ||
18 | # by BoardConfigVendor.mk | ||
19 | BOARD_USES_GENERIC_AUDIO := true | ||
20 | #USE_CAMERA_STUB := true | ||
21 | #OMAP_ENHANCEMENT := true | ||
22 | |||
23 | ifeq ($(OMAP_ENHANCEMENT),true) | ||
24 | COMMON_GLOBAL_CFLAGS += -DOMAP_ENHANCEMENT | ||
25 | # Multi-zone audio (requires ro.com.ti.omap_multizone_audio, see device.mk) | ||
26 | #OMAP_MULTIZONE_AUDIO := true | ||
27 | endif | ||
28 | |||
29 | TARGET_CPU_ABI := armeabi-v7a | ||
30 | TARGET_CPU_ABI2 := armeabi | ||
31 | TARGET_CPU_SMP := true | ||
32 | TARGET_ARCH := arm | ||
33 | TARGET_ARCH_VARIANT := armv7-a-neon | ||
34 | TARGET_CPU_VARIANT := cortex-a15 | ||
35 | |||
36 | BOARD_HAVE_BLUETOOTH := true | ||
37 | BOARD_HAVE_BLUETOOTH_TI := true | ||
38 | BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR := device/ti/jacinto6evm/bluetooth | ||
39 | TARGET_NO_BOOTLOADER := true | ||
40 | |||
41 | BOARD_KERNEL_BASE := 0x80000000 | ||
42 | #BOARD_KERNEL_CMDLINE := console=ttyO2,115200n8 mem=1024M androidboot.console=ttyO2 androidboot.hardware=jacinto6evmboard vram=20M omapfb.vram=0:16M | ||
43 | BOARD_MKBOOTIMG_ARGS := --ramdisk_offset 0x01f00000 | ||
44 | |||
45 | TARGET_NO_RADIOIMAGE := true | ||
46 | TARGET_BOARD_PLATFORM := jacinto6 | ||
47 | TARGET_BOOTLOADER_BOARD_NAME := jacinto6evm | ||
48 | |||
49 | BOARD_EGL_CFG := device/ti/jacinto6evm/egl.cfg | ||
50 | |||
51 | USE_OPENGL_RENDERER := true | ||
52 | |||
53 | TARGET_USERIMAGES_USE_EXT4 := true | ||
54 | BOARD_SYSTEMIMAGE_PARTITION_SIZE := 805306368 | ||
55 | BOARD_USERDATAIMAGE_PARTITION_SIZE := 2147483648 | ||
56 | BOARD_FLASH_BLOCK_SIZE := 4096 | ||
57 | |||
58 | TARGET_RECOVERY_FSTAB = device/ti/jacinto6evm/fstab.jacinto6evmboard | ||
59 | TARGET_RECOVERY_PIXEL_FORMAT := "RGB565" | ||
60 | TARGET_RELEASETOOLS_EXTENSIONS := device/ti/jacinto6evm | ||
61 | |||
62 | # Connectivity - Wi-Fi | ||
63 | #USES_TI_MAC80211 := true | ||
64 | ifeq ($(USES_TI_MAC80211),true) | ||
65 | BOARD_WPA_SUPPLICANT_DRIVER := NL80211 | ||
66 | WPA_SUPPLICANT_VERSION := VER_0_8_X_TI | ||
67 | BOARD_HOSTAPD_DRIVER := NL80211 | ||
68 | BOARD_WLAN_DEVICE := wl12xx_mac80211 | ||
69 | BOARD_SOFTAP_DEVICE := wl12xx_mac80211 | ||
70 | COMMON_GLOBAL_CFLAGS += -DUSES_TI_MAC80211 | ||
71 | endif | ||
72 | |||
73 | ifeq ($(OMAP_MULTIZONE_AUDIO),true) | ||
74 | COMMON_GLOBAL_CFLAGS += -DOMAP_MULTIZONE_AUDIO | ||
75 | endif | ||
76 | |||
77 | #BOARD_SEPOLICY_DIRS := device/ti/jacinto6evm/sepolicy | ||
78 | #BOARD_SEPOLICY_UNION := \ | ||
79 | # healthd.te | ||
80 | |||
diff --git a/CleanSpec.mk b/CleanSpec.mk new file mode 100644 index 0000000..07f668f --- /dev/null +++ b/CleanSpec.mk | |||
@@ -0,0 +1,51 @@ | |||
1 | # Copyright (C) 2007 The Android Open Source Project | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | # | ||
15 | |||
16 | # If you don't need to do a full clean build but would like to touch | ||
17 | # a file or delete some intermediate files, add a clean step to the end | ||
18 | # of the list. These steps will only be run once, if they haven't been | ||
19 | # run before. | ||
20 | # | ||
21 | # E.g.: | ||
22 | # $(call add-clean-step, touch -c external/sqlite/sqlite3.h) | ||
23 | # $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) | ||
24 | # | ||
25 | # Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with | ||
26 | # files that are missing or have been moved. | ||
27 | # | ||
28 | # Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. | ||
29 | # Use $(OUT_DIR) to refer to the "out" directory. | ||
30 | # | ||
31 | # If you need to re-do something that's already mentioned, just copy | ||
32 | # the command and add it to the bottom of the list. E.g., if a change | ||
33 | # that you made last week required touching a file and a change you | ||
34 | # made today requires touching the same file, just copy the old | ||
35 | # touch step and add it to the end of the list. | ||
36 | # | ||
37 | # ************************************************ | ||
38 | # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST | ||
39 | # ************************************************ | ||
40 | |||
41 | # For example: | ||
42 | #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) | ||
43 | #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) | ||
44 | #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) | ||
45 | #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) | ||
46 | |||
47 | # ************************************************ | ||
48 | # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST | ||
49 | # ************************************************ | ||
50 | $(call add-clean-step, rm -f $(PRODUCT_OUT)/system/build.prop) | ||
51 | $(call add-clean-step, rm -f $(PRODUCT_OUT)/system/build.prop) \ No newline at end of file | ||
diff --git a/LDC_3001_TouchScreen_Controller.idc b/LDC_3001_TouchScreen_Controller.idc new file mode 100644 index 0000000..2d4c26a --- /dev/null +++ b/LDC_3001_TouchScreen_Controller.idc | |||
@@ -0,0 +1,25 @@ | |||
1 | # Copyright (C) 2010 The Android Open Source Project | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | # | ||
16 | # Input Device Configuration File for the Atmel Maxtouch touch screen. | ||
17 | # | ||
18 | # These calibration values are derived from empirical measurements | ||
19 | # and may not be appropriate for use with other touch screens. | ||
20 | # Refer to the input device configuration documentation for more details. | ||
21 | # | ||
22 | |||
23 | # Basic Parameters | ||
24 | touch.deviceType = touchScreen | ||
25 | touch.orientationAware = 1 | ||
diff --git a/audio/Android.mk b/audio/Android.mk new file mode 100644 index 0000000..da7bcfe --- /dev/null +++ b/audio/Android.mk | |||
@@ -0,0 +1,37 @@ | |||
1 | # Copyright (C) 2013 Texas Instruments | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | LOCAL_PATH := $(call my-dir) | ||
16 | |||
17 | include $(CLEAR_VARS) | ||
18 | LOCAL_MODULE := mixer_paths.xml | ||
19 | LOCAL_MODULE_TAGS := optional | ||
20 | LOCAL_MODULE_CLASS := ETC | ||
21 | LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) | ||
22 | LOCAL_SRC_FILES := $(LOCAL_MODULE) | ||
23 | include $(BUILD_PREBUILT) | ||
24 | |||
25 | # build multizone audio if the OMAP_MULTIZONE_AUDIO flag is set to true | ||
26 | ifeq ($(OMAP_MULTIZONE_AUDIO),true) | ||
27 | include $(CLEAR_VARS) | ||
28 | |||
29 | include $(LOCAL_PATH)/multizone/Android.mk | ||
30 | |||
31 | else # build the legacy audio if the OMAP_MULTIZONE_AUDIO flag is set to false | ||
32 | |||
33 | include $(CLEAR_VARS) | ||
34 | |||
35 | include $(LOCAL_PATH)/legacy/Android.mk | ||
36 | |||
37 | endif | ||
diff --git a/audio/legacy/Android.mk b/audio/legacy/Android.mk new file mode 100644 index 0000000..1e6c223 --- /dev/null +++ b/audio/legacy/Android.mk | |||
@@ -0,0 +1,51 @@ | |||
1 | # Copyright (C) 2013 Texas Instruments | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | LOCAL_PATH := $(call my-dir) | ||
16 | |||
17 | ifeq ($(findstring jacinto6, $(TARGET_BOARD_PLATFORM)),jacinto6) | ||
18 | |||
19 | include $(CLEAR_VARS) | ||
20 | LOCAL_MODULE := audio_policy.conf | ||
21 | LOCAL_MODULE_TAGS := optional | ||
22 | LOCAL_MODULE_CLASS := ETC | ||
23 | LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) | ||
24 | LOCAL_SRC_FILES := $(LOCAL_MODULE) | ||
25 | include $(BUILD_PREBUILT) | ||
26 | |||
27 | include $(CLEAR_VARS) | ||
28 | |||
29 | LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) | ||
30 | |||
31 | LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw | ||
32 | LOCAL_SRC_FILES := audio_hw.c | ||
33 | |||
34 | LOCAL_C_INCLUDES += \ | ||
35 | external/tinyalsa/include \ | ||
36 | system/media/audio_route/include \ | ||
37 | system/media/audio_utils/include \ | ||
38 | system/media/audio_effects/include | ||
39 | |||
40 | LOCAL_SHARED_LIBRARIES := \ | ||
41 | liblog \ | ||
42 | libcutils \ | ||
43 | libtinyalsa \ | ||
44 | libaudioroute \ | ||
45 | libaudioutils | ||
46 | |||
47 | LOCAL_MODULE_TAGS := optional | ||
48 | |||
49 | include $(BUILD_SHARED_LIBRARY) | ||
50 | |||
51 | endif | ||
diff --git a/audio/legacy/audio_hw.c b/audio/legacy/audio_hw.c new file mode 100644 index 0000000..772f17b --- /dev/null +++ b/audio/legacy/audio_hw.c | |||
@@ -0,0 +1,1674 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Texas Instruments | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #define LOG_TAG "audio_hw_primary" | ||
18 | //#define LOG_NDEBUG 0 | ||
19 | //#define VERY_VERBOSE_LOGGING | ||
20 | #ifdef VERY_VERBOSE_LOGGING | ||
21 | #define ALOGVV ALOGV | ||
22 | #else | ||
23 | #define ALOGVV(a...) do { } while(0) | ||
24 | #endif | ||
25 | |||
26 | #include <errno.h> | ||
27 | #include <stdint.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <sys/time.h> | ||
30 | |||
31 | #include <cutils/log.h> | ||
32 | #include <cutils/str_parms.h> | ||
33 | #include <cutils/properties.h> | ||
34 | |||
35 | #include <audio_utils/resampler.h> | ||
36 | #include <audio_route/audio_route.h> | ||
37 | #include <system/audio.h> | ||
38 | #include <hardware/hardware.h> | ||
39 | #include <hardware/audio.h> | ||
40 | #include <hardware/audio_effect.h> | ||
41 | |||
42 | #include <tinyalsa/asoundlib.h> | ||
43 | |||
44 | /* yet another definition of ARRAY_SIZE macro) */ | ||
45 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | ||
46 | |||
47 | /* | ||
48 | * additional space in resampler buffer allowing for extra samples to be returned | ||
49 | * by speex resampler when sample rates ratio is not an integer | ||
50 | */ | ||
51 | #define RESAMPLER_HEADROOM_FRAMES 10 | ||
52 | |||
53 | /* buffer_remix: functor for doing in-place buffer manipulations. | ||
54 | * | ||
55 | * NB. When remix_func is called, the memory at `buf` must be at least | ||
56 | * as large as frames * sample_size * MAX(in_chans, out_chans). | ||
57 | */ | ||
58 | struct buffer_remix { | ||
59 | void (*remix_func)(struct buffer_remix *data, void *buf, size_t frames); | ||
60 | size_t sample_size; /* size of one audio sample, in bytes */ | ||
61 | size_t in_chans; /* number of input channels */ | ||
62 | size_t out_chans; /* number of output channels */ | ||
63 | }; | ||
64 | |||
65 | struct j6_voice_stream { | ||
66 | struct j6_audio_device *dev; | ||
67 | struct pcm *pcm_in; | ||
68 | struct pcm *pcm_out; | ||
69 | struct pcm_config in_config; | ||
70 | struct pcm_config out_config; | ||
71 | struct resampler_itfe *resampler; | ||
72 | struct resampler_buffer_provider buf_provider; | ||
73 | struct buffer_remix *remix; | ||
74 | pthread_t thread; | ||
75 | int16_t *in_buffer; | ||
76 | int16_t *out_buffer; | ||
77 | size_t in_frames; | ||
78 | size_t out_frames; | ||
79 | size_t frame_size; | ||
80 | char *name; | ||
81 | }; | ||
82 | |||
83 | struct j6_voice { | ||
84 | struct j6_voice_stream ul; | ||
85 | struct j6_voice_stream dl; | ||
86 | }; | ||
87 | |||
88 | struct j6_audio_device { | ||
89 | struct audio_hw_device device; | ||
90 | struct j6_stream_in *in; | ||
91 | struct j6_stream_out *out; | ||
92 | struct j6_voice voice; | ||
93 | struct audio_route *route; | ||
94 | audio_devices_t in_device; | ||
95 | audio_devices_t out_device; | ||
96 | pthread_mutex_t lock; | ||
97 | unsigned int card; | ||
98 | unsigned int in_port; | ||
99 | unsigned int out_port; | ||
100 | unsigned int bt_port; | ||
101 | bool mic_mute; | ||
102 | bool in_call; | ||
103 | audio_mode_t mode; | ||
104 | }; | ||
105 | |||
106 | struct j6_stream_in { | ||
107 | struct audio_stream_in stream; | ||
108 | struct j6_audio_device *dev; | ||
109 | struct pcm_config config; | ||
110 | struct pcm *pcm; | ||
111 | struct buffer_remix *remix; /* adapt hw chan count to client */ | ||
112 | struct resampler_itfe *resampler; | ||
113 | struct resampler_buffer_provider buf_provider; | ||
114 | int16_t *buffer; | ||
115 | size_t frames_in; | ||
116 | size_t hw_frame_size; | ||
117 | unsigned int requested_rate; | ||
118 | unsigned int requested_channels; | ||
119 | int read_status; | ||
120 | pthread_mutex_t lock; | ||
121 | bool standby; | ||
122 | }; | ||
123 | |||
124 | struct j6_stream_out { | ||
125 | struct audio_stream_out stream; | ||
126 | struct j6_audio_device *dev; | ||
127 | struct pcm_config config; | ||
128 | struct pcm *pcm; | ||
129 | struct timespec last; | ||
130 | pthread_mutex_t lock; | ||
131 | bool standby; | ||
132 | int64_t written; /* total frames written, not cleared when entering standby */ | ||
133 | }; | ||
134 | |||
135 | |||
136 | static const char *supported_cards[] = { | ||
137 | "dra7evm", | ||
138 | "VayuEVM", | ||
139 | }; | ||
140 | |||
141 | #define SUPPORTED_IN_DEVICES (AUDIO_DEVICE_IN_BUILTIN_MIC | \ | ||
142 | AUDIO_DEVICE_IN_WIRED_HEADSET | \ | ||
143 | AUDIO_DEVICE_IN_DEFAULT) | ||
144 | #define SUPPORTED_OUT_DEVICES (AUDIO_DEVICE_OUT_SPEAKER | \ | ||
145 | AUDIO_DEVICE_OUT_WIRED_HEADSET | \ | ||
146 | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | \ | ||
147 | AUDIO_DEVICE_OUT_DEFAULT) | ||
148 | |||
149 | #define CAPTURE_SAMPLE_RATE 44100 | ||
150 | #define CAPTURE_PERIOD_SIZE 960 | ||
151 | #define CAPTURE_PERIOD_COUNT 4 | ||
152 | #define CAPTURE_BUFFER_SIZE (CAPTURE_PERIOD_SIZE * CAPTURE_PERIOD_COUNT) | ||
153 | |||
154 | #define PLAYBACK_SAMPLE_RATE 44100 | ||
155 | #define PLAYBACK_PERIOD_SIZE 960 | ||
156 | #define PLAYBACK_PERIOD_COUNT 4 | ||
157 | #define PLAYBACK_BUFFER_SIZE (PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT) | ||
158 | |||
159 | #define BT_SAMPLE_RATE 8000 | ||
160 | #define BT_PERIOD_SIZE 160 | ||
161 | #define BT_PERIOD_COUNT 4 | ||
162 | #define BT_BUFFER_SIZE (BT_PERIOD_SIZE * BT_PERIOD_COUNT) | ||
163 | |||
164 | struct pcm_config pcm_config_capture = { | ||
165 | .channels = 2, | ||
166 | .rate = CAPTURE_SAMPLE_RATE, | ||
167 | .format = PCM_FORMAT_S16_LE, | ||
168 | .period_size = CAPTURE_PERIOD_SIZE, | ||
169 | .period_count = CAPTURE_PERIOD_COUNT, | ||
170 | .start_threshold = 1, | ||
171 | .stop_threshold = CAPTURE_BUFFER_SIZE, | ||
172 | }; | ||
173 | |||
174 | struct pcm_config pcm_config_playback = { | ||
175 | .channels = 2, | ||
176 | .rate = PLAYBACK_SAMPLE_RATE, | ||
177 | .format = PCM_FORMAT_S16_LE, | ||
178 | .period_size = PLAYBACK_PERIOD_SIZE, | ||
179 | .period_count = PLAYBACK_PERIOD_COUNT, | ||
180 | .start_threshold = PLAYBACK_BUFFER_SIZE / 2, | ||
181 | .stop_threshold = PLAYBACK_BUFFER_SIZE, | ||
182 | .avail_min = PLAYBACK_PERIOD_SIZE, | ||
183 | }; | ||
184 | |||
185 | struct pcm_config pcm_config_bt_in = { | ||
186 | .channels = 2, | ||
187 | .rate = BT_SAMPLE_RATE, | ||
188 | .format = PCM_FORMAT_S16_LE, | ||
189 | .period_size = BT_PERIOD_SIZE, | ||
190 | .period_count = BT_PERIOD_COUNT, | ||
191 | .start_threshold = 1, | ||
192 | .stop_threshold = BT_BUFFER_SIZE, | ||
193 | }; | ||
194 | |||
195 | struct pcm_config pcm_config_bt_out = { | ||
196 | .channels = 2, | ||
197 | .rate = BT_SAMPLE_RATE, | ||
198 | .format = PCM_FORMAT_S16_LE, | ||
199 | .period_size = BT_PERIOD_SIZE, | ||
200 | .period_count = BT_PERIOD_COUNT, | ||
201 | .start_threshold = BT_BUFFER_SIZE / 2, | ||
202 | .stop_threshold = BT_BUFFER_SIZE, | ||
203 | .avail_min = BT_PERIOD_SIZE, | ||
204 | }; | ||
205 | |||
206 | static int find_supported_card(void) | ||
207 | { | ||
208 | char name[256] = ""; | ||
209 | int card = 0; | ||
210 | int found = 0; | ||
211 | unsigned int i; | ||
212 | |||
213 | #ifdef OMAP_ENHANCEMENT | ||
214 | do { | ||
215 | /* returns an error after last valid card */ | ||
216 | int ret = mixer_get_card_name(card, name, sizeof(name)); | ||
217 | if (ret) | ||
218 | break; | ||
219 | |||
220 | for (i = 0; i < ARRAY_SIZE(supported_cards); ++i) { | ||
221 | if (supported_cards[i] && !strcmp(name, supported_cards[i])) { | ||
222 | ALOGV("Supported card '%s' found at %d", name, card); | ||
223 | found = 1; | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | } while (!found && (card++ < MAX_CARD_COUNT)); | ||
228 | #endif | ||
229 | |||
230 | /* Use default card number if not found */ | ||
231 | if (!found) | ||
232 | card = 0; | ||
233 | |||
234 | return card; | ||
235 | } | ||
236 | |||
237 | static void do_out_standby(struct j6_stream_out *out); | ||
238 | |||
239 | /* must be called with device lock held */ | ||
240 | static void select_input_device(struct j6_audio_device *adev) | ||
241 | { | ||
242 | if (adev->in_device & ~SUPPORTED_IN_DEVICES) | ||
243 | ALOGW("select_input_device() device not supported, will use default device"); | ||
244 | } | ||
245 | |||
246 | /* must be called with device lock held */ | ||
247 | static void select_output_device(struct j6_audio_device *adev) | ||
248 | { | ||
249 | if (adev->out_device & ~SUPPORTED_OUT_DEVICES) | ||
250 | ALOGW("select_output_device() device(s) not supported, will use default devices"); | ||
251 | } | ||
252 | |||
253 | static size_t get_input_buffer_size(uint32_t sample_rate, int format, int channel_count) | ||
254 | { | ||
255 | size_t size; | ||
256 | |||
257 | /* | ||
258 | * take resampling into account and return the closest majoring | ||
259 | * multiple of 16 frames, as audioflinger expects audio buffers to | ||
260 | * be a multiple of 16 frames | ||
261 | */ | ||
262 | size = (pcm_config_capture.period_size * sample_rate) / pcm_config_capture.rate; | ||
263 | size = ((size + 15) / 16) * 16; | ||
264 | |||
265 | return size * channel_count * sizeof(int16_t); | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * Implementation of buffer_remix::remix_func that removes | ||
270 | * channels in place without doing any other processing. The | ||
271 | * extra channels are truncated. | ||
272 | */ | ||
273 | static void remove_channels_from_buf(struct buffer_remix *data, void *buf, size_t frames) | ||
274 | { | ||
275 | size_t samp_size, in_frame, out_frame; | ||
276 | size_t N, c; | ||
277 | char *s, *d; | ||
278 | |||
279 | ALOGVV("remove_channels_from_buf() remix=%p buf=%p frames=%u", | ||
280 | data, buf, frames); | ||
281 | |||
282 | if (frames == 0) | ||
283 | return; | ||
284 | |||
285 | samp_size = data->sample_size; | ||
286 | in_frame = data->in_chans * samp_size; | ||
287 | out_frame = data->out_chans * samp_size; | ||
288 | |||
289 | if (out_frame >= in_frame) { | ||
290 | ALOGE("BUG: remove_channels_from_buf() can not add channels to a buffer.\n"); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | N = frames - 1; | ||
295 | d = (char*)buf + out_frame; | ||
296 | s = (char*)buf + in_frame; | ||
297 | |||
298 | /* take the first several channels and truncate the rest */ | ||
299 | while (N--) { | ||
300 | for (c = 0; c < out_frame; ++c) | ||
301 | d[c] = s[c]; | ||
302 | d += out_frame; | ||
303 | s += in_frame; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int setup_stereo_to_mono_input_remix(struct j6_stream_in *in) | ||
308 | { | ||
309 | ALOGV("setup_stereo_to_mono_input_remix() stream=%p", in); | ||
310 | |||
311 | struct buffer_remix *br = (struct buffer_remix *)malloc(sizeof(struct buffer_remix)); | ||
312 | if (!br) | ||
313 | return -ENOMEM; | ||
314 | |||
315 | br->remix_func = remove_channels_from_buf; | ||
316 | br->sample_size = sizeof(int16_t); | ||
317 | br->in_chans = 2; | ||
318 | br->out_chans = 1; | ||
319 | in->remix = br; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Implementation of buffer_remix::remix_func that duplicates the first | ||
326 | * channel into the rest of channels in the frame without doing any other | ||
327 | * processing. It assumes data in 16-bits, but it's not explicitly checked | ||
328 | */ | ||
329 | static void mono_remix(struct buffer_remix *data, void *buf, size_t frames) | ||
330 | { | ||
331 | int16_t *buffer = (int16_t*)buf; | ||
332 | size_t i; | ||
333 | |||
334 | ALOGVV("mono_remix() remix=%p buf=%p frames=%u", data, buf, frames); | ||
335 | |||
336 | if (frames == 0) | ||
337 | return; | ||
338 | |||
339 | /* duplicate first channel into the rest of channels in the frame */ | ||
340 | while (frames--) { | ||
341 | for (i = 1; i < data->out_chans; i++) | ||
342 | buffer[i] = buffer[0]; | ||
343 | buffer += data->out_chans; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static int setup_mono_input_remix(struct j6_voice_stream *stream) | ||
348 | { | ||
349 | ALOGV("setup_mono_input_remix() %s stream", stream->name); | ||
350 | |||
351 | struct buffer_remix *br = (struct buffer_remix *)malloc(sizeof(struct buffer_remix)); | ||
352 | if (!br) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | br->remix_func = mono_remix; | ||
356 | br->sample_size = sizeof(int16_t); | ||
357 | br->in_chans = stream->in_config.channels; | ||
358 | br->out_chans = stream->out_config.channels; | ||
359 | stream->remix = br; | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int voice_get_next_buffer(struct resampler_buffer_provider *buffer_provider, | ||
365 | struct resampler_buffer* buffer) | ||
366 | { | ||
367 | struct j6_voice_stream *stream; | ||
368 | int ret; | ||
369 | |||
370 | if (buffer_provider == NULL || buffer == NULL) { | ||
371 | ALOGE("voice_get_next_buffer() invalid buffer/provider"); | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | stream = (struct j6_voice_stream *)((char *)buffer_provider - | ||
376 | offsetof(struct j6_voice_stream, buf_provider)); | ||
377 | |||
378 | if (stream->pcm_in == NULL) { | ||
379 | buffer->raw = NULL; | ||
380 | buffer->frame_count = 0; | ||
381 | return -ENODEV; | ||
382 | } | ||
383 | |||
384 | if (buffer->frame_count > stream->in_frames) { | ||
385 | ALOGW("voice_get_next_buffer() %s unexpected frame count %u, " | ||
386 | "buffer was allocated for %u frames", | ||
387 | stream->name, buffer->frame_count, stream->in_frames); | ||
388 | buffer->frame_count = stream->in_frames; | ||
389 | } | ||
390 | |||
391 | ret = pcm_read(stream->pcm_in, stream->in_buffer, | ||
392 | buffer->frame_count * stream->frame_size); | ||
393 | if (ret) { | ||
394 | ALOGE("voice_get_next_buffer() failed to read %s: %s", | ||
395 | stream->name, pcm_get_error(stream->pcm_in)); | ||
396 | buffer->raw = NULL; | ||
397 | buffer->frame_count = 0; | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | buffer->i16 = stream->in_buffer; | ||
402 | |||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | static void voice_release_buffer(struct resampler_buffer_provider *buffer_provider, | ||
407 | struct resampler_buffer* buffer) | ||
408 | { | ||
409 | } | ||
410 | |||
411 | static void *voice_thread_func(void *arg) | ||
412 | { | ||
413 | struct j6_voice_stream *stream = (struct j6_voice_stream *)arg; | ||
414 | struct j6_audio_device *adev = stream->dev; | ||
415 | struct timespec now; | ||
416 | size_t frames = stream->out_frames; | ||
417 | uint32_t periods = 0; | ||
418 | uint32_t avail; | ||
419 | bool in_steady = false; | ||
420 | bool out_steady = false; | ||
421 | int ret = 0; | ||
422 | |||
423 | pcm_start(stream->pcm_in); | ||
424 | |||
425 | memset(stream->out_buffer, 0, stream->out_frames * stream->frame_size); | ||
426 | |||
427 | while (adev->in_call) { | ||
428 | if (out_steady) { | ||
429 | if (in_steady) { | ||
430 | stream->resampler->resample_from_provider(stream->resampler, | ||
431 | stream->out_buffer, | ||
432 | &frames); | ||
433 | } else { | ||
434 | ret = pcm_get_htimestamp(stream->pcm_in, &avail, &now); | ||
435 | if (!ret && (avail > 0)) { | ||
436 | in_steady = true; | ||
437 | continue; | ||
438 | } | ||
439 | } | ||
440 | } else if (++periods == stream->out_config.period_count) { | ||
441 | out_steady = true; | ||
442 | } | ||
443 | |||
444 | if (stream->remix) | ||
445 | stream->remix->remix_func(stream->remix, stream->out_buffer, frames); | ||
446 | |||
447 | ret = pcm_write(stream->pcm_out, stream->out_buffer, | ||
448 | frames * stream->frame_size); | ||
449 | if (ret) { | ||
450 | ALOGE("voice_thread_func() failed to write %s: %s", | ||
451 | stream->name, pcm_get_error(stream->pcm_out)); | ||
452 | usleep((frames * 1000000) / stream->out_config.rate); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | return (void*)ret; | ||
457 | } | ||
458 | |||
459 | static void voice_stream_exit(struct j6_voice_stream *stream) | ||
460 | { | ||
461 | if (stream->resampler) { | ||
462 | release_resampler(stream->resampler); | ||
463 | stream->resampler = NULL; | ||
464 | } | ||
465 | |||
466 | if (stream->pcm_out) { | ||
467 | pcm_close(stream->pcm_out); | ||
468 | stream->pcm_out = NULL; | ||
469 | } | ||
470 | |||
471 | if (stream->pcm_in) { | ||
472 | pcm_close(stream->pcm_in); | ||
473 | stream->pcm_in = NULL; | ||
474 | } | ||
475 | |||
476 | if (stream->in_buffer) { | ||
477 | free(stream->in_buffer); | ||
478 | stream->in_buffer = NULL; | ||
479 | stream->in_frames = 0; | ||
480 | } | ||
481 | |||
482 | if (stream->out_buffer) { | ||
483 | free(stream->out_buffer); | ||
484 | stream->out_buffer = NULL; | ||
485 | stream->out_frames = 0; | ||
486 | } | ||
487 | |||
488 | if (stream->remix) { | ||
489 | free(stream->remix); | ||
490 | stream->remix = NULL; | ||
491 | } | ||
492 | |||
493 | if (stream->name) { | ||
494 | free(stream->name); | ||
495 | stream->name = NULL; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | static int voice_stream_init(struct j6_voice_stream *stream, | ||
500 | unsigned int in_port, | ||
501 | unsigned int out_port, | ||
502 | bool needs_mono_remix) | ||
503 | { | ||
504 | struct j6_audio_device *adev = stream->dev; | ||
505 | int ret; | ||
506 | |||
507 | stream->buf_provider.get_next_buffer = voice_get_next_buffer; | ||
508 | stream->buf_provider.release_buffer = voice_release_buffer; | ||
509 | ret = create_resampler(stream->in_config.rate, | ||
510 | stream->out_config.rate, | ||
511 | 2, | ||
512 | RESAMPLER_QUALITY_DEFAULT, | ||
513 | &stream->buf_provider, | ||
514 | &stream->resampler); | ||
515 | if (ret) { | ||
516 | ALOGE("voice_stream_init() failed to create %s resampler %d", stream->name, ret); | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | stream->pcm_in = pcm_open(adev->card, in_port, PCM_IN, &stream->in_config); | ||
521 | stream->pcm_out = pcm_open(adev->card, out_port, PCM_OUT, &stream->out_config); | ||
522 | |||
523 | if (!pcm_is_ready(stream->pcm_in) || !pcm_is_ready(stream->pcm_out)) { | ||
524 | ALOGE("voice_stream_init() failed to open pcm %s devices", stream->name); | ||
525 | voice_stream_exit(stream); | ||
526 | return -ENODEV; | ||
527 | } | ||
528 | |||
529 | stream->frame_size = pcm_frames_to_bytes(stream->pcm_in, 1); | ||
530 | |||
531 | /* out_buffer will store the resampled data */ | ||
532 | stream->out_frames = stream->out_config.period_size; | ||
533 | stream->out_buffer = malloc(stream->out_frames * stream->frame_size); | ||
534 | |||
535 | /* in_buffer will store the frames recorded from the PCM device */ | ||
536 | stream->in_frames = (stream->out_frames * stream->in_config.rate) / stream->out_config.rate + | ||
537 | RESAMPLER_HEADROOM_FRAMES; | ||
538 | stream->in_buffer = malloc(stream->in_frames * stream->frame_size); | ||
539 | |||
540 | if (!stream->in_buffer || !stream->out_buffer) { | ||
541 | ALOGE("voice_stream_init() failed to allocate %s buffers", stream->name); | ||
542 | voice_stream_exit(stream); | ||
543 | return -ENOMEM; | ||
544 | } | ||
545 | |||
546 | if (needs_mono_remix) { | ||
547 | ret = setup_mono_input_remix(stream); | ||
548 | if (ret) { | ||
549 | ALOGE("voice_stream_init() failed to setup mono remix %d", ret); | ||
550 | voice_stream_exit(stream); | ||
551 | return ret; | ||
552 | } | ||
553 | } else { | ||
554 | stream->remix = NULL; | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int enter_voice_call(struct j6_audio_device *adev) | ||
561 | { | ||
562 | struct j6_voice *voice = &adev->voice; | ||
563 | int ret; | ||
564 | |||
565 | ALOGI("enter_voice_call() entering bluetooth voice call"); | ||
566 | |||
567 | audio_route_apply_path(adev->route, "BT SCO Master"); | ||
568 | audio_route_update_mixer(adev->route); | ||
569 | |||
570 | /* Let the primary output switch to a dummy sink */ | ||
571 | if (adev->out) | ||
572 | do_out_standby(adev->out); | ||
573 | |||
574 | /* Uplink: Mic (44.1kHz) -> BT (8kHz) */ | ||
575 | voice->ul.name = strdup("UL"); | ||
576 | voice->ul.in_config = pcm_config_capture; | ||
577 | voice->ul.out_config = pcm_config_bt_out; | ||
578 | voice->ul.dev = adev; | ||
579 | ret = voice_stream_init(&voice->ul, adev->in_port, adev->bt_port, false); | ||
580 | if (ret) { | ||
581 | ALOGE("enter_voice_call() failed to init uplink %d", ret); | ||
582 | goto err_ul_init; | ||
583 | } | ||
584 | |||
585 | /* Downlink: BT (8kHz) -> HP/Spk (44.1kHz) */ | ||
586 | voice->dl.name = strdup("DL"); | ||
587 | voice->dl.in_config = pcm_config_bt_in; | ||
588 | voice->dl.out_config = pcm_config_playback; | ||
589 | voice->dl.dev = adev; | ||
590 | ret = voice_stream_init(&voice->dl, adev->bt_port, adev->out_port, true); | ||
591 | if (ret) { | ||
592 | ALOGE("enter_voice_call() failed to init downlink %d", ret); | ||
593 | goto err_dl_init; | ||
594 | } | ||
595 | |||
596 | adev->in_call = true; | ||
597 | |||
598 | /* Create uplink thread: Mic -> BT */ | ||
599 | ret = pthread_create(&voice->ul.thread, NULL, voice_thread_func, &voice->ul); | ||
600 | if (ret) { | ||
601 | ALOGE("enter_voice_call() failed to create uplink thread %d", ret); | ||
602 | adev->in_call = false; | ||
603 | goto err_ul_thread; | ||
604 | } | ||
605 | |||
606 | /* Create downlink thread: BT -> HP/Spk */ | ||
607 | ret = pthread_create(&voice->dl.thread, NULL, voice_thread_func, &voice->dl); | ||
608 | if (ret) { | ||
609 | ALOGE("enter_voice_call() failed to create downlink thread %d", ret); | ||
610 | adev->in_call = false; | ||
611 | goto err_dl_thread; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | |||
616 | err_dl_thread: | ||
617 | pthread_join(voice->ul.thread, NULL); | ||
618 | err_ul_thread: | ||
619 | voice_stream_exit(&voice->ul); | ||
620 | err_dl_init: | ||
621 | voice_stream_exit(&voice->dl); | ||
622 | err_ul_init: | ||
623 | audio_route_reset_path(adev->route, "BT SCO Master"); | ||
624 | audio_route_update_mixer(adev->route); | ||
625 | |||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | static void leave_voice_call(struct j6_audio_device *adev) | ||
630 | { | ||
631 | struct j6_voice *voice = &adev->voice; | ||
632 | struct j6_voice_stream *ul = &voice->ul; | ||
633 | struct j6_voice_stream *dl = &voice->dl; | ||
634 | void *ret; | ||
635 | |||
636 | ALOGI("leave_voice_call() leaving bluetooth voice call"); | ||
637 | |||
638 | adev->in_call = false; | ||
639 | |||
640 | /* | ||
641 | * The PCM ports used for Bluetooth are slaves and they can lose the | ||
642 | * BCLK and FSYNC while still active. That leads to blocking read() and | ||
643 | * write() calls, which is prevented by switching the clock source to | ||
644 | * an internal one and explicitly stopping both ports for the new source | ||
645 | * to take effect at kernel level | ||
646 | */ | ||
647 | audio_route_reset_path(adev->route, "BT SCO Master"); | ||
648 | audio_route_update_mixer(adev->route); | ||
649 | if (ul->pcm_out) | ||
650 | pcm_stop(ul->pcm_out); | ||
651 | if (dl->pcm_in) | ||
652 | pcm_stop(dl->pcm_in); | ||
653 | |||
654 | pthread_join(voice->dl.thread, &ret); | ||
655 | pthread_join(voice->ul.thread, &ret); | ||
656 | |||
657 | voice_stream_exit(&voice->dl); | ||
658 | voice_stream_exit(&voice->ul); | ||
659 | |||
660 | /* Let the primary output switch back to its ALSA PCM device */ | ||
661 | if (adev->out) | ||
662 | do_out_standby(adev->out); | ||
663 | } | ||
664 | |||
665 | static uint32_t time_diff(struct timespec t1, struct timespec t0) | ||
666 | { | ||
667 | struct timespec temp; | ||
668 | |||
669 | if ((t1.tv_nsec - t0.tv_nsec) < 0) { | ||
670 | temp.tv_sec = t1.tv_sec - t0.tv_sec-1; | ||
671 | temp.tv_nsec = 1000000000UL + t1.tv_nsec - t0.tv_nsec; | ||
672 | } else { | ||
673 | temp.tv_sec = t1.tv_sec - t0.tv_sec; | ||
674 | temp.tv_nsec = t1.tv_nsec - t0.tv_nsec; | ||
675 | } | ||
676 | |||
677 | return (temp.tv_sec * 1000000UL + temp.tv_nsec / 1000); | ||
678 | } | ||
679 | |||
680 | /* audio HAL functions */ | ||
681 | |||
682 | static uint32_t out_get_sample_rate(const struct audio_stream *stream) | ||
683 | { | ||
684 | uint32_t rate = PLAYBACK_SAMPLE_RATE; | ||
685 | |||
686 | ALOGVV("out_get_sample_rate() stream=%p rate=%u", stream, rate); | ||
687 | |||
688 | return rate; | ||
689 | } | ||
690 | |||
691 | static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) | ||
692 | { | ||
693 | ALOGVV("out_set_sample_rate() stream=%p rate=%u", stream, rate); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static size_t out_get_buffer_size(const struct audio_stream *stream) | ||
699 | { | ||
700 | uint32_t frames = ((PLAYBACK_PERIOD_SIZE + 15) / 16) * 16; | ||
701 | size_t bytes = frames * audio_stream_frame_size(stream); | ||
702 | |||
703 | ALOGVV("out_get_buffer_size() stream=%p frames=%u bytes=%u", stream, frames, bytes); | ||
704 | |||
705 | return bytes; | ||
706 | } | ||
707 | |||
708 | static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) | ||
709 | { | ||
710 | audio_channel_mask_t channels = AUDIO_CHANNEL_OUT_STEREO; | ||
711 | |||
712 | ALOGVV("out_get_channels() stream=%p channels=%u", stream, popcount(channels)); | ||
713 | |||
714 | return channels; | ||
715 | } | ||
716 | |||
717 | static audio_format_t out_get_format(const struct audio_stream *stream) | ||
718 | { | ||
719 | audio_format_t format = AUDIO_FORMAT_PCM_16_BIT; | ||
720 | |||
721 | ALOGVV("out_set_format() stream=%p format=0x%08x (%u bits/sample)", | ||
722 | stream, format, audio_bytes_per_sample(format) << 3); | ||
723 | |||
724 | return format; | ||
725 | } | ||
726 | |||
727 | static int out_set_format(struct audio_stream *stream, audio_format_t format) | ||
728 | { | ||
729 | ALOGVV("out_set_format() stream=%p format=0x%08x (%u bits/sample)", | ||
730 | stream, format, audio_bytes_per_sample(format) << 3); | ||
731 | |||
732 | if (format != AUDIO_FORMAT_PCM_16_BIT) { | ||
733 | return -ENOSYS; | ||
734 | } else { | ||
735 | return 0; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | /* must be called with locks held */ | ||
740 | static void do_out_standby(struct j6_stream_out *out) | ||
741 | { | ||
742 | struct j6_audio_device *adev = out->dev; | ||
743 | |||
744 | if (!out->standby) { | ||
745 | if (adev->mode != AUDIO_MODE_IN_CALL) { | ||
746 | ALOGI("do_out_standby() close card %u port %u", adev->card, adev->out_port); | ||
747 | pcm_close(out->pcm); | ||
748 | out->pcm = NULL; | ||
749 | } else { | ||
750 | ALOGI("do_out_standby() close dummy card"); | ||
751 | } | ||
752 | out->standby = true; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | static int out_standby(struct audio_stream *stream) | ||
757 | { | ||
758 | struct j6_stream_out *out = (struct j6_stream_out *)(stream); | ||
759 | struct j6_audio_device *adev = out->dev; | ||
760 | |||
761 | ALOGV("out_standby() stream=%p", out); | ||
762 | pthread_mutex_lock(&adev->lock); | ||
763 | pthread_mutex_lock(&out->lock); | ||
764 | do_out_standby(out); | ||
765 | pthread_mutex_unlock(&out->lock); | ||
766 | pthread_mutex_unlock(&adev->lock); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static int out_dump(const struct audio_stream *stream, int fd) | ||
772 | { | ||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) | ||
777 | { | ||
778 | struct j6_stream_out *out = (struct j6_stream_out *)(stream); | ||
779 | struct j6_audio_device *adev = out->dev; | ||
780 | struct str_parms *parms; | ||
781 | char value[32]; | ||
782 | int ret; | ||
783 | uint32_t val = 0; | ||
784 | |||
785 | ALOGV("out_set_parameters() stream=%p parameter='%s'", out, kvpairs); | ||
786 | |||
787 | parms = str_parms_create_str(kvpairs); | ||
788 | |||
789 | ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); | ||
790 | if (ret >= 0) { | ||
791 | val = atoi(value); | ||
792 | pthread_mutex_lock(&adev->lock); | ||
793 | pthread_mutex_lock(&out->lock); | ||
794 | if (val != 0) { | ||
795 | if ((adev->out_device & AUDIO_DEVICE_OUT_ALL) != val) | ||
796 | do_out_standby(out); | ||
797 | |||
798 | /* set the active output device */ | ||
799 | adev->out_device = val; | ||
800 | select_output_device(adev); | ||
801 | } | ||
802 | pthread_mutex_unlock(&out->lock); | ||
803 | pthread_mutex_unlock(&adev->lock); | ||
804 | } | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | static char* out_get_parameters(const struct audio_stream *stream, const char *keys) | ||
810 | { | ||
811 | return strdup(""); | ||
812 | } | ||
813 | |||
814 | static uint32_t out_get_latency(const struct audio_stream_out *stream) | ||
815 | { | ||
816 | const struct j6_stream_out *out = (const struct j6_stream_out *)(stream); | ||
817 | uint32_t frames = PLAYBACK_BUFFER_SIZE; | ||
818 | uint32_t latency = (frames * 1000) / PLAYBACK_SAMPLE_RATE; | ||
819 | |||
820 | ALOGVV("out_get_latency() stream=%p latency=%u msecs", out, latency); | ||
821 | |||
822 | return latency; | ||
823 | } | ||
824 | |||
825 | static int out_set_volume(struct audio_stream_out *stream, float left, | ||
826 | float right) | ||
827 | { | ||
828 | return -ENOSYS; | ||
829 | } | ||
830 | |||
831 | static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, | ||
832 | size_t bytes) | ||
833 | { | ||
834 | struct j6_stream_out *out = (struct j6_stream_out *)(stream); | ||
835 | struct j6_audio_device *adev = out->dev; | ||
836 | struct timespec now; | ||
837 | const size_t frame_size = audio_stream_frame_size(&stream->common); | ||
838 | const size_t frames = bytes / frame_size; | ||
839 | uint32_t rate = out->config.rate; | ||
840 | uint32_t write_usecs = frames * 1000000 / rate; | ||
841 | uint32_t diff_usecs; | ||
842 | int ret = 0; | ||
843 | |||
844 | ALOGVV("out_write() stream=%p buffer=%p size=%u/%u time=%u usecs", | ||
845 | out, buffer, frames, rate, write_usecs); | ||
846 | |||
847 | pthread_mutex_lock(&adev->lock); | ||
848 | pthread_mutex_lock(&out->lock); | ||
849 | |||
850 | if (out->standby) { | ||
851 | if (!adev->in_call) { | ||
852 | select_output_device(adev); | ||
853 | |||
854 | ALOGI("out_write() open card %u port %u", adev->card, adev->out_port); | ||
855 | out->pcm = pcm_open(adev->card, adev->out_port, PCM_OUT, &out->config); | ||
856 | if (!pcm_is_ready(out->pcm)) { | ||
857 | ALOGE("out_write() failed to open pcm out: %s", pcm_get_error(out->pcm)); | ||
858 | pcm_close(out->pcm); | ||
859 | out->pcm = NULL; | ||
860 | ret = -ENODEV; | ||
861 | } | ||
862 | } else { | ||
863 | ALOGI("out_write() open dummy port"); | ||
864 | clock_gettime(CLOCK_REALTIME, &out->last); | ||
865 | } | ||
866 | |||
867 | if (ret) { | ||
868 | usleep(write_usecs); /* limits the rate of error messages */ | ||
869 | pthread_mutex_unlock(&out->lock); | ||
870 | pthread_mutex_unlock(&adev->lock); | ||
871 | return ret; | ||
872 | } | ||
873 | |||
874 | out->standby = false; | ||
875 | } | ||
876 | |||
877 | pthread_mutex_unlock(&adev->lock); | ||
878 | |||
879 | if (!adev->in_call) { | ||
880 | ret = pcm_write(out->pcm, buffer, bytes); | ||
881 | if (ret) { | ||
882 | ALOGE("out_write() failed to write audio data %d", ret); | ||
883 | usleep(write_usecs); /* limits the rate of error messages */ | ||
884 | } | ||
885 | } else { | ||
886 | clock_gettime(CLOCK_REALTIME, &now); | ||
887 | diff_usecs = time_diff(now, out->last); | ||
888 | if (write_usecs > diff_usecs) | ||
889 | usleep(write_usecs - diff_usecs); | ||
890 | |||
891 | clock_gettime(CLOCK_REALTIME, &out->last); | ||
892 | } | ||
893 | |||
894 | out->written += frames; | ||
895 | |||
896 | pthread_mutex_unlock(&out->lock); | ||
897 | |||
898 | return bytes; | ||
899 | } | ||
900 | |||
901 | static int out_get_render_position(const struct audio_stream_out *stream, | ||
902 | uint32_t *dsp_frames) | ||
903 | { | ||
904 | return -EINVAL; | ||
905 | } | ||
906 | |||
907 | static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) | ||
908 | { | ||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) | ||
913 | { | ||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static int out_get_next_write_timestamp(const struct audio_stream_out *stream, | ||
918 | int64_t *timestamp) | ||
919 | { | ||
920 | return -EINVAL; | ||
921 | } | ||
922 | |||
923 | static int out_get_presentation_position(const struct audio_stream_out *stream, | ||
924 | uint64_t *frames, struct timespec *timestamp) | ||
925 | { | ||
926 | struct j6_stream_out *out = (struct j6_stream_out *)(stream); | ||
927 | struct j6_audio_device *adev = out->dev; | ||
928 | int64_t signed_frames = -1; | ||
929 | size_t avail; | ||
930 | int ret = -1; | ||
931 | |||
932 | pthread_mutex_lock(&out->lock); | ||
933 | |||
934 | if (!adev->in_call) { | ||
935 | if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) { | ||
936 | signed_frames = out->written - pcm_get_buffer_size(out->pcm) + avail; | ||
937 | } | ||
938 | } else { | ||
939 | clock_gettime(CLOCK_REALTIME, timestamp); | ||
940 | signed_frames = out->written + | ||
941 | (time_diff(*timestamp, out->last) * out->config.rate) / 1000000; | ||
942 | } | ||
943 | |||
944 | /* It would be unusual for this value to be negative, but check just in case ... */ | ||
945 | if (signed_frames >= 0) { | ||
946 | *frames = signed_frames; | ||
947 | ret = 0; | ||
948 | } | ||
949 | |||
950 | pthread_mutex_unlock(&out->lock); | ||
951 | |||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | /** audio_stream_in implementation **/ | ||
956 | static uint32_t in_get_sample_rate(const struct audio_stream *stream) | ||
957 | { | ||
958 | const struct j6_stream_in *in = (const struct j6_stream_in *)(stream); | ||
959 | |||
960 | ALOGVV("in_get_sample_rate() stream=%p rate=%u", stream, in->requested_rate); | ||
961 | |||
962 | return in->requested_rate; | ||
963 | } | ||
964 | |||
965 | static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) | ||
966 | { | ||
967 | ALOGV("in_set_sample_rate() stream=%p rate=%u", stream, rate); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static size_t in_get_buffer_size(const struct audio_stream *stream) | ||
973 | { | ||
974 | const struct j6_stream_in *in = (const struct j6_stream_in *)(stream); | ||
975 | |||
976 | size_t bytes = get_input_buffer_size(in->requested_rate, | ||
977 | AUDIO_FORMAT_PCM_16_BIT, | ||
978 | in->requested_channels); | ||
979 | |||
980 | ALOGVV("in_get_buffer_size() stream=%p bytes=%u", in, bytes); | ||
981 | |||
982 | return bytes; | ||
983 | } | ||
984 | |||
985 | static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) | ||
986 | { | ||
987 | const struct j6_stream_in *in = (const struct j6_stream_in *)(stream); | ||
988 | audio_channel_mask_t channels = audio_channel_out_mask_from_count(in->requested_channels); | ||
989 | |||
990 | ALOGVV("in_get_channels() stream=%p channels=%u", in, in->requested_channels); | ||
991 | |||
992 | return channels; | ||
993 | } | ||
994 | |||
995 | static audio_format_t in_get_format(const struct audio_stream *stream) | ||
996 | { | ||
997 | audio_format_t format = AUDIO_FORMAT_PCM_16_BIT; | ||
998 | |||
999 | ALOGVV("in_set_format() stream=%p format=0x%08x (%u bits/sample)", | ||
1000 | stream, format, audio_bytes_per_sample(format) << 3); | ||
1001 | |||
1002 | return format; | ||
1003 | } | ||
1004 | |||
1005 | static int in_set_format(struct audio_stream *stream, audio_format_t format) | ||
1006 | { | ||
1007 | ALOGV("in_set_format() stream=%p format=0x%08x (%u bits/sample)", | ||
1008 | stream, format, audio_bytes_per_sample(format) << 3); | ||
1009 | |||
1010 | if (format != AUDIO_FORMAT_PCM_16_BIT) { | ||
1011 | return -ENOSYS; | ||
1012 | } else { | ||
1013 | return 0; | ||
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | /* must be called with locks held */ | ||
1018 | static void do_in_standby(struct j6_stream_in *in) | ||
1019 | { | ||
1020 | struct j6_audio_device *adev = in->dev; | ||
1021 | |||
1022 | if (!in->standby) { | ||
1023 | ALOGI("do_in_standby() close card %u port %u", adev->card, adev->out_port); | ||
1024 | pcm_close(in->pcm); | ||
1025 | in->pcm = NULL; | ||
1026 | in->standby = true; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | static int in_standby(struct audio_stream *stream) | ||
1031 | { | ||
1032 | struct j6_stream_in *in = (struct j6_stream_in *)(stream); | ||
1033 | struct j6_audio_device *adev = in->dev; | ||
1034 | |||
1035 | ALOGV("in_standby() stream=%p", in); | ||
1036 | pthread_mutex_lock(&adev->lock); | ||
1037 | pthread_mutex_lock(&in->lock); | ||
1038 | do_in_standby(in); | ||
1039 | pthread_mutex_unlock(&in->lock); | ||
1040 | pthread_mutex_unlock(&adev->lock); | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | static int in_dump(const struct audio_stream *stream, int fd) | ||
1046 | { | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) | ||
1051 | { | ||
1052 | struct j6_stream_in *in = (struct j6_stream_in *)(stream); | ||
1053 | struct j6_audio_device *adev = in->dev; | ||
1054 | struct str_parms *parms; | ||
1055 | char value[32]; | ||
1056 | int ret; | ||
1057 | uint32_t val = 0; | ||
1058 | |||
1059 | ALOGV("in_set_parameters() stream=%p parameter='%s'", stream, kvpairs); | ||
1060 | |||
1061 | parms = str_parms_create_str(kvpairs); | ||
1062 | |||
1063 | /* Nothing to do for AUDIO_PARAMETER_STREAM_INPUT_SOURCE, so it's ignored */ | ||
1064 | |||
1065 | ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); | ||
1066 | if (ret >= 0) { | ||
1067 | val = atoi(value); | ||
1068 | pthread_mutex_lock(&adev->lock); | ||
1069 | pthread_mutex_lock(&in->lock); | ||
1070 | if (val != 0) { | ||
1071 | if ((adev->in_device & AUDIO_DEVICE_IN_ALL) != val) | ||
1072 | do_in_standby(in); | ||
1073 | |||
1074 | /* set the active input device */ | ||
1075 | adev->in_device = val; | ||
1076 | select_input_device(adev); | ||
1077 | } | ||
1078 | pthread_mutex_unlock(&in->lock); | ||
1079 | pthread_mutex_unlock(&adev->lock); | ||
1080 | } | ||
1081 | |||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static char * in_get_parameters(const struct audio_stream *stream, | ||
1086 | const char *keys) | ||
1087 | { | ||
1088 | return strdup(""); | ||
1089 | } | ||
1090 | |||
1091 | static int in_set_gain(struct audio_stream_in *stream, float gain) | ||
1092 | { | ||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | static int get_next_buffer(struct resampler_buffer_provider *buffer_provider, | ||
1097 | struct resampler_buffer* buffer) | ||
1098 | { | ||
1099 | struct j6_stream_in *in; | ||
1100 | struct buffer_remix *remix; | ||
1101 | |||
1102 | if (buffer_provider == NULL || buffer == NULL) | ||
1103 | return -EINVAL; | ||
1104 | |||
1105 | in = (struct j6_stream_in *)((char *)buffer_provider - | ||
1106 | offsetof(struct j6_stream_in, buf_provider)); | ||
1107 | |||
1108 | if (in->pcm == NULL) { | ||
1109 | buffer->raw = NULL; | ||
1110 | buffer->frame_count = 0; | ||
1111 | in->read_status = -ENODEV; | ||
1112 | return -ENODEV; | ||
1113 | } | ||
1114 | |||
1115 | if (in->frames_in == 0) { | ||
1116 | in->read_status = pcm_read(in->pcm, | ||
1117 | (void*)in->buffer, | ||
1118 | buffer->frame_count * in->hw_frame_size); | ||
1119 | if (in->read_status != 0) { | ||
1120 | ALOGE("get_next_buffer() pcm_read error %d", in->read_status); | ||
1121 | buffer->raw = NULL; | ||
1122 | buffer->frame_count = 0; | ||
1123 | return in->read_status; | ||
1124 | } | ||
1125 | in->frames_in = buffer->frame_count; | ||
1126 | |||
1127 | remix = in->remix; | ||
1128 | if (remix) | ||
1129 | remix->remix_func(remix, in->buffer, in->frames_in); | ||
1130 | } | ||
1131 | |||
1132 | buffer->frame_count = (buffer->frame_count > in->frames_in) ? | ||
1133 | in->frames_in : buffer->frame_count; | ||
1134 | buffer->i16 = in->buffer; | ||
1135 | |||
1136 | return in->read_status; | ||
1137 | } | ||
1138 | |||
1139 | static void release_buffer(struct resampler_buffer_provider *buffer_provider, | ||
1140 | struct resampler_buffer* buffer) | ||
1141 | { | ||
1142 | struct j6_stream_in *in; | ||
1143 | |||
1144 | if (buffer_provider == NULL || buffer == NULL) | ||
1145 | return; | ||
1146 | |||
1147 | in = (struct j6_stream_in *)((char *)buffer_provider - | ||
1148 | offsetof(struct j6_stream_in, buf_provider)); | ||
1149 | |||
1150 | in->frames_in -= buffer->frame_count; | ||
1151 | } | ||
1152 | |||
1153 | /* | ||
1154 | * read_frames() reads frames from kernel driver, down samples to capture rate | ||
1155 | * if necessary and output the number of frames requested to the buffer specified | ||
1156 | */ | ||
1157 | static ssize_t read_frames(struct j6_stream_in *in, void *buffer, ssize_t frames) | ||
1158 | { | ||
1159 | ssize_t frames_wr = 0; | ||
1160 | size_t frame_size; | ||
1161 | |||
1162 | ALOGVV("read_frames() stream=%p frames=%u", in, frames); | ||
1163 | |||
1164 | if (in->remix) | ||
1165 | frame_size = audio_stream_frame_size(&in->stream.common); | ||
1166 | else | ||
1167 | frame_size = in->hw_frame_size; | ||
1168 | |||
1169 | while (frames_wr < frames) { | ||
1170 | size_t frames_rd = frames - frames_wr; | ||
1171 | |||
1172 | in->resampler->resample_from_provider(in->resampler, | ||
1173 | (int16_t *)((char *)buffer + frames_wr * frame_size), | ||
1174 | &frames_rd); | ||
1175 | /* in->read_status is updated by getNextBuffer() also called by | ||
1176 | * in->resampler->resample_from_provider() */ | ||
1177 | if (in->read_status != 0) | ||
1178 | return in->read_status; | ||
1179 | |||
1180 | frames_wr += frames_rd; | ||
1181 | } | ||
1182 | |||
1183 | return frames_wr; | ||
1184 | } | ||
1185 | |||
1186 | static ssize_t in_read(struct audio_stream_in *stream, void* buffer, | ||
1187 | size_t bytes) | ||
1188 | { | ||
1189 | struct j6_stream_in *in = (struct j6_stream_in *)(stream); | ||
1190 | struct j6_audio_device *adev = in->dev; | ||
1191 | const size_t frame_size = audio_stream_frame_size(&stream->common); | ||
1192 | const size_t frames = bytes / frame_size; | ||
1193 | uint32_t rate = in_get_sample_rate(&stream->common); | ||
1194 | uint32_t read_usecs = frames * 1000000 / rate; | ||
1195 | int ret; | ||
1196 | |||
1197 | ALOGVV("in_read() stream=%p buffer=%p size=%u/%u time=%u usecs", | ||
1198 | stream, buffer, frames, rate, read_usecs); | ||
1199 | |||
1200 | pthread_mutex_lock(&adev->lock); | ||
1201 | pthread_mutex_lock(&in->lock); | ||
1202 | |||
1203 | if (in->standby) { | ||
1204 | select_input_device(adev); | ||
1205 | |||
1206 | ALOGI("in_read() open card %u port %u", adev->card, adev->in_port); | ||
1207 | in->pcm = pcm_open(adev->card, adev->in_port, PCM_IN, &in->config); | ||
1208 | if (!pcm_is_ready(in->pcm)) { | ||
1209 | ALOGE("in_read() failed to open pcm in: %s", pcm_get_error(in->pcm)); | ||
1210 | pcm_close(in->pcm); | ||
1211 | in->pcm = NULL; | ||
1212 | usleep(read_usecs); /* limits the rate of error messages */ | ||
1213 | pthread_mutex_unlock(&in->lock); | ||
1214 | pthread_mutex_unlock(&adev->lock); | ||
1215 | return -ENODEV; | ||
1216 | } | ||
1217 | |||
1218 | /* if no supported sample rate is available, use the resampler */ | ||
1219 | if (in->resampler) { | ||
1220 | in->resampler->reset(in->resampler); | ||
1221 | in->frames_in = 0; | ||
1222 | } | ||
1223 | |||
1224 | in->standby = false; | ||
1225 | } | ||
1226 | |||
1227 | pthread_mutex_unlock(&adev->lock); | ||
1228 | |||
1229 | if (in->resampler || in->remix) | ||
1230 | ret = read_frames(in, buffer, frames); | ||
1231 | else | ||
1232 | ret = pcm_read(in->pcm, buffer, bytes); | ||
1233 | |||
1234 | if (ret < 0) { | ||
1235 | ALOGE("in_read() failed to read audio data %d", ret); | ||
1236 | usleep(read_usecs); /* limits the rate of error messages */ | ||
1237 | memset(buffer, 0, bytes); | ||
1238 | } else if (adev->mic_mute) { | ||
1239 | memset(buffer, 0, bytes); | ||
1240 | } | ||
1241 | |||
1242 | pthread_mutex_unlock(&in->lock); | ||
1243 | |||
1244 | return bytes; | ||
1245 | } | ||
1246 | |||
1247 | static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) | ||
1248 | { | ||
1249 | ALOGVV("in_get_input_frames_lost() stream=%p frames=%u", stream, 0); | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) | ||
1254 | { | ||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) | ||
1259 | { | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static int adev_open_output_stream(struct audio_hw_device *dev, | ||
1264 | audio_io_handle_t handle, | ||
1265 | audio_devices_t devices, | ||
1266 | audio_output_flags_t flags, | ||
1267 | struct audio_config *config, | ||
1268 | struct audio_stream_out **stream_out, | ||
1269 | const char *address __unused) | ||
1270 | { | ||
1271 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1272 | struct j6_stream_out *out; | ||
1273 | |||
1274 | out = (struct j6_stream_out *)malloc(sizeof(struct j6_stream_out)); | ||
1275 | if (!out) | ||
1276 | return -ENOMEM; | ||
1277 | |||
1278 | ALOGV("adev_open_output_stream() stream=%p rate=%u channels=%u " | ||
1279 | "format=0x%08x flags=0x%08x", | ||
1280 | out, config->sample_rate, popcount(config->channel_mask), | ||
1281 | config->format, flags); | ||
1282 | |||
1283 | pthread_mutex_init(&out->lock, NULL); | ||
1284 | |||
1285 | out->stream.common.get_sample_rate = out_get_sample_rate; | ||
1286 | out->stream.common.set_sample_rate = out_set_sample_rate; | ||
1287 | out->stream.common.get_buffer_size = out_get_buffer_size; | ||
1288 | out->stream.common.get_channels = out_get_channels; | ||
1289 | out->stream.common.get_format = out_get_format; | ||
1290 | out->stream.common.set_format = out_set_format; | ||
1291 | out->stream.common.standby = out_standby; | ||
1292 | out->stream.common.dump = out_dump; | ||
1293 | out->stream.common.set_parameters = out_set_parameters; | ||
1294 | out->stream.common.get_parameters = out_get_parameters; | ||
1295 | out->stream.common.add_audio_effect = out_add_audio_effect; | ||
1296 | out->stream.common.remove_audio_effect = out_remove_audio_effect; | ||
1297 | out->stream.get_latency = out_get_latency; | ||
1298 | out->stream.set_volume = out_set_volume; | ||
1299 | out->stream.write = out_write; | ||
1300 | out->stream.get_render_position = out_get_render_position; | ||
1301 | out->stream.get_next_write_timestamp = out_get_next_write_timestamp; | ||
1302 | out->stream.get_presentation_position = out_get_presentation_position; | ||
1303 | |||
1304 | out->dev = adev; | ||
1305 | out->standby = true; | ||
1306 | out->config = pcm_config_playback; | ||
1307 | out->written = 0; | ||
1308 | adev->out = out; | ||
1309 | |||
1310 | config->format = out_get_format(&out->stream.common); | ||
1311 | config->channel_mask = out_get_channels(&out->stream.common); | ||
1312 | config->sample_rate = out_get_sample_rate(&out->stream.common); | ||
1313 | |||
1314 | *stream_out = &out->stream; | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static void adev_close_output_stream(struct audio_hw_device *dev, | ||
1320 | struct audio_stream_out *stream) | ||
1321 | { | ||
1322 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1323 | struct j6_stream_out *out = (struct j6_stream_out *)(stream); | ||
1324 | |||
1325 | ALOGV("adev_close_output_stream() stream=%p", out); | ||
1326 | |||
1327 | out_standby(&stream->common); | ||
1328 | out->dev = NULL; | ||
1329 | adev->out = NULL; | ||
1330 | |||
1331 | free(stream); | ||
1332 | } | ||
1333 | |||
1334 | static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) | ||
1335 | { | ||
1336 | return -ENOSYS; | ||
1337 | } | ||
1338 | |||
1339 | static char * adev_get_parameters(const struct audio_hw_device *dev, | ||
1340 | const char *keys) | ||
1341 | { | ||
1342 | return strdup("");; | ||
1343 | } | ||
1344 | |||
1345 | static int adev_init_check(const struct audio_hw_device *dev) | ||
1346 | { | ||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) | ||
1351 | { | ||
1352 | return -ENOSYS; | ||
1353 | } | ||
1354 | |||
1355 | static int adev_set_master_volume(struct audio_hw_device *dev, float volume) | ||
1356 | { | ||
1357 | return -ENOSYS; | ||
1358 | } | ||
1359 | |||
1360 | static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) | ||
1361 | { | ||
1362 | return -ENOSYS; | ||
1363 | } | ||
1364 | |||
1365 | static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) | ||
1366 | { | ||
1367 | return -ENOSYS; | ||
1368 | } | ||
1369 | |||
1370 | static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) | ||
1371 | { | ||
1372 | return -ENOSYS; | ||
1373 | } | ||
1374 | |||
1375 | static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) | ||
1376 | { | ||
1377 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1378 | struct j6_stream_out *out = adev->out; | ||
1379 | int ret = 0; | ||
1380 | |||
1381 | ALOGV("adev_set_mode() mode=0x%08x", mode); | ||
1382 | |||
1383 | pthread_mutex_lock(&adev->lock); | ||
1384 | pthread_mutex_lock(&out->lock); | ||
1385 | |||
1386 | if (adev->mode == mode) { | ||
1387 | ALOGV("adev_set_mode() already in mode=0x%08x", mode); | ||
1388 | goto out; | ||
1389 | } | ||
1390 | |||
1391 | if (mode == AUDIO_MODE_IN_CALL) { | ||
1392 | ret = enter_voice_call(adev); | ||
1393 | if (ret) { | ||
1394 | ALOGE("adev_set_mode() failed to initialize voice call %d", ret); | ||
1395 | goto out; | ||
1396 | } | ||
1397 | } else if (adev->mode == AUDIO_MODE_IN_CALL) { | ||
1398 | leave_voice_call(adev); | ||
1399 | } | ||
1400 | |||
1401 | adev->mode = mode; | ||
1402 | |||
1403 | out: | ||
1404 | pthread_mutex_unlock(&out->lock); | ||
1405 | pthread_mutex_unlock(&adev->lock); | ||
1406 | |||
1407 | return ret; | ||
1408 | } | ||
1409 | |||
1410 | static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) | ||
1411 | { | ||
1412 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1413 | |||
1414 | ALOGV("adev_set_mic_mute() state=%s", state ? "mute" : "unmute"); | ||
1415 | adev->mic_mute = state; | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) | ||
1421 | { | ||
1422 | const struct j6_audio_device *adev = (const struct j6_audio_device *)dev; | ||
1423 | |||
1424 | *state = adev->mic_mute; | ||
1425 | ALOGV("adev_get_mic_mute() state=%s", *state ? "mute" : "unmute"); | ||
1426 | |||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, | ||
1431 | const struct audio_config *config) | ||
1432 | { | ||
1433 | size_t bytes = get_input_buffer_size(config->sample_rate, | ||
1434 | config->format, | ||
1435 | popcount(config->channel_mask)); | ||
1436 | |||
1437 | ALOGVV("adev_in_get_buffer_size() bytes=%u", bytes); | ||
1438 | |||
1439 | return bytes; | ||
1440 | } | ||
1441 | |||
1442 | static int adev_open_input_stream(struct audio_hw_device *dev, | ||
1443 | audio_io_handle_t handle, | ||
1444 | audio_devices_t devices, | ||
1445 | struct audio_config *config, | ||
1446 | struct audio_stream_in **stream_in, | ||
1447 | audio_input_flags_t flags __unused, | ||
1448 | const char *address __unused, | ||
1449 | audio_source_t source __unused) | ||
1450 | { | ||
1451 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1452 | struct j6_stream_in *in; | ||
1453 | int ret; | ||
1454 | |||
1455 | in = (struct j6_stream_in *)malloc(sizeof(struct j6_stream_in)); | ||
1456 | if (!in) | ||
1457 | return -ENOMEM; | ||
1458 | |||
1459 | ALOGV("adev_open_input_stream() stream=%p rate=%u channels=%u format=0x%08x", | ||
1460 | in, config->sample_rate, popcount(config->channel_mask), config->format); | ||
1461 | |||
1462 | pthread_mutex_init(&in->lock, NULL); | ||
1463 | |||
1464 | in->stream.common.get_sample_rate = in_get_sample_rate; | ||
1465 | in->stream.common.set_sample_rate = in_set_sample_rate; | ||
1466 | in->stream.common.get_buffer_size = in_get_buffer_size; | ||
1467 | in->stream.common.get_channels = in_get_channels; | ||
1468 | in->stream.common.get_format = in_get_format; | ||
1469 | in->stream.common.set_format = in_set_format; | ||
1470 | in->stream.common.standby = in_standby; | ||
1471 | in->stream.common.dump = in_dump; | ||
1472 | in->stream.common.set_parameters = in_set_parameters; | ||
1473 | in->stream.common.get_parameters = in_get_parameters; | ||
1474 | in->stream.common.add_audio_effect = in_add_audio_effect; | ||
1475 | in->stream.common.remove_audio_effect = in_remove_audio_effect; | ||
1476 | in->stream.set_gain = in_set_gain; | ||
1477 | in->stream.read = in_read; | ||
1478 | in->stream.get_input_frames_lost = in_get_input_frames_lost; | ||
1479 | |||
1480 | in->dev = adev; | ||
1481 | in->standby = true; | ||
1482 | in->config = pcm_config_capture; | ||
1483 | in->requested_rate = config->sample_rate; | ||
1484 | in->requested_channels = popcount(config->channel_mask); | ||
1485 | in->hw_frame_size = in->config.channels * sizeof(int16_t); | ||
1486 | in->remix = NULL; | ||
1487 | in->resampler = NULL; | ||
1488 | in->buffer = NULL; | ||
1489 | adev->in = in; | ||
1490 | |||
1491 | /* in-place stereo-to-mono remix since capture stream is stereo */ | ||
1492 | if (in->requested_channels == 1) { | ||
1493 | ALOGV("adev_open_input_stream() stereo-to-mono remix needed"); | ||
1494 | |||
1495 | /* | ||
1496 | * buffer size is already enough to allow stereo-to-mono remix | ||
1497 | * and resample if needed | ||
1498 | */ | ||
1499 | in->buffer = malloc(2 * in->config.period_size * in->hw_frame_size); | ||
1500 | if (!in->buffer) { | ||
1501 | ret = -ENOMEM; | ||
1502 | goto err1; | ||
1503 | } | ||
1504 | |||
1505 | ret = setup_stereo_to_mono_input_remix(in); | ||
1506 | if (ret) { | ||
1507 | ALOGE("adev_open_input_stream() failed to setup remix %d", ret); | ||
1508 | goto err2; | ||
1509 | } | ||
1510 | } | ||
1511 | |||
1512 | if (in->requested_rate != in->config.rate) { | ||
1513 | ALOGV("adev_open_input_stream() resample needed, req=%uHz got=%uHz", | ||
1514 | in->requested_rate, in->config.rate); | ||
1515 | |||
1516 | in->buf_provider.get_next_buffer = get_next_buffer; | ||
1517 | in->buf_provider.release_buffer = release_buffer; | ||
1518 | ret = create_resampler(in->config.rate, | ||
1519 | in->requested_rate, | ||
1520 | in->requested_channels, | ||
1521 | RESAMPLER_QUALITY_DEFAULT, | ||
1522 | &in->buf_provider, | ||
1523 | &in->resampler); | ||
1524 | if (ret) { | ||
1525 | ALOGE("adev_open_input_stream() failed to create resampler %d", ret); | ||
1526 | goto err3; | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | *stream_in = &in->stream; | ||
1531 | |||
1532 | return 0; | ||
1533 | |||
1534 | err3: | ||
1535 | free(in->remix); | ||
1536 | err2: | ||
1537 | free(in->buffer); | ||
1538 | err1: | ||
1539 | free(in); | ||
1540 | return ret; | ||
1541 | } | ||
1542 | |||
1543 | static void adev_close_input_stream(struct audio_hw_device *dev, | ||
1544 | struct audio_stream_in *stream) | ||
1545 | { | ||
1546 | struct j6_audio_device *adev = (struct j6_audio_device *)dev; | ||
1547 | struct j6_stream_in *in = (struct j6_stream_in *)(stream); | ||
1548 | |||
1549 | ALOGV("adev_close_input_stream() stream=%p", stream); | ||
1550 | |||
1551 | in_standby(&stream->common); | ||
1552 | |||
1553 | if (in->resampler) | ||
1554 | release_resampler(in->resampler); | ||
1555 | in->resampler = NULL; | ||
1556 | |||
1557 | if (in->remix) | ||
1558 | free(in->remix); | ||
1559 | in->remix = NULL; | ||
1560 | |||
1561 | in->dev = NULL; | ||
1562 | adev->in = NULL; | ||
1563 | |||
1564 | free(in->buffer); | ||
1565 | free(in); | ||
1566 | } | ||
1567 | |||
1568 | static int adev_dump(const audio_hw_device_t *device, int fd) | ||
1569 | { | ||
1570 | return 0; | ||
1571 | } | ||
1572 | |||
1573 | /* | ||
1574 | * should not be needed for API version 2.0 but AudioFlinger uses it to find | ||
1575 | * suitable hw device, so we keep it | ||
1576 | */ | ||
1577 | static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) | ||
1578 | { | ||
1579 | uint32_t devices = SUPPORTED_IN_DEVICES | SUPPORTED_OUT_DEVICES; | ||
1580 | |||
1581 | ALOGV("adev_get_supported_devices() devices=0x%08x", devices); | ||
1582 | |||
1583 | return devices; | ||
1584 | } | ||
1585 | |||
1586 | static int adev_close(hw_device_t *device) | ||
1587 | { | ||
1588 | struct j6_audio_device *adev = (struct j6_audio_device *)device; | ||
1589 | |||
1590 | ALOGI("adev_close()"); | ||
1591 | |||
1592 | audio_route_free(adev->route); | ||
1593 | free(device); | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | static int adev_open(const hw_module_t* module, const char* name, | ||
1599 | hw_device_t** device) | ||
1600 | { | ||
1601 | struct j6_audio_device *adev; | ||
1602 | |||
1603 | ALOGI("adev_open() %s", name); | ||
1604 | |||
1605 | if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) | ||
1606 | return -EINVAL; | ||
1607 | |||
1608 | adev = (struct j6_audio_device*)malloc(sizeof(struct j6_audio_device)); | ||
1609 | if (!adev) | ||
1610 | return -ENOMEM; | ||
1611 | |||
1612 | pthread_mutex_init(&adev->lock, NULL); | ||
1613 | |||
1614 | adev->device.common.tag = HARDWARE_DEVICE_TAG; | ||
1615 | adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; | ||
1616 | adev->device.common.module = (struct hw_module_t *) module; | ||
1617 | adev->device.common.close = adev_close; | ||
1618 | |||
1619 | adev->device.get_supported_devices = adev_get_supported_devices; | ||
1620 | adev->device.init_check = adev_init_check; | ||
1621 | adev->device.set_voice_volume = adev_set_voice_volume; | ||
1622 | adev->device.set_master_volume = adev_set_master_volume; | ||
1623 | adev->device.get_master_volume = adev_get_master_volume; | ||
1624 | adev->device.set_master_mute = adev_set_master_mute; | ||
1625 | adev->device.get_master_mute = adev_get_master_mute; | ||
1626 | adev->device.set_mode = adev_set_mode; | ||
1627 | adev->device.set_mic_mute = adev_set_mic_mute; | ||
1628 | adev->device.get_mic_mute = adev_get_mic_mute; | ||
1629 | adev->device.set_parameters = adev_set_parameters; | ||
1630 | adev->device.get_parameters = adev_get_parameters; | ||
1631 | adev->device.get_input_buffer_size = adev_get_input_buffer_size; | ||
1632 | adev->device.open_output_stream = adev_open_output_stream; | ||
1633 | adev->device.close_output_stream = adev_close_output_stream; | ||
1634 | adev->device.open_input_stream = adev_open_input_stream; | ||
1635 | adev->device.close_input_stream = adev_close_input_stream; | ||
1636 | adev->device.dump = adev_dump; | ||
1637 | |||
1638 | adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC; | ||
1639 | adev->out_device = AUDIO_DEVICE_OUT_SPEAKER; | ||
1640 | adev->card = find_supported_card(); | ||
1641 | adev->in_port = 0; | ||
1642 | adev->out_port = 0; | ||
1643 | adev->bt_port = 2; | ||
1644 | adev->mic_mute = false; | ||
1645 | adev->in_call = false; | ||
1646 | adev->mode = AUDIO_MODE_NORMAL; | ||
1647 | |||
1648 | adev->route = audio_route_init(adev->card, NULL); | ||
1649 | if (!adev->route) { | ||
1650 | ALOGE("Unable to initialize audio routes"); | ||
1651 | free(adev); | ||
1652 | return -EINVAL; | ||
1653 | } | ||
1654 | |||
1655 | *device = &adev->device.common; | ||
1656 | |||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | static struct hw_module_methods_t hal_module_methods = { | ||
1661 | .open = adev_open, | ||
1662 | }; | ||
1663 | |||
1664 | struct audio_module HAL_MODULE_INFO_SYM = { | ||
1665 | .common = { | ||
1666 | .tag = HARDWARE_MODULE_TAG, | ||
1667 | .module_api_version = AUDIO_MODULE_API_VERSION_0_1, | ||
1668 | .hal_api_version = HARDWARE_HAL_API_VERSION, | ||
1669 | .id = AUDIO_HARDWARE_MODULE_ID, | ||
1670 | .name = "Jacinto6 Audio HAL", | ||
1671 | .author = "Texas Instruments Inc.", | ||
1672 | .methods = &hal_module_methods, | ||
1673 | }, | ||
1674 | }; | ||
diff --git a/audio/legacy/audio_policy.conf b/audio/legacy/audio_policy.conf new file mode 100644 index 0000000..a806163 --- /dev/null +++ b/audio/legacy/audio_policy.conf | |||
@@ -0,0 +1,94 @@ | |||
1 | # Global configuration section: lists input and output devices always present on the device | ||
2 | # as well as the output device selected by default. | ||
3 | # Devices are designated by a string that corresponds to the enum in audio.h | ||
4 | |||
5 | global_configuration { | ||
6 | attached_output_devices AUDIO_DEVICE_OUT_SPEAKER | ||
7 | default_output_device AUDIO_DEVICE_OUT_SPEAKER | ||
8 | attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC | ||
9 | } | ||
10 | |||
11 | # audio hardware module section: contains descriptors for all audio hw modules present on the | ||
12 | # device. Each hw module node is named after the corresponding hw module library base name. | ||
13 | # For instance, "primary" corresponds to audio.primary.<device>.so. | ||
14 | # The "primary" module is mandatory and must include at least one output with | ||
15 | # AUDIO_OUTPUT_FLAG_PRIMARY flag. | ||
16 | # Each module descriptor contains one or more output profile descriptors and zero or more | ||
17 | # input profile descriptors. Each profile lists all the parameters supported by a given output | ||
18 | # or input stream category. | ||
19 | # The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding | ||
20 | # to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n". | ||
21 | |||
22 | audio_hw_modules { | ||
23 | primary { | ||
24 | outputs { | ||
25 | primary { | ||
26 | sampling_rates 44100 | ||
27 | channel_masks AUDIO_CHANNEL_OUT_STEREO | ||
28 | formats AUDIO_FORMAT_PCM_16_BIT | ||
29 | devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE | ||
30 | flags AUDIO_OUTPUT_FLAG_PRIMARY | ||
31 | } | ||
32 | } | ||
33 | inputs { | ||
34 | primary { | ||
35 | sampling_rates 8000|11025|16000|22050|32000|44100|48000 | ||
36 | channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO | ||
37 | formats AUDIO_FORMAT_PCM_16_BIT | ||
38 | devices AUDIO_DEVICE_IN_BUILTIN_MIC | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | hdmi { | ||
43 | outputs { | ||
44 | stereo { | ||
45 | sampling_rates 44100|48000 | ||
46 | channel_masks AUDIO_CHANNEL_OUT_STEREO | ||
47 | formats AUDIO_FORMAT_PCM_16_BIT | ||
48 | devices AUDIO_DEVICE_OUT_AUX_DIGITAL | ||
49 | } | ||
50 | multichannel { | ||
51 | sampling_rates 44100|48000 | ||
52 | channel_masks dynamic | ||
53 | formats AUDIO_FORMAT_PCM_16_BIT | ||
54 | devices AUDIO_DEVICE_OUT_AUX_DIGITAL | ||
55 | flags AUDIO_OUTPUT_FLAG_DIRECT | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | a2dp { | ||
60 | outputs { | ||
61 | a2dp { | ||
62 | sampling_rates 44100 | ||
63 | channel_masks AUDIO_CHANNEL_OUT_STEREO | ||
64 | formats AUDIO_FORMAT_PCM_16_BIT | ||
65 | devices AUDIO_DEVICE_OUT_ALL_A2DP | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | r_submix { | ||
70 | outputs { | ||
71 | r_submix { | ||
72 | sampling_rates 44100|48000 | ||
73 | channel_masks AUDIO_CHANNEL_OUT_STEREO | ||
74 | formats AUDIO_FORMAT_PCM_16_BIT | ||
75 | devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX | ||
76 | } | ||
77 | multichannel { | ||
78 | sampling_rates 44100|48000 | ||
79 | channel_masks AUDIO_CHANNEL_OUT_5POINT1 | ||
80 | formats AUDIO_FORMAT_PCM_16_BIT | ||
81 | devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX | ||
82 | flags AUDIO_OUTPUT_FLAG_DIRECT | ||
83 | } | ||
84 | } | ||
85 | inputs { | ||
86 | r_submix { | ||
87 | sampling_rates 44100|48000 | ||
88 | channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_5POINT1EMUL | ||
89 | formats AUDIO_FORMAT_PCM_16_BIT | ||
90 | devices AUDIO_DEVICE_IN_REMOTE_SUBMIX | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | } | ||
diff --git a/audio/mixer_paths.xml b/audio/mixer_paths.xml new file mode 100644 index 0000000..09949fa --- /dev/null +++ b/audio/mixer_paths.xml | |||
@@ -0,0 +1,85 @@ | |||
1 | <mixer> | ||
2 | |||
3 | <!-- Card default routes --> | ||
4 | |||
5 | <!-- Capture: Mic --> | ||
6 | <ctl name="Left PGA Mixer Mic3L Switch" value="1" /> | ||
7 | <ctl name="Right PGA Mixer Mic3R Switch" value="1" /> | ||
8 | <ctl name="PGA Capture Switch" value="1" /> | ||
9 | <ctl name="PGA Capture Volume" value="24" /> | ||
10 | <ctl name="Left Line1L Mux" value="single-ended" /> | ||
11 | <ctl name="Right Line1L Mux" value="single-ended" /> | ||
12 | <ctl name="Left Line1R Mux" value="single-ended" /> | ||
13 | <ctl name="Right Line1R Mux" value="single-ended" /> | ||
14 | |||
15 | <!-- Playback: Line-Out and Headphone --> | ||
16 | <ctl name="Left DAC Mux" value="DAC_L1" /> | ||
17 | <ctl name="Right DAC Mux" value="DAC_R1" /> | ||
18 | <ctl name="PCM Playback Volume" value="127" /> | ||
19 | |||
20 | <ctl name="Left HP Mixer DACL1 Switch" value="1" /> | ||
21 | <ctl name="Right HP Mixer DACR1 Switch" value="1" /> | ||
22 | <ctl name="HP Playback Switch" value="1" /> | ||
23 | <ctl name="HP DAC Playback Volume" value="118" /> | ||
24 | <ctl name="Output Driver Power-On time" value="200ms" /> | ||
25 | |||
26 | <ctl name="Left Line Mixer DACL1 Switch" value="1" /> | ||
27 | <ctl name="Right Line Mixer DACR1 Switch" value="1" /> | ||
28 | <ctl name="Line Playback Switch" value="1" /> | ||
29 | <ctl name="Line DAC Playback Volume" value="118" /> | ||
30 | |||
31 | <!-- JAMR3 board, codec-A input: Line-In --> | ||
32 | <ctl name="J3A Left PGA Mixer Line1L Switch" value="1" /> | ||
33 | <ctl name="J3A Right PGA Mixer Line1R Switch" value="1" /> | ||
34 | <ctl name="J3A PGA Capture Switch" value="1" /> | ||
35 | <ctl name="J3A PGA Capture Volume" value="0" /> | ||
36 | <ctl name="J3A Left Line1L Mux" value="differential" /> | ||
37 | <ctl name="J3A Right Line1L Mux" value="differential" /> | ||
38 | <ctl name="J3A Left Line1R Mux" value="differential" /> | ||
39 | <ctl name="J3A Right Line1R Mux" value="differential" /> | ||
40 | |||
41 | <!-- JAMR3 board, codec-B input: Mic --> | ||
42 | <ctl name="J3B Left PGA Mixer Line1L Switch" value="1" /> | ||
43 | <ctl name="J3B Right PGA Mixer Line1R Switch" value="1" /> | ||
44 | <ctl name="J3B PGA Capture Switch" value="1" /> | ||
45 | <ctl name="J3B PGA Capture Volume" value="0" /> | ||
46 | <ctl name="J3B Left Line1L Mux" value="differential" /> | ||
47 | <ctl name="J3B Right Line1L Mux" value="differential" /> | ||
48 | <ctl name="J3B Left Line1R Mux" value="differential" /> | ||
49 | <ctl name="J3B Right Line1R Mux" value="differential" /> | ||
50 | |||
51 | <!-- JAMR3 board, codec-A output: Line-Out --> | ||
52 | <ctl name="J3A Left DAC Mux" value="DAC_L1" /> | ||
53 | <ctl name="J3A Right DAC Mux" value="DAC_R1" /> | ||
54 | <ctl name="J3A Left Line Mixer DACL1 Switch" value="1" /> | ||
55 | <ctl name="J3A Right Line Mixer DACR1 Switch" value="1" /> | ||
56 | <ctl name="J3A Line DAC Playback Volume" value="118" /> | ||
57 | <ctl name="J3A Line Playback Switch" value="1" /> | ||
58 | <ctl name="J3A PCM Playback Volume" value="127" /> | ||
59 | |||
60 | <!-- JAMR3 board, codec-B Output: Line-Out --> | ||
61 | <ctl name="J3B Left DAC Mux" value="DAC_L1" /> | ||
62 | <ctl name="J3B Right DAC Mux" value="DAC_R1" /> | ||
63 | <ctl name="J3B Left Line Mixer DACL1 Switch" value="1" /> | ||
64 | <ctl name="J3B Right Line Mixer DACR1 Switch" value="1" /> | ||
65 | <ctl name="J3B Line DAC Playback Volume" value="118" /> | ||
66 | <ctl name="J3B Line Playback Switch" value="1" /> | ||
67 | <ctl name="J3B PCM Playback Volume" value="127" /> | ||
68 | |||
69 | <!-- JAMR3 board, codec-C Output: Line-Out --> | ||
70 | <ctl name="J3C Left DAC Mux" value="DAC_L1" /> | ||
71 | <ctl name="J3C Right DAC Mux" value="DAC_R1" /> | ||
72 | <ctl name="J3C Left Line Mixer DACL1 Switch" value="1" /> | ||
73 | <ctl name="J3C Right Line Mixer DACR1 Switch" value="1" /> | ||
74 | <ctl name="J3C Line DAC Playback Volume" value="118" /> | ||
75 | <ctl name="J3C Line Playback Switch" value="1" /> | ||
76 | <ctl name="J3C PCM Playback Volume" value="127" /> | ||
77 | |||
78 | <!-- Bluetooth --> | ||
79 | <ctl name="Bluetooth Mode" value="Slave" /> | ||
80 | |||
81 | <path name="BT SCO Master"> | ||
82 | <ctl name="Bluetooth Mode" value="Master" /> | ||
83 | </path> | ||
84 | |||
85 | </mixer> | ||
diff --git a/audio/multizone/Android.mk b/audio/multizone/Android.mk new file mode 100644 index 0000000..bf1c4d7 --- /dev/null +++ b/audio/multizone/Android.mk | |||
@@ -0,0 +1,53 @@ | |||
1 | # Copyright (C) 2013 Texas Instruments | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | LOCAL_PATH := $(call my-dir) | ||
16 | |||
17 | include $(CLEAR_VARS) | ||
18 | LOCAL_MODULE := audio_policy.conf | ||
19 | LOCAL_MODULE_TAGS := optional | ||
20 | LOCAL_MODULE_CLASS := ETC | ||
21 | LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) | ||
22 | LOCAL_SRC_FILES := $(LOCAL_MODULE) | ||
23 | include $(BUILD_PREBUILT) | ||
24 | |||
25 | include $(CLEAR_VARS) | ||
26 | |||
27 | LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) | ||
28 | |||
29 | LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw | ||
30 | |||
31 | LOCAL_SRC_FILES := \ | ||
32 | AudioHw.cpp \ | ||
33 | audio_hw.cpp | ||
34 | |||
35 | LOCAL_C_INCLUDES += \ | ||
36 | system/media/audio_utils/include \ | ||
37 | system/media/audio_effects/include \ | ||
38 | device/ti/common-open/audio/utils/include | ||
39 | |||
40 | LOCAL_SHARED_LIBRARIES := \ | ||
41 | liblog \ | ||
42 | libtiaudioutils \ | ||
43 | libcutils \ | ||
44 | libutils | ||
45 | |||
46 | LOCAL_SHARED_LIBRARIES += libstlport | ||
47 | include external/stlport/libstlport.mk | ||
48 | |||
49 | LOCAL_STATIC_LIBRARIES := libmedia_helper | ||
50 | |||
51 | LOCAL_MODULE_TAGS := optional | ||
52 | |||
53 | include $(BUILD_SHARED_LIBRARY) | ||
diff --git a/audio/multizone/AudioHw.cpp b/audio/multizone/AudioHw.cpp new file mode 100644 index 0000000..38d06ed --- /dev/null +++ b/audio/multizone/AudioHw.cpp | |||
@@ -0,0 +1,1276 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Texas Instruments | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #define LOG_TAG "AudioHw" | ||
18 | // #define LOG_NDEBUG 0 | ||
19 | // #define VERY_VERBOSE_LOGGING | ||
20 | #ifdef VERY_VERBOSE_LOGGING | ||
21 | #define ALOGVV ALOGV | ||
22 | #else | ||
23 | #define ALOGVV(...) do { } while(0) | ||
24 | #endif | ||
25 | |||
26 | #include <cutils/log.h> | ||
27 | #include <cutils/properties.h> | ||
28 | #include <media/AudioParameter.h> | ||
29 | |||
30 | #include <AudioHw.h> | ||
31 | |||
32 | namespace android { | ||
33 | |||
34 | AudioStreamOut::AudioStreamOut(AudioHwDevice *hwDev, | ||
35 | PcmWriter *writer, | ||
36 | const PcmParams ¶ms, | ||
37 | const SlotMap &map, | ||
38 | audio_devices_t devices) | ||
39 | : mHwDev(hwDev), mNullWriter(&mNullPort, params), mWriter(writer), | ||
40 | mParams(params), mDevices(devices), mStandby(true), mUsedForVoiceCall(false) | ||
41 | { | ||
42 | if (mWriter) | ||
43 | mStream = new AdaptedOutStream(params, map); | ||
44 | } | ||
45 | |||
46 | int AudioStreamOut::initCheck() const | ||
47 | { | ||
48 | int ret = 0; | ||
49 | |||
50 | if (!mHwDev) { | ||
51 | ALOGE("AudioStreamOut: initCheck() invalid AudioHwDevice"); | ||
52 | ret = -ENODEV; | ||
53 | } | ||
54 | else if (!mWriter || !mWriter->initCheck()) { | ||
55 | ALOGE("AudioStreamOut: initCheck() invalid PCM writer"); | ||
56 | ret = -ENODEV; | ||
57 | } | ||
58 | else if (mStream == NULL || !mStream->initCheck()) { | ||
59 | ALOGE("AudioStreamOut: initCheck() invalid Out Stream"); | ||
60 | ret = -ENODEV; | ||
61 | } | ||
62 | |||
63 | ALOGV("AudioStreamOut: init check %d", ret); | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | uint32_t AudioStreamOut::getSampleRate() const | ||
69 | { | ||
70 | uint32_t rate = mParams.sampleRate; | ||
71 | |||
72 | ALOGVV("AudioStreamOut: getSampleRate() %u Hz", rate); | ||
73 | |||
74 | return rate; | ||
75 | } | ||
76 | |||
77 | int AudioStreamOut::setSampleRate(uint32_t rate) | ||
78 | { | ||
79 | ALOGV("AudioStreamOut: setSampleRate() %u Hz", rate); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | size_t AudioStreamOut::getBufferSize() const | ||
85 | { | ||
86 | size_t size; | ||
87 | |||
88 | /* Take resampling ratio into account and align to the nearest | ||
89 | * 16 frames as required by the AudioFlinger */ | ||
90 | size = (mParams.frameCount * mParams.sampleRate) / mWriter->getParams().sampleRate; | ||
91 | size = ((size + 15) & ~15) * mParams.frameSize(); | ||
92 | |||
93 | ALOGVV("AudioStreamOut: getBufferSize() %u bytes", size); | ||
94 | |||
95 | return size; | ||
96 | } | ||
97 | |||
98 | audio_channel_mask_t AudioStreamOut::getChannels() const | ||
99 | { | ||
100 | uint32_t channels = mParams.channels; | ||
101 | |||
102 | ALOGVV("AudioStreamOut: getChannels() %u channels", channels); | ||
103 | |||
104 | return audio_channel_out_mask_from_count(channels); | ||
105 | } | ||
106 | |||
107 | audio_format_t AudioStreamOut::getFormat() const | ||
108 | { | ||
109 | uint32_t sampleBits = mParams.sampleBits; | ||
110 | |||
111 | ALOGVV("AudioStreamOut: getFormat() %u bits/sample", sampleBits); | ||
112 | |||
113 | switch (sampleBits) { | ||
114 | case 8: | ||
115 | return AUDIO_FORMAT_PCM_8_BIT; | ||
116 | case 24: | ||
117 | return AUDIO_FORMAT_PCM_8_24_BIT; | ||
118 | case 32: | ||
119 | return AUDIO_FORMAT_PCM_32_BIT; | ||
120 | case 16: | ||
121 | default: | ||
122 | return AUDIO_FORMAT_PCM_16_BIT; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | int AudioStreamOut::setFormat(audio_format_t format) | ||
127 | { | ||
128 | ALOGV("AudioStreamOut: setFormat() %u bits/sample", | ||
129 | audio_bytes_per_sample(format) * 8); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* must be called with mLock */ | ||
135 | int AudioStreamOut::resume() | ||
136 | { | ||
137 | ALOGV("AudioStreamOut: resume using %s writer", | ||
138 | mUsedForVoiceCall ? "null" : "regular"); | ||
139 | |||
140 | /* | ||
141 | * Switching PCM writers is done under the assumption that the non-null | ||
142 | * writer (mWriter) is always open (but possibly in standby), which is | ||
143 | * achieved by using the primary output for voice calls. | ||
144 | */ | ||
145 | PcmWriter *writer; | ||
146 | if (mUsedForVoiceCall) | ||
147 | writer = &mNullWriter; | ||
148 | else | ||
149 | writer = mWriter; | ||
150 | |||
151 | int ret = writer->registerStream(mStream); | ||
152 | if (ret) { | ||
153 | ALOGE("AudioStreamOut: failed to register stream %d", ret); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | ret = mStream->start(); | ||
158 | if (ret) { | ||
159 | ALOGE("AudioStreamOut: failed to start stream %d", ret); | ||
160 | writer->unregisterStream(mStream); | ||
161 | } | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | /* must be called with mLock */ | ||
167 | void AudioStreamOut::idle() | ||
168 | { | ||
169 | ALOGV("AudioStreamOut: idle using %s writer", | ||
170 | mUsedForVoiceCall ? "null" : "regular"); | ||
171 | |||
172 | PcmWriter *writer; | ||
173 | if (mUsedForVoiceCall) | ||
174 | writer = &mNullWriter; | ||
175 | else | ||
176 | writer = mWriter; | ||
177 | |||
178 | mStream->stop(); | ||
179 | writer->unregisterStream(mStream); | ||
180 | } | ||
181 | |||
182 | int AudioStreamOut::standby() | ||
183 | { | ||
184 | ALOGV("AudioStreamOut: standby()"); | ||
185 | |||
186 | AutoMutex lock(mLock); | ||
187 | |||
188 | if (!mStandby) { | ||
189 | idle(); | ||
190 | mStandby = true; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | void AudioStreamOut::setVoiceCall(bool on) | ||
197 | { | ||
198 | ALOGV("AudioStreamOut: setVoiceCall() %s", on ? "enter" : "leave"); | ||
199 | |||
200 | AutoMutex lock(mLock); | ||
201 | |||
202 | /* | ||
203 | * Voice call reuses one of the PCM writers that is otherwise used | ||
204 | * for media. Media has to be re-routed to a null writer (that only | ||
205 | * consumes the data but doesn't write it to the hardware) when the | ||
206 | * voice call starts and routed back to the actual writer when the | ||
207 | * voice call stops. | ||
208 | * Temporarily entering standby helps transitioning to the null writer | ||
209 | * the next time that data is written to the stream if the voice call | ||
210 | * occurs at mid-stream. | ||
211 | */ | ||
212 | if (mUsedForVoiceCall != on) { | ||
213 | if (!mStandby) { | ||
214 | idle(); | ||
215 | mStandby = true; | ||
216 | } | ||
217 | mUsedForVoiceCall = on; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | int AudioStreamOut::dump(int fd) const | ||
222 | { | ||
223 | ALOGV("AudioStreamOut: dump()"); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | audio_devices_t AudioStreamOut::getDevice() const | ||
228 | { | ||
229 | ALOGV("AudioStreamOut: getDevice()"); | ||
230 | return mDevices; | ||
231 | } | ||
232 | |||
233 | int AudioStreamOut::setParameters(const char *kv_pairs) | ||
234 | { | ||
235 | ALOGV("AudioStreamOut: setParameters() '%s'", kv_pairs ? kv_pairs : ""); | ||
236 | |||
237 | int ret; | ||
238 | |||
239 | AudioParameter parms = AudioParameter(String8(kv_pairs)); | ||
240 | String8 key = String8(AudioParameter::keyRouting); | ||
241 | int device; | ||
242 | |||
243 | if ((ret = parms.getInt(key, device)) == NO_ERROR) { | ||
244 | if ((mDevices & AUDIO_DEVICE_OUT_ALL) != (unsigned int)device) { | ||
245 | standby(); | ||
246 | } | ||
247 | if (device & ~(mHwDev->getSupportedDevices())) { | ||
248 | ALOGW("AudioStreamOut: setParameters() device(s) not supported, " | ||
249 | "will use default devices"); | ||
250 | } | ||
251 | else | ||
252 | mDevices = device; | ||
253 | } | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | char *AudioStreamOut::getParameters(const char *keys) const | ||
259 | { | ||
260 | ALOGV("AudioStreamOut::getParameters()"); | ||
261 | return NULL; | ||
262 | } | ||
263 | |||
264 | int AudioStreamOut::addAudioEffect(effect_handle_t effect) const | ||
265 | { | ||
266 | ALOGV("AudioStreamOut: addAudioEffects()"); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | int AudioStreamOut::removeAudioEffect(effect_handle_t effect) const | ||
271 | { | ||
272 | ALOGV("AudioStreamOut: removeAudioEffects()"); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | uint32_t AudioStreamOut::getLatency() const | ||
277 | { | ||
278 | uint32_t latency = (1000 * getBufferSize()) / mWriter->getParams().sampleRate; | ||
279 | |||
280 | ALOGVV("AudioStreamOut: getLatency() %u ms", latency); | ||
281 | |||
282 | return latency; | ||
283 | } | ||
284 | |||
285 | int AudioStreamOut::setVolume(float left, float right) | ||
286 | { | ||
287 | ALOGV("AudioStreamOut: setVolume() left=%.4f right=%.4f", left, right); | ||
288 | return -ENOSYS; | ||
289 | } | ||
290 | |||
291 | ssize_t AudioStreamOut::write(const void* buffer, size_t bytes) | ||
292 | { | ||
293 | uint32_t frames = mParams.bytesToFrames(bytes); | ||
294 | int ret = 0; | ||
295 | uint32_t usecs = (frames * 1000000) / mParams.sampleRate; | ||
296 | |||
297 | ALOGVV("AudioStreamOut: write %u frames (%u bytes) buffer %p", | ||
298 | frames, bytes, buffer); | ||
299 | |||
300 | AutoMutex lock(mLock); | ||
301 | |||
302 | if (mStandby) { | ||
303 | ret = resume(); | ||
304 | if (ret) { | ||
305 | ALOGE("AudioStreamOut: failed to resume stream %d", ret); | ||
306 | usleep(usecs); /* limits the rate of error messages */ | ||
307 | return ret; | ||
308 | } | ||
309 | mStandby = false; | ||
310 | } | ||
311 | |||
312 | ret = mStream->write(buffer, frames); | ||
313 | if (ret < 0) { | ||
314 | ALOGE("AudioStreamOut: failed to write data %d", ret); | ||
315 | usleep(usecs); | ||
316 | } else { | ||
317 | ALOGW_IF(ret != (int)frames, | ||
318 | "AudioStreamOut: wrote only %d out of %d requested frames", | ||
319 | ret, frames); | ||
320 | bytes = mParams.framesToBytes(ret); | ||
321 | } | ||
322 | |||
323 | return bytes; | ||
324 | } | ||
325 | |||
326 | int AudioStreamOut::getRenderPosition(uint32_t *dsp_frames) const | ||
327 | { | ||
328 | ALOGV("AudioStreamOut: getRenderPosition()"); | ||
329 | |||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | int AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp) const | ||
334 | { | ||
335 | ALOGVV("AudioStreamOut: getNextWriteTimestamp()"); | ||
336 | |||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | /* ---------------------------------------------------------------------------------------- */ | ||
341 | |||
342 | AudioStreamIn::AudioStreamIn(AudioHwDevice *hwDev, | ||
343 | PcmReader *reader, | ||
344 | const PcmParams ¶ms, | ||
345 | const SlotMap &map, | ||
346 | audio_devices_t devices) | ||
347 | : mHwDev(hwDev), mReader(reader), mParams(params), mDevices(devices), | ||
348 | mSource(AUDIO_SOURCE_DEFAULT), mStandby(true) | ||
349 | { | ||
350 | if (mReader) | ||
351 | mStream = new AdaptedInStream(params, map); | ||
352 | } | ||
353 | |||
354 | int AudioStreamIn::initCheck() const | ||
355 | { | ||
356 | int ret = 0; | ||
357 | |||
358 | if (!mHwDev) { | ||
359 | ALOGE("AudioStreamIn: initCheck() invalid AudioHwDevice"); | ||
360 | ret = -ENODEV; | ||
361 | } | ||
362 | else if (!mReader || !mReader->initCheck()) { | ||
363 | ALOGE("AudioStreamIn: initCheck() invalid PCM reader"); | ||
364 | ret = -ENODEV; | ||
365 | } | ||
366 | else if (mStream == NULL || !mStream->initCheck()) { | ||
367 | ALOGE("AudioStreamIn: initCheck() invalid In Stream"); | ||
368 | ret = -ENODEV; | ||
369 | } | ||
370 | |||
371 | ALOGV("AudioStreamIn: init check %d", ret); | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | uint32_t AudioStreamIn::getSampleRate() const | ||
377 | { | ||
378 | ALOGV("AudioStreamIn: getSampleRate()"); | ||
379 | |||
380 | uint32_t rate = mParams.sampleRate; | ||
381 | |||
382 | return rate; | ||
383 | } | ||
384 | |||
385 | int AudioStreamIn::setSampleRate(uint32_t rate) | ||
386 | { | ||
387 | ALOGV("AudioStreamIn: setSampleRate() %u Hz", rate); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | size_t AudioStreamIn::getBufferSize() const | ||
393 | { | ||
394 | size_t size; | ||
395 | |||
396 | /* Take resampling ratio into account */ | ||
397 | size = (mParams.frameCount * mParams.sampleRate) / mReader->getParams().sampleRate; | ||
398 | size = size * mParams.frameSize(); | ||
399 | |||
400 | ALOGVV("AudioStreamIn: getBufferSize() %u bytes", size); | ||
401 | |||
402 | return size; | ||
403 | } | ||
404 | |||
405 | audio_channel_mask_t AudioStreamIn::getChannels() const | ||
406 | { | ||
407 | ALOGV("AudioStreamIn: getChannels()"); | ||
408 | |||
409 | return audio_channel_in_mask_from_count(mParams.channels); | ||
410 | } | ||
411 | |||
412 | audio_format_t AudioStreamIn::getFormat() const | ||
413 | { | ||
414 | ALOGV("AudioStreamIn: getFormat()"); | ||
415 | |||
416 | return AUDIO_FORMAT_PCM_16_BIT; | ||
417 | } | ||
418 | |||
419 | int AudioStreamIn::setFormat(audio_format_t format) | ||
420 | { | ||
421 | ALOGV("AudioStreamIn: setFormat()"); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | /* must be called with mLock */ | ||
427 | int AudioStreamIn::resume() | ||
428 | { | ||
429 | int ret = mReader->registerStream(mStream); | ||
430 | if (ret) { | ||
431 | ALOGE("AudioStreamIn: failed to register Dest %d", ret); | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | ret = mStream->start(); | ||
436 | if (ret) { | ||
437 | ALOGE("AudioStreamIn: failed to start stream %d", ret); | ||
438 | mReader->unregisterStream(mStream); | ||
439 | } | ||
440 | |||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | /* must be called with mLock */ | ||
445 | void AudioStreamIn::idle() | ||
446 | { | ||
447 | mStream->stop(); | ||
448 | mReader->unregisterStream(mStream); | ||
449 | } | ||
450 | |||
451 | int AudioStreamIn::standby() | ||
452 | { | ||
453 | ALOGV("AudioStreamIn: standby()"); | ||
454 | |||
455 | AutoMutex lock(mLock); | ||
456 | |||
457 | if (!mStandby) { | ||
458 | idle(); | ||
459 | mStandby = true; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | int AudioStreamIn::dump(int fd) const | ||
466 | { | ||
467 | ALOGV("AudioStreamIn: dump()"); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | audio_devices_t AudioStreamIn::getDevice() const | ||
473 | { | ||
474 | ALOGV("AudioStreamIn: getDevice()"); | ||
475 | |||
476 | return mDevices; | ||
477 | } | ||
478 | |||
479 | int AudioStreamIn::setParameters(const char *kv_pairs) | ||
480 | { | ||
481 | ALOGV("AudioStreamIn: setParameters() '%s'", kv_pairs ? kv_pairs : ""); | ||
482 | |||
483 | int ret; | ||
484 | |||
485 | AudioParameter parms = AudioParameter(String8(kv_pairs)); | ||
486 | String8 source_key = String8(AudioParameter::keyInputSource); | ||
487 | String8 device_key = String8(AudioParameter::keyRouting); | ||
488 | int source, device; | ||
489 | |||
490 | if ((ret = parms.getInt(source_key, source)) == NO_ERROR) { | ||
491 | /* no audio source uses 0 */ | ||
492 | if ((mSource != (unsigned int)source) && | ||
493 | (source != 0) && | ||
494 | (source < AUDIO_SOURCE_CNT)) { | ||
495 | ALOGV("AudioStreamIn: setParameters() source changed [%d]->[%d]", | ||
496 | mSource, source); | ||
497 | mSource = (audio_source_t)source; | ||
498 | /* Nothing to do for AUDIO_PARAMETER_STREAM_INPUT_SOURCE, so only | ||
499 | * record the source and continue */ | ||
500 | } | ||
501 | } | ||
502 | |||
503 | if ((ret = parms.getInt(device_key, device)) == NO_ERROR) { | ||
504 | if ((mDevices & AUDIO_DEVICE_IN_ALL) != (unsigned int)device) { | ||
505 | standby(); | ||
506 | } | ||
507 | if (device & ~(mHwDev->getSupportedDevices())) { | ||
508 | ALOGW("AudioStreamIn: setParameters() device(s) not supported, " | ||
509 | "will use default devices"); | ||
510 | } | ||
511 | else { | ||
512 | mDevices = device; | ||
513 | ALOGV("AudioStreamIn: setParameters() device set to [0x%x]", | ||
514 | mDevices); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | char *AudioStreamIn::getParameters(const char *keys) const | ||
522 | { | ||
523 | ALOGV("AudioStreamIn: getParameters()"); | ||
524 | |||
525 | return NULL; | ||
526 | } | ||
527 | |||
528 | int AudioStreamIn::addAudioEffect(effect_handle_t effect) const | ||
529 | { | ||
530 | ALOGV("AudioStreamIn: addAudioEffect()"); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | int AudioStreamIn::removeAudioEffect(effect_handle_t effect) const | ||
536 | { | ||
537 | ALOGV("AudioStreamIn: removeAudioEffect()"); | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | int AudioStreamIn::setGain(float gain) | ||
543 | { | ||
544 | ALOGV("AudioStreamIn: setGain()"); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | ssize_t AudioStreamIn::read(void* buffer, size_t bytes) | ||
550 | { | ||
551 | uint32_t frames = mParams.bytesToFrames(bytes); | ||
552 | int ret = 0; | ||
553 | uint32_t usecs = (frames * 1000000) / mParams.sampleRate; | ||
554 | |||
555 | ALOGVV("AudioStreamIn: read %u frames (%u bytes) buffer %p", | ||
556 | frames, bytes, buffer); | ||
557 | |||
558 | AutoMutex lock(mLock); | ||
559 | |||
560 | if (mStandby) { | ||
561 | ret = resume(); | ||
562 | if (ret) { | ||
563 | ALOGE("AudioStreamIn: failed to resume stream %d", ret); | ||
564 | usleep(usecs); /* limits the rate of error messages */ | ||
565 | return ret; | ||
566 | } | ||
567 | mStandby = false; | ||
568 | } | ||
569 | |||
570 | ret = mStream->read(buffer, frames); | ||
571 | if (ret < 0) { | ||
572 | ALOGE("AudioStreamIn: failed to read data %d", ret); | ||
573 | usleep(usecs); | ||
574 | bytes = ret; | ||
575 | } else { | ||
576 | ALOGW_IF(ret != (int)frames, | ||
577 | "AudioStreamIn: read only %d out of %d requested frames", | ||
578 | ret, frames); | ||
579 | bytes = mParams.framesToBytes(ret); | ||
580 | if (mHwDev->mMicMute) | ||
581 | memset(buffer, 0, bytes); | ||
582 | } | ||
583 | |||
584 | return bytes; | ||
585 | } | ||
586 | |||
587 | uint32_t AudioStreamIn::getInputFramesLost() | ||
588 | { | ||
589 | ALOGVV("AudioStreamIn: getInputFrameLost()"); | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | /* ---------------------------------------------------------------------------------------- */ | ||
595 | |||
596 | const char *AudioHwDevice::kCabinVolumeHP = "HP DAC Playback Volume"; | ||
597 | const char *AudioHwDevice::kCabinVolumeLine = "Line DAC Playback Volume"; | ||
598 | const char *AudioHwDevice::kBTMode = "Bluetooth Mode"; | ||
599 | |||
600 | AudioHwDevice::AudioHwDevice(uint32_t card) | ||
601 | : mCardId(card), mMixer(mCardId), mMicMute(false), mMode(AUDIO_MODE_NORMAL) | ||
602 | { | ||
603 | /* | ||
604 | * "multizone_audio.use_jamr" property is used to indicate if JAMR3 | ||
605 | * board is available in the system: | ||
606 | * - Present | ||
607 | * o Cabin : port 1, slots 0 & 1 | ||
608 | * o Mic : port 1, slot 2 | ||
609 | * o Back Mic: port 1, slot 3 | ||
610 | * - Not present | ||
611 | * o Cabin : port 0, slots 0 & 1 | ||
612 | * o Mic : port 0, slots 0 & 1 | ||
613 | */ | ||
614 | char value[PROPERTY_VALUE_MAX]; | ||
615 | if ((property_get("persist.audio.use_jamr", value, NULL) == 0) || | ||
616 | !strcmp(value, "1") || !strcasecmp(value, "true")) { | ||
617 | mMediaPortId = kJAMR3PortId; | ||
618 | } else { | ||
619 | mMediaPortId = kCPUPortId; | ||
620 | } | ||
621 | |||
622 | ALOGI("AudioHwDevice: create hw device for card hw:%u Jacinto6 EVM %s", | ||
623 | card, usesJAMR3() ? "+ JAMR3" : ""); | ||
624 | |||
625 | /* Mixer for dra7evm and input/output ports for JAMR3 PCM device */ | ||
626 | for (uint32_t i = 0; i < kNumPorts; i++) { | ||
627 | ALSAInPort *inPort = new ALSAInPort(mCardId, i); | ||
628 | mInPorts.push_back(inPort); | ||
629 | |||
630 | ALSAOutPort *outPort = new ALSAOutPort(mCardId, i); | ||
631 | mOutPorts.push_back(outPort); | ||
632 | } | ||
633 | |||
634 | /* PCM parameters for the port associated with on-board audio: | ||
635 | * 2 channels, 16-bits/sample, 44.1kHz, buffer of 882 frames (capture) */ | ||
636 | PcmParams params0(kCPUNumChannels, kSampleSize, kSampleRate, kCaptureFrameCount); | ||
637 | PcmReader *reader = new PcmReader(mInPorts[kCPUPortId], params0); | ||
638 | mReaders.push_back(reader); | ||
639 | /* 2 channels, 16-bits/sample, 44.1kHz, buffer of 1024 frames (playback) */ | ||
640 | params0.frameCount = kPlaybackFrameCount; | ||
641 | PcmWriter *writer = new PcmWriter(mOutPorts[kCPUPortId], params0); | ||
642 | mWriters.push_back(writer); | ||
643 | |||
644 | /* PCM parameters for the port associated with JAMR3 audio: | ||
645 | * 8 channels, 16-bits/sample, 44.1kHz, buffer of 882 frames (capture) */ | ||
646 | PcmParams params1(kJAMR3NumChannels, kSampleSize, kSampleRate, kCaptureFrameCount); | ||
647 | reader = new PcmReader(mInPorts[kJAMR3PortId], params1); | ||
648 | mReaders.push_back(reader); | ||
649 | /* 8 channels, 16-bits/sample, 44.1kHz, buffer of 1024 frames (playback) */ | ||
650 | params1.frameCount = kPlaybackFrameCount; | ||
651 | writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1); | ||
652 | mWriters.push_back(writer); | ||
653 | |||
654 | /* Voice call */ | ||
655 | PcmParams paramsBT(kBTNumChannels, kSampleSize, kBTSampleRate, kBTFrameCount); | ||
656 | writer = new PcmWriter(mOutPorts[kBTPortId], paramsBT); | ||
657 | mWriters.push_back(writer); | ||
658 | reader = new PcmReader(mInPorts[kBTPortId], paramsBT); | ||
659 | mReaders.push_back(reader); | ||
660 | |||
661 | /* BT is configured as stereo but only the left channel carries data */ | ||
662 | SlotMap slots; | ||
663 | slots[0] = 0; | ||
664 | slots[1] = 0; | ||
665 | |||
666 | /* Microphone slots are different in JAMR3 and CPU board */ | ||
667 | SlotMap micSlots; | ||
668 | if (usesJAMR3()) { | ||
669 | micSlots[0] = 2; | ||
670 | micSlots[1] = 2; | ||
671 | } else { | ||
672 | micSlots[0] = 0; | ||
673 | micSlots[1] = 0; | ||
674 | } | ||
675 | |||
676 | /* Voice call uplink */ | ||
677 | mULPipe = new tiaudioutils::MonoPipe(paramsBT, | ||
678 | (kVoiceCallPipeMs * paramsBT.sampleRate) / 1000); | ||
679 | mULPipeWriter = new PipeWriter(mULPipe); | ||
680 | mULPipeReader = new PipeReader(mULPipe); | ||
681 | mVoiceULInStream = new InStream(paramsBT, micSlots, mULPipeWriter); | ||
682 | mVoiceULOutStream = new OutStream(paramsBT, slots, mULPipeReader); | ||
683 | |||
684 | /* Voice call downlink */ | ||
685 | mDLPipe = new tiaudioutils::MonoPipe(paramsBT, | ||
686 | (kVoiceCallPipeMs * params0.sampleRate) / 1000); | ||
687 | mDLPipeWriter = new PipeWriter(mDLPipe); | ||
688 | mDLPipeReader = new PipeReader(mDLPipe); | ||
689 | mVoiceDLInStream = new InStream(paramsBT, slots, mDLPipeWriter); | ||
690 | mVoiceDLOutStream = new OutStream(paramsBT, slots, mDLPipeReader); | ||
691 | |||
692 | mMixer.initRoutes(); | ||
693 | } | ||
694 | |||
695 | AudioHwDevice::~AudioHwDevice() | ||
696 | { | ||
697 | ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId); | ||
698 | |||
699 | if (mDLPipeWriter) | ||
700 | delete mDLPipeWriter; | ||
701 | |||
702 | if (mDLPipeReader) | ||
703 | delete mDLPipeReader; | ||
704 | |||
705 | if (mDLPipe) | ||
706 | delete mDLPipe; | ||
707 | |||
708 | if (mULPipeWriter) | ||
709 | delete mULPipeWriter; | ||
710 | |||
711 | if (mULPipeReader) | ||
712 | delete mULPipeReader; | ||
713 | |||
714 | if (mULPipe) | ||
715 | delete mULPipe; | ||
716 | |||
717 | for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { | ||
718 | delete (*i); | ||
719 | } | ||
720 | for (ReaderVect::const_iterator i = mReaders.begin(); i != mReaders.end(); ++i) { | ||
721 | delete (*i); | ||
722 | } | ||
723 | for (OutPortVect::iterator i = mOutPorts.begin(); i != mOutPorts.end(); ++i) { | ||
724 | delete (*i); | ||
725 | } | ||
726 | for (InPortVect::iterator i = mInPorts.begin(); i != mInPorts.end(); ++i) { | ||
727 | delete (*i); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | uint32_t AudioHwDevice::getSupportedDevices() const | ||
732 | { | ||
733 | uint32_t devices; | ||
734 | |||
735 | devices = AUDIO_DEVICE_IN_BUILTIN_MIC | | ||
736 | AUDIO_DEVICE_IN_BACK_MIC | | ||
737 | AUDIO_DEVICE_IN_VOICE_CALL | | ||
738 | AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | | ||
739 | AUDIO_DEVICE_OUT_SPEAKER | | ||
740 | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | | ||
741 | AUDIO_DEVICE_OUT_WIRED_HEADSET | | ||
742 | AUDIO_DEVICE_OUT_WIRED_HEADPHONE2; | ||
743 | ALOGV("AudioHwDevice: supported devices 0x%08x", devices); | ||
744 | |||
745 | return devices; | ||
746 | } | ||
747 | |||
748 | int AudioHwDevice::initCheck() const | ||
749 | { | ||
750 | if (!mMixer.initCheck()) { | ||
751 | ALOGE("AudioHwDevice: ALSA mixer init failed"); | ||
752 | return -ENODEV; | ||
753 | } | ||
754 | |||
755 | for (ReaderVect::const_iterator i = mReaders.begin(); i != mReaders.end(); ++i) { | ||
756 | if (!((*i)->initCheck())) { | ||
757 | ALOGE("AudioHwDevice: PCM reader initCheck failed"); | ||
758 | return -ENODEV; | ||
759 | } | ||
760 | } | ||
761 | for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { | ||
762 | if (!((*i)->initCheck())) { | ||
763 | ALOGE("AudioHwDevice: PCM writer init failed"); | ||
764 | return -ENODEV; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | if ((mULPipe == NULL) || !mULPipe->initCheck() || | ||
769 | (mULPipeReader == NULL) || !mULPipeReader->initCheck() || | ||
770 | (mULPipeWriter == NULL) || !mULPipeWriter->initCheck()) { | ||
771 | ALOGE("AudioHwDevice: voice call uplink init check failed"); | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | |||
775 | if ((mDLPipe == NULL) || !mDLPipe->initCheck() || | ||
776 | (mDLPipeReader == NULL) || !mDLPipeReader->initCheck() || | ||
777 | (mDLPipeWriter == NULL) || !mDLPipeWriter->initCheck()) { | ||
778 | ALOGE("AudioHwDevice: voice call downlink init check failed"); | ||
779 | return -ENODEV; | ||
780 | } | ||
781 | |||
782 | if ((mVoiceULInStream == NULL) || !mVoiceULInStream->initCheck() || | ||
783 | (mVoiceULOutStream == NULL) || !mVoiceULOutStream->initCheck()) { | ||
784 | ALOGE("AudioHwDevice: voice call uplink streams init check failed"); | ||
785 | return -ENODEV; | ||
786 | } | ||
787 | |||
788 | if ((mVoiceDLInStream == NULL) || !mVoiceDLInStream->initCheck() || | ||
789 | (mVoiceDLOutStream == NULL) || !mVoiceDLOutStream->initCheck()) { | ||
790 | ALOGE("AudioHwDevice: voice call downlink streams init check failed"); | ||
791 | return -ENODEV; | ||
792 | } | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | int AudioHwDevice::setVoiceVolume(float volume) | ||
798 | { | ||
799 | /* Linear interpolation between voice dB limits */ | ||
800 | float dB = (kVoiceDBMax - kVoiceDBMin) * volume + kVoiceDBMin; | ||
801 | |||
802 | /* Output stage gain (-59.0dB, 0dB) with steps of 0.5dB */ | ||
803 | int val = 2 * (dB + 59.0f); | ||
804 | |||
805 | ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f dB=%.4f", volume, dB, val); | ||
806 | |||
807 | mMixer.set(ALSAControl(kCabinVolumeHP, val), true); | ||
808 | mMixer.set(ALSAControl(kCabinVolumeLine, val), true); | ||
809 | |||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | int AudioHwDevice::setMasterVolume(float volume) | ||
814 | { | ||
815 | ALOGV("AudioHwDevice: setMasterVolume() vol=%.4f", volume); | ||
816 | return -ENOSYS; | ||
817 | } | ||
818 | |||
819 | const char *AudioHwDevice::getModeName(audio_mode_t mode) const | ||
820 | { | ||
821 | switch (mode) { | ||
822 | case AUDIO_MODE_CURRENT: | ||
823 | return "CURRENT"; | ||
824 | case AUDIO_MODE_NORMAL: | ||
825 | return "NORMAL"; | ||
826 | case AUDIO_MODE_RINGTONE: | ||
827 | return "RINGTONE"; | ||
828 | case AUDIO_MODE_IN_CALL: | ||
829 | return "IN_CALL"; | ||
830 | case AUDIO_MODE_IN_COMMUNICATION: | ||
831 | return "COMMUNICATION"; | ||
832 | default: | ||
833 | return "INVALID"; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | int AudioHwDevice::setMode(audio_mode_t mode) | ||
838 | { | ||
839 | ALOGV("AudioHwDevice: setMode() %s", getModeName(mode)); | ||
840 | |||
841 | AutoMutex lock(mLock); | ||
842 | if (mMode == mode) { | ||
843 | ALOGW("AudioHwDevice: already in mode %s", getModeName(mode)); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | int ret = 0; | ||
848 | if (mode == AUDIO_MODE_IN_CALL) { | ||
849 | ret = enterVoiceCall(); | ||
850 | ALOGE_IF(ret, "AudioHwDevice: failed to enter voice call %d", ret); | ||
851 | } else { | ||
852 | leaveVoiceCall(); | ||
853 | } | ||
854 | |||
855 | if (!ret) | ||
856 | mMode = mode; | ||
857 | |||
858 | return ret; | ||
859 | } | ||
860 | |||
861 | int AudioHwDevice::enableVoiceCall() | ||
862 | { | ||
863 | ALOGV("AudioHwDevice: enable voice call paths"); | ||
864 | |||
865 | sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote(); | ||
866 | if (outStream == NULL) { | ||
867 | ALOGE("AudioHwDevice: primary output stream is not valid"); | ||
868 | return -ENODEV; | ||
869 | } | ||
870 | |||
871 | /* Playback stream will free the writer and switch to a null writer */ | ||
872 | outStream->setVoiceCall(true); | ||
873 | |||
874 | /* Uplink input stream: Mic -> Pipe */ | ||
875 | int ret = mReaders[mMediaPortId]->registerStream(mVoiceULInStream); | ||
876 | if (ret) { | ||
877 | ALOGE("AudioHwDevice: failed to register uplink in stream %d", ret); | ||
878 | return ret; | ||
879 | } | ||
880 | |||
881 | /* Uplink output stream: Pipe -> Bluetooth */ | ||
882 | ret = mWriters[kBTPortId]->registerStream(mVoiceULOutStream); | ||
883 | if (ret) { | ||
884 | ALOGE("AudioHwDevice: failed to register uplink out stream %d", ret); | ||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | /* Downlink input stream: Bluetooth -> Pipe */ | ||
889 | ret = mReaders[kBTPortId]->registerStream(mVoiceDLInStream); | ||
890 | if (ret) { | ||
891 | ALOGE("AudioHwDevice: failed to register downlink in stream %d", ret); | ||
892 | return ret; | ||
893 | } | ||
894 | |||
895 | /* Downlink output stream: Pipe -> Speaker */ | ||
896 | ret = outStream->mWriter->registerStream(mVoiceDLOutStream); | ||
897 | if (ret) { | ||
898 | ALOGE("AudioHwDevice: failed to register downlink out stream %d", ret); | ||
899 | } | ||
900 | |||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | void AudioHwDevice::disableVoiceCall() | ||
905 | { | ||
906 | ALOGV("AudioHwDevice: disable voice call paths"); | ||
907 | |||
908 | sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote(); | ||
909 | if (outStream != NULL) { | ||
910 | if (outStream->mWriter->isStreamRegistered(mVoiceDLOutStream)) | ||
911 | outStream->mWriter->unregisterStream(mVoiceDLOutStream); | ||
912 | outStream->setVoiceCall(false); | ||
913 | } else { | ||
914 | ALOGE("AudioHwDevice: primary output stream is not valid"); | ||
915 | } | ||
916 | |||
917 | if (mReaders[kBTPortId]->isStreamRegistered(mVoiceDLInStream)) | ||
918 | mReaders[kBTPortId]->unregisterStream(mVoiceDLInStream); | ||
919 | |||
920 | if (mWriters[kBTPortId]->isStreamRegistered(mVoiceULOutStream)) | ||
921 | mWriters[kBTPortId]->unregisterStream(mVoiceULOutStream); | ||
922 | |||
923 | if (mReaders[mMediaPortId]->isStreamRegistered(mVoiceULInStream)) | ||
924 | mReaders[mMediaPortId]->unregisterStream(mVoiceULInStream); | ||
925 | } | ||
926 | |||
927 | int AudioHwDevice::enterVoiceCall() | ||
928 | { | ||
929 | ALOGI("AudioHwDevice: enter voice call"); | ||
930 | |||
931 | /* Setup uplink and downlink pipes */ | ||
932 | int ret = enableVoiceCall(); | ||
933 | if (ret) { | ||
934 | ALOGE("AudioHwDevice: failed to enable voice call path %d", ret); | ||
935 | return ret; | ||
936 | } | ||
937 | |||
938 | /* Bluetooth is master, provides BCLK and FSYNC */ | ||
939 | mMixer.set(ALSAControl(kBTMode, "Master"), true); | ||
940 | |||
941 | mULPipe->shutdown(false); | ||
942 | mDLPipe->shutdown(false); | ||
943 | |||
944 | /* Uplink input stream: Mic -> Pipe */ | ||
945 | ret = mVoiceULInStream->start(); | ||
946 | if (ret) { | ||
947 | ALOGE("AudioHwDevice: failed to start uplink in stream %d", ret); | ||
948 | return ret; | ||
949 | } | ||
950 | |||
951 | /* Downlink input stream: Bluetooth -> Pipe */ | ||
952 | ret = mVoiceDLInStream->start(); | ||
953 | if (ret) { | ||
954 | ALOGE("AudioHwDevice: failed to start downlink in stream %d", ret); | ||
955 | return ret; | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * Wait till pipe is half full to give a head start to the output streams. | ||
960 | * The time to wait consists of the actual pipe size, the ADC settle time | ||
961 | * used in the kernel and the time needed to produce a BT audio buffer. | ||
962 | * Only the pipe size related time contributes to the steady state latency. | ||
963 | */ | ||
964 | usleep((kVoiceCallPipeMs * 5000) + (kADCSettleMs * 1000) + | ||
965 | (kBTFrameCount * 1000) / kBTSampleRate); | ||
966 | |||
967 | /* Downlink output stream: Pipe -> Speaker */ | ||
968 | ret = mVoiceDLOutStream->start(); | ||
969 | if (ret) { | ||
970 | ALOGE("AudioHwDevice: failed to start downlink out stream %d", ret); | ||
971 | } | ||
972 | |||
973 | /* Uplink output stream: Pipe -> Bluetooth */ | ||
974 | ret = mVoiceULOutStream->start(); | ||
975 | if (ret) { | ||
976 | ALOGE("AudioHwDevice: failed to start uplink out stream %d", ret); | ||
977 | return ret; | ||
978 | } | ||
979 | |||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | void AudioHwDevice::leaveVoiceCall() | ||
984 | { | ||
985 | ALOGI("AudioHwDevice: leave voice call"); | ||
986 | |||
987 | /* | ||
988 | * The PCM ports used for Bluetooth are slaves and they can lose the | ||
989 | * BCLK and FSYNC while still active. That leads to blocking read() and | ||
990 | * write() calls, which is prevented by switching the clock source to | ||
991 | * an internal one and explicitly stopping both ports for the new source | ||
992 | * to take effect at kernel level | ||
993 | */ | ||
994 | mMixer.set(ALSAControl(kBTMode, "Slave"), true); | ||
995 | |||
996 | mULPipe->shutdown(true); | ||
997 | mDLPipe->shutdown(true); | ||
998 | |||
999 | /* Uplink input stream: Mic -> Pipe */ | ||
1000 | if (mVoiceULInStream->isStarted()) | ||
1001 | mVoiceULInStream->stop(); | ||
1002 | |||
1003 | /* Downlink input stream: Bluetooth -> Pipe */ | ||
1004 | mInPorts[kBTPortId]->stop(); | ||
1005 | if (mVoiceDLInStream->isStarted()) | ||
1006 | mVoiceDLInStream->stop(); | ||
1007 | |||
1008 | /* Downlink output stream: Pipe -> Speaker */ | ||
1009 | if (mVoiceDLOutStream->isStarted()) | ||
1010 | mVoiceDLOutStream->stop(); | ||
1011 | |||
1012 | /* Uplink output stream: Pipe -> Bluetooth */ | ||
1013 | mOutPorts[kBTPortId]->stop(); | ||
1014 | if (mVoiceULOutStream->isStarted()) | ||
1015 | mVoiceULOutStream->stop(); | ||
1016 | |||
1017 | mULPipe->flush(); | ||
1018 | mDLPipe->flush(); | ||
1019 | |||
1020 | disableVoiceCall(); | ||
1021 | |||
1022 | /* Reset the cabin volume for media */ | ||
1023 | setVoiceVolume(1.0f); | ||
1024 | } | ||
1025 | |||
1026 | int AudioHwDevice::setMicMute(bool state) | ||
1027 | { | ||
1028 | ALOGV("AudioHwDevice: setMicMute() %s", state ? "mute" : "unmute"); | ||
1029 | |||
1030 | mMicMute = state; | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | int AudioHwDevice::getMicMute(bool *state) const | ||
1036 | { | ||
1037 | ALOGV("AudioHwDevice: getMicMute()"); | ||
1038 | |||
1039 | *state = mMicMute; | ||
1040 | |||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | int AudioHwDevice::setParameters(const char *kv_pairs) | ||
1045 | { | ||
1046 | ALOGV("AudioHwDevice: setParameters() '%s'", kv_pairs ? kv_pairs : ""); | ||
1047 | |||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | char *AudioHwDevice::getParameters(const char *keys) const | ||
1052 | { | ||
1053 | ALOGV("AudioHwDevice: getParameters()"); | ||
1054 | |||
1055 | return NULL; | ||
1056 | } | ||
1057 | |||
1058 | size_t AudioHwDevice::getInputBufferSize(const struct audio_config *config) const | ||
1059 | { | ||
1060 | ALOGV("AudioHwDevice: getInputBufferSize()"); | ||
1061 | |||
1062 | AutoMutex lock(mLock); | ||
1063 | size_t size; | ||
1064 | |||
1065 | /* Take resampling ratio into account */ | ||
1066 | /* Use port 0 for the calculation, since values for both ports are the same */ | ||
1067 | uint32_t frames = mReaders[kCPUPortId]->getParams().frameCount; | ||
1068 | uint32_t rate = mReaders[kCPUPortId]->getParams().sampleRate; | ||
1069 | |||
1070 | size = (frames * config->sample_rate) / rate; | ||
1071 | size = size * mReaders[kCPUPortId]->getParams().frameSize(); | ||
1072 | |||
1073 | ALOGV("AudioHwDevice: getInputBufferSize() %d bytes", size); | ||
1074 | |||
1075 | return size; | ||
1076 | } | ||
1077 | |||
1078 | int AudioHwDevice::dump(int fd) const | ||
1079 | { | ||
1080 | ALOGV("AudioHwDevice: dump()"); | ||
1081 | |||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | int AudioHwDevice::setMasterMute(bool mute) | ||
1086 | { | ||
1087 | ALOGV("AudioHwDevice: setMasterMute() %s", mute ? "mute" : "unmute"); | ||
1088 | return -ENOSYS; | ||
1089 | } | ||
1090 | |||
1091 | AudioStreamIn* AudioHwDevice::openInputStream(audio_io_handle_t handle, | ||
1092 | audio_devices_t devices, | ||
1093 | struct audio_config *config) | ||
1094 | { | ||
1095 | uint32_t port = mMediaPortId; | ||
1096 | uint32_t srcSlot0, srcSlot1; | ||
1097 | uint32_t channels = popcount(config->channel_mask); | ||
1098 | |||
1099 | ALOGV("AudioHwDevice: openInputStream()"); | ||
1100 | |||
1101 | switch (devices) { | ||
1102 | case AUDIO_DEVICE_IN_BUILTIN_MIC: | ||
1103 | case AUDIO_DEVICE_IN_VOICE_CALL: | ||
1104 | if (usesJAMR3()) { | ||
1105 | srcSlot0 = 2; | ||
1106 | srcSlot1 = 2; | ||
1107 | } else { | ||
1108 | srcSlot0 = 0; | ||
1109 | srcSlot1 = 1; | ||
1110 | } | ||
1111 | break; | ||
1112 | case AUDIO_DEVICE_IN_BACK_MIC: | ||
1113 | if (usesJAMR3()) { | ||
1114 | srcSlot0 = 3; | ||
1115 | srcSlot1 = 3; | ||
1116 | } else { | ||
1117 | srcSlot0 = 0; | ||
1118 | srcSlot1 = 1; | ||
1119 | } | ||
1120 | break; | ||
1121 | case AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET: | ||
1122 | if (!usesJAMR3()) { | ||
1123 | ALOGE("AudioHwDevice: device 0x%08x requires JAMR3", devices); | ||
1124 | return NULL; | ||
1125 | } | ||
1126 | srcSlot0 = 0; | ||
1127 | srcSlot1 = 1; | ||
1128 | break; | ||
1129 | default: | ||
1130 | ALOGE("AudioHwDevice: device 0x%08x is not supported", devices); | ||
1131 | return NULL; | ||
1132 | } | ||
1133 | |||
1134 | SlotMap slotMap; | ||
1135 | if (channels >= 1) | ||
1136 | slotMap[0] = srcSlot0; | ||
1137 | if (channels == 2) | ||
1138 | slotMap[1] = srcSlot1; | ||
1139 | if (channels > 2) { | ||
1140 | ALOGE("AudioHwDevice: %u channels are not supported", channels); | ||
1141 | return NULL; | ||
1142 | } | ||
1143 | |||
1144 | if (!slotMap.isValid()) { | ||
1145 | ALOGE("AudioHwDevice: failed to create slot map"); | ||
1146 | return NULL; | ||
1147 | } | ||
1148 | |||
1149 | AutoMutex lock(mLock); | ||
1150 | |||
1151 | /* Set the parameters for the internal input stream. Don't change the | ||
1152 | * parameters for capture. The resampler is used if needed. */ | ||
1153 | PcmParams params(*config, mReaders[port]->getParams().frameCount); | ||
1154 | |||
1155 | sp<AudioStreamIn> in = new AudioStreamIn(this, mReaders[port], params, | ||
1156 | slotMap, devices); | ||
1157 | if ((in == NULL) || in->initCheck()) { | ||
1158 | ALOGE("AudioHwDevice: failed to open input stream on port hw:%u,%u", | ||
1159 | mCardId, port); | ||
1160 | return NULL; | ||
1161 | } | ||
1162 | |||
1163 | mInStreams.insert(in); | ||
1164 | |||
1165 | return in.get(); | ||
1166 | } | ||
1167 | |||
1168 | void AudioHwDevice::closeInputStream(AudioStreamIn *in) | ||
1169 | { | ||
1170 | ALOGV("AudioHwDevice: closeInputStream()"); | ||
1171 | |||
1172 | AutoMutex lock(mLock); | ||
1173 | |||
1174 | if (mInStreams.find(in) == mInStreams.end()) { | ||
1175 | ALOGW("AudioHwDevice: input stream %p is not open", in); | ||
1176 | return; | ||
1177 | } | ||
1178 | |||
1179 | mInStreams.erase(in); | ||
1180 | |||
1181 | in = NULL; | ||
1182 | } | ||
1183 | |||
1184 | AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle, | ||
1185 | audio_devices_t devices, | ||
1186 | audio_output_flags_t flags, | ||
1187 | struct audio_config *config) | ||
1188 | { | ||
1189 | uint32_t port = 0; | ||
1190 | PcmParams params; | ||
1191 | |||
1192 | ALOGV("AudioHwDevice: openOutputStream()"); | ||
1193 | |||
1194 | uint32_t destMask; | ||
1195 | switch (devices) { | ||
1196 | case AUDIO_DEVICE_OUT_SPEAKER: | ||
1197 | port = mMediaPortId; | ||
1198 | destMask = 0x03; | ||
1199 | break; | ||
1200 | case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: | ||
1201 | case AUDIO_DEVICE_OUT_WIRED_HEADSET: | ||
1202 | port = kJAMR3PortId; | ||
1203 | destMask = 0x0c; | ||
1204 | break; | ||
1205 | case AUDIO_DEVICE_OUT_WIRED_HEADPHONE2: | ||
1206 | port = kJAMR3PortId; | ||
1207 | destMask = 0x30; | ||
1208 | break; | ||
1209 | default: | ||
1210 | ALOGE("AudioHwDevice: device 0x%08x is not supported", devices); | ||
1211 | return NULL; | ||
1212 | } | ||
1213 | |||
1214 | SlotMap slotMap(0x03, destMask); | ||
1215 | if (!slotMap.isValid()) { | ||
1216 | ALOGE("AudioHwDevice: failed to create slot map"); | ||
1217 | return NULL; | ||
1218 | } | ||
1219 | |||
1220 | AutoMutex lock(mLock); | ||
1221 | |||
1222 | /* Set the parameters for the internal output stream */ | ||
1223 | params.frameCount = mWriters[port]->getParams().frameCount; | ||
1224 | params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */ | ||
1225 | params.sampleBits = 16; /* 16-bits/sample */ | ||
1226 | params.channels = 2; /* Listening zones are stereo */ | ||
1227 | |||
1228 | /* Update audio config with granted parameters */ | ||
1229 | if (popcount(config->channel_mask) != (int)params.channels) { | ||
1230 | ALOGV("AudioHwDevice: updating audio config channel mask [0x%x]->[0x%x]", | ||
1231 | config->channel_mask, | ||
1232 | audio_channel_out_mask_from_count(params.channels)); | ||
1233 | } | ||
1234 | config->channel_mask = audio_channel_out_mask_from_count(params.channels); | ||
1235 | if (config->format != AUDIO_FORMAT_PCM_16_BIT) { | ||
1236 | ALOGV("AudioHwDevice: updating audio config format [0x%x]->[0x%x]", | ||
1237 | config->format, AUDIO_FORMAT_PCM_16_BIT); | ||
1238 | } | ||
1239 | config->format = AUDIO_FORMAT_PCM_16_BIT; | ||
1240 | |||
1241 | sp<AudioStreamOut> out = new AudioStreamOut(this, mWriters[port], params, | ||
1242 | slotMap, devices); | ||
1243 | if ((out == NULL) || out->initCheck()) { | ||
1244 | ALOGE("AudioHwDevice: failed to open output stream on port hw:%u,%u", | ||
1245 | mCardId, port); | ||
1246 | return NULL; | ||
1247 | } | ||
1248 | |||
1249 | if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) | ||
1250 | mPrimaryStreamOut = out; | ||
1251 | |||
1252 | mOutStreams.insert(out); | ||
1253 | |||
1254 | return out.get(); | ||
1255 | } | ||
1256 | |||
1257 | void AudioHwDevice::closeOutputStream(AudioStreamOut *out) | ||
1258 | { | ||
1259 | ALOGV("AudioHwDevice: closeOutputStream()"); | ||
1260 | |||
1261 | AutoMutex lock(mLock); | ||
1262 | |||
1263 | if (mOutStreams.find(out) == mOutStreams.end()) { | ||
1264 | ALOGW("AudioHwDevice: output stream %p is not open", out); | ||
1265 | return; | ||
1266 | } | ||
1267 | |||
1268 | if (mPrimaryStreamOut == out) | ||
1269 | mPrimaryStreamOut = NULL; | ||
1270 | |||
1271 | mOutStreams.erase(out); | ||
1272 | |||
1273 | out = NULL; | ||
1274 | } | ||
1275 | |||
1276 | }; /* namespace android */ | ||
diff --git a/audio/multizone/AudioHw.h b/audio/multizone/AudioHw.h new file mode 100644 index 0000000..0d475da --- /dev/null +++ b/audio/multizone/AudioHw.h | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Texas Instruments | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #ifndef _AUDIO_HW_H_ | ||
18 | #define _AUDIO_HW_H_ | ||
19 | |||
20 | #include <vector> | ||
21 | |||
22 | #include <system/audio.h> | ||
23 | #include <hardware/audio_effect.h> | ||
24 | |||
25 | #include <tiaudioutils/Pcm.h> | ||
26 | #include <tiaudioutils/NullPcm.h> | ||
27 | #include <tiaudioutils/ALSAPcm.h> | ||
28 | #include <tiaudioutils/ALSAMixer.h> | ||
29 | #include <tiaudioutils/MumStream.h> | ||
30 | #include <tiaudioutils/Stream.h> | ||
31 | #include <tiaudioutils/Base.h> | ||
32 | |||
33 | namespace android { | ||
34 | |||
35 | using namespace tiaudioutils; | ||
36 | using std::vector; | ||
37 | |||
38 | class AudioHwDevice; | ||
39 | |||
40 | class AudioStream { | ||
41 | public: | ||
42 | virtual ~AudioStream() {} | ||
43 | virtual uint32_t getSampleRate() const = 0; | ||
44 | virtual int setSampleRate(uint32_t rate) = 0; | ||
45 | virtual size_t getBufferSize() const = 0; | ||
46 | virtual audio_channel_mask_t getChannels() const = 0; | ||
47 | virtual audio_format_t getFormat() const = 0; | ||
48 | virtual int setFormat(audio_format_t format) = 0; | ||
49 | virtual int standby() = 0; | ||
50 | virtual int dump(int fd) const = 0; | ||
51 | virtual audio_devices_t getDevice() const = 0; | ||
52 | virtual int setDevice(audio_devices_t device) { return 0; } /* unused */ | ||
53 | virtual int setParameters(const char *kv_pairs) = 0; | ||
54 | virtual char *getParameters(const char *keys) const = 0; | ||
55 | virtual int addAudioEffect(effect_handle_t effect) const = 0; | ||
56 | virtual int removeAudioEffect(effect_handle_t effect) const = 0; | ||
57 | }; | ||
58 | |||
59 | class AudioStreamOut : public RefBase, public AudioStream { | ||
60 | public: | ||
61 | AudioStreamOut(AudioHwDevice *hwDev, | ||
62 | PcmWriter *writer, | ||
63 | const PcmParams ¶ms, | ||
64 | const SlotMap &map, | ||
65 | audio_devices_t devices); | ||
66 | virtual ~AudioStreamOut() {}; | ||
67 | int initCheck() const; | ||
68 | |||
69 | /* From AudioStream */ | ||
70 | virtual uint32_t getSampleRate() const; | ||
71 | virtual int setSampleRate(uint32_t rate); | ||
72 | virtual size_t getBufferSize() const; | ||
73 | virtual audio_channel_mask_t getChannels() const; | ||
74 | virtual audio_format_t getFormat() const; | ||
75 | virtual int setFormat(audio_format_t format); | ||
76 | virtual int standby(); | ||
77 | virtual int dump(int fd) const; | ||
78 | virtual audio_devices_t getDevice() const; | ||
79 | virtual int setParameters(const char *kv_pairs); | ||
80 | virtual char *getParameters(const char *keys) const; | ||
81 | virtual int addAudioEffect(effect_handle_t effect) const; | ||
82 | virtual int removeAudioEffect(effect_handle_t effect) const; | ||
83 | |||
84 | /* AudioStreamOut specific */ | ||
85 | uint32_t getLatency() const; | ||
86 | int setVolume(float left, float right); | ||
87 | ssize_t write(const void* buffer, size_t bytes); | ||
88 | int getRenderPosition(uint32_t *dsp_frames) const; | ||
89 | int getNextWriteTimestamp(int64_t *timestamp) const; | ||
90 | |||
91 | void setVoiceCall(bool on); | ||
92 | |||
93 | friend AudioHwDevice; | ||
94 | |||
95 | protected: | ||
96 | int resume(); | ||
97 | void idle(); | ||
98 | |||
99 | AudioHwDevice *mHwDev; | ||
100 | NullOutPort mNullPort; | ||
101 | PcmWriter mNullWriter; | ||
102 | PcmWriter *mWriter; | ||
103 | PcmParams mParams; | ||
104 | audio_devices_t mDevices; | ||
105 | sp<OutStream> mStream; | ||
106 | bool mStandby; | ||
107 | bool mUsedForVoiceCall; | ||
108 | Mutex mLock; | ||
109 | }; | ||
110 | |||
111 | class AudioStreamIn : public RefBase, public AudioStream { | ||
112 | public: | ||
113 | AudioStreamIn(AudioHwDevice *hwDev, | ||
114 | PcmReader *reader, | ||
115 | const PcmParams ¶ms, | ||
116 | const SlotMap &map, | ||
117 | audio_devices_t devices); | ||
118 | virtual ~AudioStreamIn() {}; | ||
119 | int initCheck() const; | ||
120 | |||
121 | /* From AudioStream */ | ||
122 | virtual uint32_t getSampleRate() const; | ||
123 | virtual int setSampleRate(uint32_t rate); | ||
124 | virtual size_t getBufferSize() const; | ||
125 | virtual audio_channel_mask_t getChannels() const; | ||
126 | virtual audio_format_t getFormat() const; | ||
127 | virtual int setFormat(audio_format_t format); | ||
128 | virtual int standby(); | ||
129 | virtual int dump(int fd) const; | ||
130 | virtual audio_devices_t getDevice() const; | ||
131 | virtual int setParameters(const char *kv_pairs); | ||
132 | virtual char *getParameters(const char *keys) const; | ||
133 | virtual int addAudioEffect(effect_handle_t effect) const; | ||
134 | virtual int removeAudioEffect(effect_handle_t effect) const; | ||
135 | |||
136 | /* AudioStreamIn specific */ | ||
137 | int setGain(float gain); | ||
138 | ssize_t read(void* buffer, size_t bytes); | ||
139 | uint32_t getInputFramesLost(); | ||
140 | |||
141 | protected: | ||
142 | int resume(); | ||
143 | void idle(); | ||
144 | |||
145 | AudioHwDevice *mHwDev; | ||
146 | PcmReader *mReader; | ||
147 | PcmParams mParams; | ||
148 | audio_devices_t mDevices; | ||
149 | audio_source_t mSource; | ||
150 | sp<InStream> mStream; | ||
151 | bool mStandby; | ||
152 | Mutex mLock; | ||
153 | }; | ||
154 | |||
155 | class AudioHwDevice { | ||
156 | public: | ||
157 | AudioHwDevice(uint32_t card); | ||
158 | virtual ~AudioHwDevice(); | ||
159 | |||
160 | uint32_t getSupportedDevices() const; | ||
161 | int initCheck() const; | ||
162 | int setVoiceVolume(float volume); | ||
163 | int setMasterVolume(float volume); | ||
164 | int setMode(audio_mode_t mode); | ||
165 | int setMicMute(bool state); | ||
166 | int getMicMute(bool *state) const; | ||
167 | int setParameters(const char *kv_pairs); | ||
168 | char *getParameters(const char *keys) const; | ||
169 | size_t getInputBufferSize(const struct audio_config *config) const; | ||
170 | int dump(int fd) const; | ||
171 | int setMasterMute(bool mute); | ||
172 | AudioStreamIn* openInputStream(audio_io_handle_t handle, | ||
173 | audio_devices_t devices, | ||
174 | struct audio_config *config); | ||
175 | void closeInputStream(AudioStreamIn *in); | ||
176 | AudioStreamOut* openOutputStream(audio_io_handle_t handle, | ||
177 | audio_devices_t devices, | ||
178 | audio_output_flags_t flags, | ||
179 | struct audio_config *config); | ||
180 | void closeOutputStream(AudioStreamOut *out); | ||
181 | |||
182 | friend class AudioStreamIn; | ||
183 | friend class AudioStreamOut; | ||
184 | |||
185 | static const uint32_t kNumPorts = 3; | ||
186 | static const uint32_t kCPUPortId = 0; | ||
187 | static const uint32_t kJAMR3PortId = 1; | ||
188 | static const uint32_t kBTPortId = 2; | ||
189 | static const uint32_t kCPUNumChannels = 2; | ||
190 | static const uint32_t kJAMR3NumChannels = 8; | ||
191 | static const uint32_t kBTNumChannels = 2; | ||
192 | |||
193 | static const uint32_t kSampleRate = 44100; | ||
194 | static const uint32_t kBTSampleRate = 8000; | ||
195 | static const uint32_t kSampleSize = 16; | ||
196 | static const uint32_t kCaptureFrameCount = 882; | ||
197 | static const uint32_t kPlaybackFrameCount = 1024; | ||
198 | static const uint32_t kBTFrameCount = 160; | ||
199 | |||
200 | static const uint32_t kADCSettleMs = 80; | ||
201 | static const uint32_t kVoiceCallPipeMs = 100; | ||
202 | |||
203 | static const float kVoiceDBMax = 0.0f; | ||
204 | static const float kVoiceDBMin = -24.0f; | ||
205 | static const char *kCabinVolumeHP; | ||
206 | static const char *kCabinVolumeLine; | ||
207 | static const char *kBTMode; | ||
208 | |||
209 | protected: | ||
210 | typedef set< sp<AudioStreamIn> > StreamInSet; | ||
211 | typedef set< sp<AudioStreamOut> > StreamOutSet; | ||
212 | typedef vector<ALSAInPort*> InPortVect; | ||
213 | typedef vector<ALSAOutPort*> OutPortVect; | ||
214 | typedef vector<PcmReader*> ReaderVect; | ||
215 | typedef vector<PcmWriter*> WriterVect; | ||
216 | |||
217 | bool usesJAMR3() const { return mMediaPortId == kJAMR3PortId; } | ||
218 | const char *getModeName(audio_mode_t mode) const; | ||
219 | int enterVoiceCall(); | ||
220 | void leaveVoiceCall(); | ||
221 | int enableVoiceCall(); | ||
222 | void disableVoiceCall(); | ||
223 | |||
224 | uint32_t mCardId; | ||
225 | ALSAMixer mMixer; | ||
226 | InPortVect mInPorts; | ||
227 | OutPortVect mOutPorts; | ||
228 | ReaderVect mReaders; | ||
229 | WriterVect mWriters; | ||
230 | StreamInSet mInStreams; | ||
231 | StreamOutSet mOutStreams; | ||
232 | bool mMicMute; | ||
233 | audio_mode_t mMode; | ||
234 | uint32_t mMediaPortId; | ||
235 | wp<AudioStreamOut> mPrimaryStreamOut; | ||
236 | tiaudioutils::MonoPipe *mULPipe; | ||
237 | tiaudioutils::MonoPipe *mDLPipe; | ||
238 | PipeWriter *mULPipeWriter; | ||
239 | PipeWriter *mDLPipeWriter; | ||
240 | PipeReader *mULPipeReader; | ||
241 | PipeReader *mDLPipeReader; | ||
242 | sp<InStream> mVoiceULInStream; | ||
243 | sp<InStream> mVoiceDLInStream; | ||
244 | sp<OutStream> mVoiceULOutStream; | ||
245 | sp<OutStream> mVoiceDLOutStream; | ||
246 | mutable Mutex mLock; | ||
247 | }; | ||
248 | |||
249 | }; // namespace android | ||
250 | |||
251 | #endif /* _AUDIO_HW_H_ */ | ||
diff --git a/audio/multizone/audio_hw.cpp b/audio/multizone/audio_hw.cpp new file mode 100644 index 0000000..3e429c4 --- /dev/null +++ b/audio/multizone/audio_hw.cpp | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Texas Instruments | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #define LOG_TAG "audio_hw_primary" | ||
18 | /* #define LOG_NDEBUG 0 */ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <stdint.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <sys/time.h> | ||
24 | |||
25 | #include <cutils/log.h> | ||
26 | #include <cutils/str_parms.h> | ||
27 | #include <cutils/properties.h> | ||
28 | |||
29 | #include <system/audio.h> | ||
30 | #include <hardware/hardware.h> | ||
31 | #include <hardware/audio.h> | ||
32 | #include <hardware/audio_effect.h> | ||
33 | |||
34 | #include <AudioHw.h> | ||
35 | |||
36 | extern "C" { | ||
37 | |||
38 | namespace android { | ||
39 | |||
40 | struct mz_audio_device { | ||
41 | struct audio_hw_device device; | ||
42 | AudioHwDevice *hwDev; | ||
43 | }; | ||
44 | |||
45 | struct mz_stream_in { | ||
46 | struct audio_stream_in stream; | ||
47 | AudioStreamIn *streamIn; | ||
48 | }; | ||
49 | |||
50 | struct mz_stream_out { | ||
51 | struct audio_stream_out stream; | ||
52 | AudioStreamOut *streamOut; | ||
53 | }; | ||
54 | |||
55 | static inline AudioHwDevice *toAudioHwDev(struct audio_hw_device *dev) | ||
56 | { | ||
57 | return reinterpret_cast<struct mz_audio_device *>(dev)->hwDev; | ||
58 | } | ||
59 | |||
60 | static inline const AudioHwDevice *tocAudioHwDev(const struct audio_hw_device *dev) | ||
61 | { | ||
62 | return reinterpret_cast<const struct mz_audio_device *>(dev)->hwDev; | ||
63 | } | ||
64 | |||
65 | static inline AudioStreamIn *toStreamIn(struct audio_stream_in *in) | ||
66 | { | ||
67 | return reinterpret_cast<struct mz_stream_in *>(in)->streamIn; | ||
68 | } | ||
69 | |||
70 | static inline const AudioStreamIn *tocStreamIn(const struct audio_stream_in *in) | ||
71 | { | ||
72 | return reinterpret_cast<const struct mz_stream_in *>(in)->streamIn; | ||
73 | } | ||
74 | |||
75 | static inline AudioStreamOut *toStreamOut(struct audio_stream_out *out) | ||