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
45struct 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
52struct a2dp_data a2dp;
53
54#define AUDIO_PARAMETER_A2DP_STARTED "A2dpStarted"
55
56static 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
97static 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
114void 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
153void 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
173void 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
194void 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