1 /*
2 * Copyright (c) 2021 Chipsea Technologies (Shenzhen) Corp., Ltd. All rights reserved.
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 /*chipsea_ohos proguard begin*/
16 #include "cs_proguard.h"
17 /*chipsea_ohos proguard end*/
18 #include "cs_target_config.h"
19 #if APP_SUPPORT_A2DP_SBC == 1 || APP_SUPPORT_A2DP_AAC ==1 ||APP_SUPPORT_A2DP_SOURCE == 1
20 #include "al_rtos.h"
21 #include "app_bt.h"
22 #include "app_a2dp.h"
23 #if APP_SUPPORT_A2DP_SOURCE == 1
24 #include "app_a2dp_source.h"
25 #endif
26 #if APP_SUPPORT_TWS == 1
27 #include "app_tws.h"
28 #endif
29 #include "cs_adp_api.h"
30
31
32 app_a2dp_state_t t_a2dp_state = A2DP_IDLE;
33
34
35
app_get_a2dp_state(void)36 app_a2dp_state_t app_get_a2dp_state(void)
37 {
38 return t_a2dp_state;
39 }
40
app_set_a2dp_state(app_a2dp_state_t state)41 void app_set_a2dp_state(app_a2dp_state_t state)
42 {
43 APP_BT_MGR *app_bt_manager_ptr = cs_adp_get_app_bt_mgr_ptr();
44
45 if (t_a2dp_state == state){
46 return;
47 }
48
49 if(state == A2DP_PLAY){
50 #if TWS_SLAVE_CONNECT_MASTER == 1
51 if(app_bt_manager_ptr->connect_index == 1){
52 #if APP_SUPPORT_TWS == 1
53 if(tws_app_get_role() == TWS_SLAVE){
54 app_bt_set_scan_mode(BT_NOSCAN);
55 }else
56 #endif
57 {
58 app_bt_set_scan_mode(BT_CONNECTABLE);
59 }
60 }else if(app_bt_manager_ptr->connect_index >= 2){
61 app_bt_set_scan_mode(BT_NOSCAN);
62 }
63 #else
64 app_bt_set_scan_mode(BT_NOSCAN);
65 #endif
66 }
67 else if(t_a2dp_state == A2DP_PLAY && state != A2DP_PLAY){
68 if(app_bt_manager_ptr->connect_index == 1){
69 #if APP_SUPPORT_TWS == 1
70 if(tws_app_get_role() == TWS_SLAVE){
71 app_bt_set_scan_mode(BT_NOSCAN);
72 }else
73 #endif
74 {
75 #if APP_SUPPORT_LINK_ONE_ONLY == 1
76 app_bt_set_scan_mode(BT_NOSCAN);
77 #else
78 app_bt_set_scan_mode(BT_CONNECTABLE);
79 #endif
80 }
81 }else if(app_bt_manager_ptr->connect_index >= 2){
82 app_bt_set_scan_mode(BT_NOSCAN);
83 }
84 }
85 TRACE("APP:set a2dp state = %d\n",state);
86 t_a2dp_state = state;
87 }
88
89
bt_parse_sbc_sample_rate(uint8_t samp_rate)90 AUD_SAMPRATE_T bt_parse_sbc_sample_rate(uint8_t samp_rate)
91 {
92 AUD_SAMPRATE_T sample_rate = AUD_SAMPRATE_44100;
93 samp_rate = samp_rate & A2DP_CSIE_SAMP_FREQ_MSK;
94
95 switch (samp_rate)
96 {
97 case A2DP_CSIE_SAMP_FREQ_16:
98 sample_rate = AUD_SAMPRATE_16000;
99 break;
100 case A2DP_CSIE_SAMP_FREQ_32:
101 sample_rate = AUD_SAMPRATE_32000;
102 break;
103 case A2DP_CSIE_SAMP_FREQ_48:
104 sample_rate = AUD_SAMPRATE_48000;
105 break;
106 case A2DP_CSIE_SAMP_FREQ_44:
107 sample_rate = AUD_SAMPRATE_44100;
108 break;
109 default:
110 ASSERT_ERR(0);
111 break;
112 }
113 return sample_rate;
114 }
115
app_a2dp_pause(void)116 void app_a2dp_pause(void)
117 {
118 TRACE("APP:app_a2dp_pause.\n");
119 if(app_get_a2dp_state() == A2DP_PLAY){
120 app_media_play(AUD_BT_A2DP ,MC_STOP,0,true);
121 app_set_a2dp_state(A2DP_CONNECTED);
122 }
123 }
124
app_a2dp_play(BT_ADDR bdaddr)125 void app_a2dp_play(BT_ADDR bdaddr)
126 {
127 A2DP_AUDIO_CAP *audio_cap = NULL;
128 MediaCommonStruct audio_param;
129 memset((U8*)&audio_param, 0, sizeof(MediaCommonStruct));
130 audio_cap = cs_adp_a2dp_get_audio_cap_by_addr(bdaddr);
131 TRACE("APP:app_a2dp_play audio_cap = 0x%x\n",audio_cap);
132 if(audio_cap){
133 audio_param.p.aud_ctrl.a2dpcodec = audio_cap->codec_type;
134 audio_param.p.aud_ctrl.samplerate = bt_parse_sbc_sample_rate(audio_cap->sample_rate_bit);
135 //TODO add channel parsing
136 audio_param.p.aud_ctrl.channel = audio_cap->channel;
137 audio_param.p.aud_ctrl.numBlocks = audio_cap->numBlocks;
138 audio_param.p.aud_ctrl.numSubBands = audio_cap->numSubBands;
139 audio_param.p.aud_ctrl.dpll_mode = AUD_DPLL_NORMAL;
140 #if APP_SUPPORT_TWS == 1
141 if(tws_app_get_role() >= TWS_NOROLE){
142 app_media_play(AUD_BT_A2DP,MC_OPEN,&audio_param,true);
143 }else{
144 app_media_play(AUD_BT_A2DP ,MC_STOP,0,false);
145 app_media_play(AUD_BT_A2DP ,MC_OPEN,&audio_param,true);
146 }
147 #else
148 #if APP_SUPPORT_MULTIPLE_PHONE == 1
149 if(app_get_a2dp_state() == A2DP_PLAY)
150 app_media_play(AUD_BT_A2DP ,MC_STOP,0,true);
151 #endif
152 app_media_play(AUD_BT_A2DP,MC_OPEN,&audio_param,true);
153 #endif
154 app_set_a2dp_state(A2DP_PLAY);
155 }
156 }
157
158
app_handle_a2dp_connect_status(CS_EVENT * event)159 void app_handle_a2dp_connect_status(CS_EVENT *event)
160 {
161 CS_ADP_A2DP_EVENT *cs_a2dp_msg = (CS_ADP_A2DP_EVENT *)event->Param;
162 app_connect_manager * app_bt_con = NULL;
163
164 app_bt_con = app_bt_get_con_ptr_by_addr(&cs_a2dp_msg->bdaddr);
165 if(!app_bt_con ){
166 app_bt_con = app_bt_get_unused_con_ptr();
167 if(!app_bt_con){
168 TRACE("APP:app a2dp get con ptr error\n");
169 ASSERT_ERR(0);
170 }
171 memcpy(app_bt_con->remotedev_addr.addr,cs_a2dp_msg->bdaddr.addr, BD_ADDR_SIZE);
172 }
173
174 if(app_bt_con->reconnect.connect_timer_handle){
175 #if PLF_AON_SUPPORT
176 co_timer_stop(app_bt_con->reconnect.connect_timer_handle);
177 #else
178 rtos_timer_stop(app_bt_con->reconnect.connect_timer_handle,0);
179 #endif
180 app_bt_con->reconnect.connect_timer_cb = NULL;
181 }
182
183 switch(event->EventId){
184 case CS_ADP_A2DP_STREAM_OPEN:
185 {
186 btdev_info* dev_info = cs_adp_get_devinfo_by_addr(&cs_a2dp_msg->bdaddr);
187 if(dev_info){
188 A2DP_AUDIO_CAP *audio_cap = (A2DP_AUDIO_CAP *)cs_a2dp_msg->p.signalingP.audioCodecP;
189 dev_info->a2dp_state = 1;
190 dev_info->a2dp_codectype = audio_cap->codec_type;
191 dev_info->a2dp_role = cs_a2dp_msg->role;
192 }
193 app_bt_con->profile.a2dp_connect = CONNECTED;
194 memcpy(app_bt_con->remotedev_addr.addr, cs_a2dp_msg->bdaddr.addr, BD_ADDR_SIZE);
195 app_bt_con->reconnect.connect_retry_cnt = 0;
196
197 switch(app_bt_con->reconnect.reconnect_mode){
198 case RECONNECT_POWERON:
199 if(app_bt_con->profile.hfp_connect != CONNECTED){
200 app_bt_connect_hfp(&app_bt_con->remotedev_addr);
201 }
202 break;
203 case RECONNECT_AFTER_DISC:
204 if(app_bt_con->profile.hfp_connect != CONNECTED){
205 app_bt_connect_hfp(&app_bt_con->remotedev_addr);
206 }
207 break;
208 default:
209 app_bt_con->reconnect.reconnect_mode = RECONNECT_IDLE;
210 break;
211 }
212 }
213 break;
214 case CS_ADP_A2DP_STREAM_CLOSED:
215 {
216 app_bt_con->profile.a2dp_connect = DISCONNECTED;
217 switch(app_bt_con->reconnect.reconnect_mode){
218 case RECONNECT_POWERON:
219 app_bt_con->reconnect.reconnect_mode = RECONNECT_IDLE;
220 break;
221 case RECONNECT_AFTER_DISC:
222 if(app_bt_con->reconnect.connect_retry_cnt < APP_RECONNECT_NUM){
223 #if PLF_AON_SUPPORT
224 app_bt_start_reconnect(&app_bt_con->reconnect.connect_timer_handle,app_bt_con->reconnect.cb_param
225 ,APP_RECONNECT_INCREASE_TIME*app_bt_con->reconnect.connect_retry_cnt + APP_RECONNECT_TIME);
226 #else
227 app_bt_start_reconnect(app_bt_con->reconnect.connect_timer_handle
228 ,APP_RECONNECT_INCREASE_TIME*app_bt_con->reconnect.connect_retry_cnt + APP_RECONNECT_TIME);
229 #endif
230 app_bt_con->reconnect.connect_retry_cnt++;
231 }else{
232 app_bt_con->reconnect.reconnect_mode = RECONNECT_IDLE;
233 #if APP_SUPPORT_TWS == 1
234 app_tws_power_down();
235 #endif
236 }
237 break;
238 default:
239 if(cs_a2dp_msg->p.disc_reason == BT_CONNECTION_TIMEOUT){
240 app_bt_con->reconnect.reconnect_mode = RECONNECT_AFTER_DISC;
241 TRACE("APP:a2dp start reconnect\n");
242 #if PLF_AON_SUPPORT
243 app_bt_start_reconnect(&app_bt_con->reconnect.connect_timer_handle, app_bt_con->reconnect.cb_param, APP_RECONNECT_TIME);
244 #else
245 app_bt_start_reconnect(app_bt_con->reconnect.connect_timer_handle ,APP_RECONNECT_TIME);
246 #endif
247 }else{
248 app_bt_con->profile.a2dp_connect = CONNECT_IDLE;
249 }
250 break;
251 }
252 }
253 break;
254 default:
255 break;
256 }
257 app_bt_report_connect_internal_audio(app_bt_con);
258 }
259
app_a2dp_state_machine(CS_EVENT * event)260 void app_a2dp_state_machine(CS_EVENT *event)
261 {
262 //CS_ADP_A2DP_EVENT *cs_a2dp_msg = (CS_ADP_A2DP_EVENT *)event->Param;
263
264 switch(event->EventId){
265 case CS_ADP_A2DP_STREAM_OPEN:
266 if(app_get_a2dp_state() == A2DP_IDLE){
267 app_set_a2dp_state(A2DP_CONNECTED);
268 }
269 break;
270 case CS_ADP_A2DP_STREAM_CLOSED:
271 if(app_get_a2dp_state() != A2DP_PLAY)
272 app_set_a2dp_state(A2DP_IDLE);
273 break;
274 default:
275 break;
276 }
277 }
278
app_a2dp_msg_handle(CS_EVENT * event)279 void app_a2dp_msg_handle(CS_EVENT *event)
280 {
281 CS_ADP_A2DP_EVENT *cs_a2dp_msg = (CS_ADP_A2DP_EVENT *)event->Param;
282 app_a2dp_state_machine(event);
283
284 switch(event->EventId) {
285 case CS_ADP_A2DP_STREAM_OPEN:
286 {
287 if(cs_a2dp_msg->role == BT_A2DP_SOURCE){
288 #if APP_SUPPORT_A2DP_SOURCE == 1
289 #endif
290 }
291 app_handle_a2dp_connect_status(event);
292 }
293 break;
294 case CS_ADP_A2DP_STREAM_STARTED:
295 {
296 A2DP_AUDIO_CAP *audio_cap = (A2DP_AUDIO_CAP *)cs_a2dp_msg->p.signalingP.audioCodecP;
297 TRACE("APP:a2dp_stream_started role = %d, codec_type = %d , sample_rate_bit = %d\n",cs_a2dp_msg->role,audio_cap->codec_type, audio_cap->sample_rate_bit);
298 if(cs_a2dp_msg->role == BT_A2DP_SOURCE){
299 #if APP_SUPPORT_A2DP_SOURCE == 1
300 app_a2dp_source_sbc_data_send_timer_begin();
301 #endif
302 }else{
303 app_a2dp_play(cs_a2dp_msg->bdaddr);
304 }
305 }
306 break;
307 case CS_ADP_A2DP_STREAM_SUSPENDED:
308 {
309 TRACE("APP:a2dp_stream_suspended role = %d\n",cs_a2dp_msg->role);
310 if(cs_a2dp_msg->role == BT_A2DP_SINK){
311 app_a2dp_pause();
312 }
313 }
314 break;
315 case CS_ADP_A2DP_STREAM_CLOSED:
316 {
317 TRACE("APP:a2dp_stream_closed role = %d\n",cs_a2dp_msg->role);
318 if(cs_a2dp_msg->role == BT_A2DP_SINK){
319 app_a2dp_pause();
320 }
321 app_handle_a2dp_connect_status(event);
322 }
323 break;
324
325 case CS_ADP_A2DP_STREAM_PACKET_SENT:
326 TRACE("APP:a2dp source data send succ!\n");
327 if(cs_a2dp_msg->role == BT_A2DP_SOURCE){
328 #if APP_SUPPORT_A2DP_SOURCE == 1
329 app_a2dp_source_sbc_data_send_timer_begin();
330 #endif
331 }
332 break;
333 case CS_ADP_A2DP_STREAM_DATA_IND:
334 {
335 A2DP_AUDIO_CAP *audio_cap = (A2DP_AUDIO_CAP *)cs_a2dp_msg->p.mediaP.audioCodecP;
336 A2DP_AUDIO_DATA *audio_data = (A2DP_AUDIO_DATA *)cs_a2dp_msg->p.mediaP.audioDataP;
337
338 if(app_get_a2dp_state() == A2DP_PLAY){
339 AppReceive_A2dpData(((unsigned char *)audio_data->data)+ audio_data->headerlen ,
340 audio_data->datalen - audio_data->headerlen,
341 audio_cap->sbc_frame_number ,
342 bt_parse_sbc_sample_rate(audio_cap->sample_rate_bit));
343 }else{
344 TRACE("APP:free a2dp stream data\n");
345 }
346 }
347 break;
348 default:
349 break;
350 }
351
352 }
353
354 #endif
355
356
357