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