1 /*
2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #define LOG_TAG "split_a2dp"
30 /*#define LOG_NDEBUG 0*/
31 #define LOG_NDDEBUG 0
32 #include <errno.h>
33 #include <cutils/log.h>
34
35 #include "audio_hw.h"
36 #include "platform.h"
37 #include "platform_api.h"
38 #include <stdlib.h>
39 #include <cutils/str_parms.h>
40 #include <hardware/audio.h>
41 #include <hardware/hardware.h>
42
43 #ifdef SPLIT_A2DP_ENABLED
44
45 struct a2dp_data{
46 struct audio_stream_out *a2dp_stream;
47 struct audio_hw_device *a2dp_device;
48 bool a2dp_started;
49 bool a2dp_suspended;
50 };
51
52 struct a2dp_data a2dp;
53
54 #define AUDIO_PARAMETER_A2DP_STARTED "A2dpStarted"
55
open_a2dp_output()56 static int open_a2dp_output()
57 {
58 hw_module_t *mod;
59 int format = AUDIO_FORMAT_PCM_16_BIT;
60 int rc=0;
61 uint32_t channels = AUDIO_CHANNEL_OUT_STEREO;
62 uint32_t sampleRate = DEFAULT_OUTPUT_SAMPLING_RATE;
63 struct audio_config config;
64
65 ALOGV("open_a2dp_output");
66
67 config.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
68 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
69 config.format = AUDIO_FORMAT_PCM_16_BIT;
70
71 if (a2dp.a2dp_device == NULL){
72 rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, (const char*)"a2dp",
73 (const hw_module_t**)&mod);
74 if (rc != 0) {
75 ALOGE("Could not get a2dp hardware module");
76 return rc;
77 }
78 ALOGV("Opening A2DP device HAL for the first time");
79 rc = audio_hw_device_open(mod, &a2dp.a2dp_device);
80 if (rc != 0) {
81 ALOGE("couldn't open a2dp audio hw device");
82 return rc;
83 }
84 }
85
86 rc = a2dp.a2dp_device->open_output_stream(a2dp.a2dp_device, 0,AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
87 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &a2dp.a2dp_stream, NULL);
88
89 if( rc != 0 ) {
90 ALOGE("Failed to open output stream for a2dp: status %d", rc);
91 }
92
93 a2dp.a2dp_suspended = false;
94 return rc;
95 }
96
close_a2dp_output()97 static int close_a2dp_output()
98 {
99
100 ALOGV("close_a2dp_output");
101 if(!a2dp.a2dp_device && !a2dp.a2dp_stream){
102 ALOGE("No Active A2dp output found");
103 return 0;
104 }
105
106 a2dp.a2dp_device->close_output_stream(a2dp.a2dp_device, a2dp.a2dp_stream);
107 a2dp.a2dp_stream = NULL;
108 a2dp.a2dp_started = false;
109 a2dp.a2dp_suspended = true;
110
111 return 0;
112 }
113
audio_extn_a2dp_set_parameters(struct str_parms * parms)114 void audio_extn_a2dp_set_parameters(struct str_parms *parms)
115 {
116 int ret, val;
117 char value[32]={0};
118
119 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value,
120 sizeof(value));
121 if( ret >= 0) {
122 val = atoi(value);
123 if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
124 ALOGV("Received device connect request for A2DP");
125 open_a2dp_output();
126 }
127 }
128
129 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value,
130 sizeof(value));
131
132 if( ret >= 0) {
133 val = atoi(value);
134 if (val & AUDIO_DEVICE_OUT_ALL_A2DP) {
135 ALOGV("Received device dis- connect request");
136 close_a2dp_output();
137 }
138 }
139
140 ret = str_parms_get_str(parms, "A2dpSuspended", value, sizeof(value));
141 if (ret >= 0) {
142 if (a2dp.a2dp_device && a2dp.a2dp_stream) {
143 a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, str_parms_to_str(parms));
144 if (!strncmp(value,"true",sizeof(value))) {
145 a2dp.a2dp_suspended = true;
146 } else {
147 a2dp.a2dp_suspended = false;
148 }
149 }
150 }
151 }
152
audio_extn_a2dp_start_playback()153 void audio_extn_a2dp_start_playback()
154 {
155 int ret = 0;
156 char buf[20]={0};
157
158 if (!a2dp.a2dp_started && a2dp.a2dp_device && a2dp.a2dp_stream) {
159
160 snprintf(buf,sizeof(buf),"%s=true",AUDIO_PARAMETER_A2DP_STARTED);
161 /* This call indicates BT HAL to start playback */
162 ret = a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, buf);
163 if (ret < 0 ) {
164 ALOGE("BT controller start failed, retry on the next write");
165 a2dp.a2dp_started = false;
166 } else {
167 a2dp.a2dp_started = true;
168 ALOGV("Start playback successful to BT HAL");
169 }
170 }
171 }
172
audio_extn_a2dp_stop_playback()173 void audio_extn_a2dp_stop_playback()
174 {
175 int ret =0;
176 char buf[20]={0};
177
178 if ( a2dp.a2dp_started && a2dp.a2dp_device && a2dp.a2dp_stream) {
179
180 snprintf(buf,sizeof(buf),"%s=false",AUDIO_PARAMETER_A2DP_STARTED);
181
182 ret = a2dp.a2dp_device->set_parameters(a2dp.a2dp_device, buf);
183
184 if (ret < 0)
185 ALOGE("out_standby to BT HAL failed");
186 else
187 ALOGV("out_standby to BT HAL successful");
188
189 }
190 a2dp.a2dp_started = false;
191 a2dp.a2dp_suspended = true;
192 }
193
audio_extn_a2dp_init()194 void audio_extn_a2dp_init ()
195 {
196 a2dp.a2dp_started = false;
197 a2dp.a2dp_suspended = true;
198 a2dp.a2dp_stream = NULL;
199 a2dp.a2dp_device = NULL;
200 }
201 #endif // SPLIT_A2DP_ENABLED
202