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