Arduino A2DP
Loading...
Searching...
No Matches
BluetoothA2DPSource.h
1// C++ Class Implementation for a A2DP Source to be used as Arduino Library
2// The original ESP32 implementation can be found at
3// https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/classic_bt/a2dp_source
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// Copyright 2020 Phil Schatzmann
18// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
19
20#pragma once
21
22#include <vector>
23
24#include "BluetoothA2DPCommon.h"
25
26#if IS_VALID_PLATFORM
27
28#ifdef ARDUINO
29#include "Stream.h"
30#endif
31
32#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0))
33#define TIMER_ARG_TYPE void*
34#else
35#define TIMER_ARG_TYPE tmrTimerControl*
36#endif
37
38typedef int32_t (*music_data_cb_t)(uint8_t* data, int32_t len);
39typedef int32_t (*music_data_frames_cb_t)(Frame* data, int32_t len);
40typedef void (*bt_app_copy_cb_t)(bt_app_msg_t* msg, void* p_dest, void* p_src);
41typedef void (*bt_app_cb_t)(uint16_t event, void* param);
42
43extern "C" void ccall_a2d_app_heart_beat(TIMER_ARG_TYPE arg);
44extern "C" void ccall_bt_app_av_sm_hdlr(uint16_t event, void* param);
45extern "C" void ccall_bt_av_hdl_avrc_ct_evt(uint16_t event, void* param);
46extern "C" int32_t ccall_bt_app_a2d_data_cb(uint8_t* data, int32_t len);
47
53 APP_AV_STATE_IDLE,
54 APP_AV_STATE_DISCOVERING,
55 APP_AV_STATE_DISCOVERED,
56 APP_AV_STATE_UNCONNECTED,
57 APP_AV_STATE_CONNECTING,
58 APP_AV_STATE_CONNECTED,
59 APP_AV_STATE_DISCONNECTING,
60};
61
62static const char* APP_AV_STATE_STR[] = {
63 "IDLE", "DISCOVERING", "DISCOVERED", "UNCONNECTED",
64 "CONNECTING", "CONNECTED", "DISCONNECTING"};
65
100 friend void ccall_a2d_app_heart_beat(TIMER_ARG_TYPE arg);
101 friend void ccall_bt_app_av_sm_hdlr(uint16_t event, void* param);
102 friend void ccall_bt_av_hdl_avrc_ct_evt(uint16_t event, void* param);
103 friend int32_t ccall_bt_app_a2d_data_cb(uint8_t* data, int32_t len);
104
105 public:
108
111
113 virtual void set_ssp_enabled(bool active) { this->ssp_enabled = active; }
114
118 virtual void set_auto_reconnect(bool active,
119 int max_retries = AUTOCONNECT_TRY_NUM) {
120 this->reconnect_status = active ? AutoReconnect : NoReconnect;
121 this->max_reconnect_retries = max_retries;
122 this->reconnect_retries = max_reconnect_retries;
123 }
124
127 virtual void set_auto_reconnect(esp_bd_addr_t addr, int max_retries = 3) {
128 set_auto_reconnect(true, max_retries);
129 memcpy(last_connection, addr, ESP_BD_ADDR_LEN);
130 }
131
133 virtual void set_local_name(const char* name) { dev_name = name; }
134
136 virtual void set_data_callback(int32_t(cb)(uint8_t* data, int32_t len)) {
137 get_data_cb = cb;
138 }
139
141 virtual void set_data_callback_in_frames(int32_t(cb)(Frame* data,
142 int32_t len)) {
143 get_data_in_frames_cb = cb;
144 }
145
146#ifdef ARDUINO
147
149 virtual void set_data_source(Stream& data) { p_stream = &data; }
151 virtual void set_data_source_callback(Stream& (*next_stream)()) {
152 get_next_stream_cb = next_stream;
153 }
154#endif
155
158 virtual void start() {
159 std::vector<const char*> names; // empty vector
160 start(names);
161 }
162
164 virtual void start(const char* name) {
165 std::vector<const char*> names = {name}; // empty vector
166 start(names);
167 }
168
170 virtual void start(std::vector<const char*> names);
171
173 virtual void start(const char* name, music_data_frames_cb_t callback) {
175 std::vector<const char*> names = {name};
176 start(names);
177 }
178
180 virtual void start(music_data_frames_cb_t callback) {
182 start();
183 }
184
186 virtual void start(std::vector<const char*> names,
187 // Prevent auto-reconnect after willful disconnect
188 music_data_frames_cb_t callback) {
190 start(names);
191 }
192
194 virtual void start_raw(const char* name, music_data_cb_t callback = nullptr) {
195 set_data_callback(callback);
196 start(name);
197 }
198
200 virtual void start_raw(std::vector<const char*> names,
201 music_data_cb_t callback = nullptr) {
202 set_data_callback(callback);
203 start(names);
204 }
205
207 virtual void start_raw(music_data_cb_t callback = nullptr) {
208 set_data_callback(callback);
209 start();
210 }
211
213 void set_pin_code(const char* pin_code, esp_bt_pin_type_t pin_type);
214
216 virtual void set_reset_ble(bool doInit);
217
219 virtual void set_ssid_callback(bool (*callback)(const char* ssid,
220 esp_bd_addr_t address,
221 int rrsi)) {
222 ssid_callback = callback;
223 }
224
227 void (*callback)(esp_bt_gap_discovery_state_t discoveryMode)) {
228 discovery_mode_callback = callback;
229 }
230
233 virtual bool is_discovery_active() { return discovery_active; }
234
238 virtual void set_valid_cod_service(uint16_t filter) {
239 this->valid_cod_services = filter;
240 }
241
243 virtual void set_avrc_passthru_command_callback(void (*cb)(uint8_t key,
244 bool isReleased)) {
245 passthru_command_callback = cb;
246 is_passthru_active = (cb != nullptr);
247 }
248
250 virtual void cancel_discovery() {
251 is_end = true;
252 esp_bt_gap_cancel_discovery();
253 }
254
256 void end(bool releaseMemory = false) override;
257
259 unsigned long get_last_heart_beat() { return last_heart_beat; }
260
262 bool is_active(unsigned long timeout = 10000);
263
264 protected:
266 int32_t (*get_data_cb)(uint8_t* data, int32_t len) = nullptr;
267 int32_t (*get_data_in_frames_cb)(Frame* data, int32_t len) = nullptr;
268#ifdef ARDUINO
269 Stream* p_stream = nullptr;
270 Stream& (*get_next_stream_cb)() = nullptr;
271#endif
272 const char* dev_name = "ESP32_A2DP_SRC";
273 bool ssp_enabled = false;
274 std::vector<const char*> bt_names;
275 esp_bt_pin_type_t pin_type;
276 esp_bt_pin_code_t pin_code;
277 uint32_t pin_code_len;
278 uint8_t s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
279 APP_AV_STATE s_a2d_state = APP_AV_STATE_IDLE; // Next Target Connection State
280 APP_AV_STATE s_a2d_last_state =
281 APP_AV_STATE_IDLE; // Next Target Connection State
282 int s_media_state = 0;
283 int s_intv_cnt = 0;
284 int s_connecting_heatbeat_count;
285 uint32_t s_pkt_cnt;
286 TimerHandle_t s_tmr;
287
288 // initialization
289 bool reset_ble = false;
290 bool discovery_active = false;
291 uint16_t valid_cod_services = ESP_BT_COD_SRVC_RENDERING |
292 ESP_BT_COD_SRVC_AUDIO |
293 ESP_BT_COD_SRVC_TELEPHONY;
294
295 bool (*ssid_callback)(const char* ssid, esp_bd_addr_t address,
296 int rrsi) = nullptr;
297 void (*discovery_mode_callback)(esp_bt_gap_discovery_state_t discoveryMode) =
298 nullptr;
299 void (*passthru_command_callback)(uint8_t, bool) = nullptr;
300 bool is_passthru_active = false;
301 bool is_end = false;
302 // Retry logic for auto reconnect
303 int reconnect_retries = 0;
304 int max_reconnect_retries = 0;
305 unsigned long last_heart_beat = 0;
306
307#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
308 esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
309#endif
310
311 void app_gap_callback(esp_bt_gap_cb_event_t event,
312 esp_bt_gap_cb_param_t* param) override;
313 void app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
314 esp_avrc_ct_cb_param_t* param) override;
315 void app_a2d_callback(esp_a2d_cb_event_t event,
316 esp_a2d_cb_param_t* param) override;
317 void av_hdl_stack_evt(uint16_t event, void* p_param) override;
318
320 virtual int32_t get_audio_data(uint8_t* data, int32_t len);
322 virtual int32_t get_audio_data_volume(uint8_t* data, int32_t len);
323
324 virtual void process_user_state_callbacks(uint16_t event, void* param);
325
326 virtual bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event,
327 void* p_params, int param_len,
328 bt_app_copy_cb_t p_copy_cback);
329 virtual void bt_app_av_media_proc(uint16_t event, void* param);
330
332 virtual void bt_app_av_state_unconnected_hdlr(uint16_t event, void* param);
333 virtual void bt_app_av_state_connecting_hdlr(uint16_t event, void* param);
334 virtual void bt_app_av_state_connected_hdlr(uint16_t event, void* param);
335 virtual void bt_app_av_state_disconnecting_hdlr(uint16_t event, void* param);
336
337 virtual bool get_name_from_eir(uint8_t* eir, uint8_t* bdname,
338 uint8_t* bdname_len);
339 virtual void filter_inquiry_scan_result(esp_bt_gap_cb_param_t* param);
340
341 virtual const char* last_bda_nvs_name() { return "src_bda"; }
342
343 virtual void a2d_app_heart_beat(void* arg);
345 virtual void bt_app_av_sm_hdlr(uint16_t event, void* param);
347 virtual void bt_av_hdl_avrc_ct_evt(uint16_t event, void* p_param);
349 virtual void reset_last_connection();
352 virtual bool is_valid_cod_service(uint32_t cod);
353
354 esp_err_t esp_a2d_connect(esp_bd_addr_t peer) override {
355 ESP_LOGI(BT_AV_TAG, "==> a2dp connecting to: %s", to_str(peer));
356 s_media_state = 0;
357 s_a2d_state = APP_AV_STATE_CONNECTING;
358 return esp_a2d_source_connect(peer);
359 }
360
361 esp_err_t esp_a2d_disconnect(esp_bd_addr_t peer) override {
362 ESP_LOGI(BT_AV_TAG, "==> a2dp esp_a2d_source_disconnect from: %s",
363 to_str(peer));
364 esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_SUSPEND);
365 return esp_a2d_source_disconnect(peer);
366 }
367
369 const char* to_state_str(int state) { return APP_AV_STATE_STR[state]; }
373
374 void set_scan_mode_connectable_default() override {
376 }
377
378#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
379 virtual void bt_av_notify_evt_handler(uint8_t event,
380 esp_avrc_rn_param_t* param);
381 virtual void bt_av_volume_changed(void);
382 virtual void app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
383 esp_avrc_tg_cb_param_t* param) override;
384 virtual void av_hdl_avrc_tg_evt(uint16_t event, void* p_param) override;
385 virtual bool isSource() { return true; }
386
387#endif
388};
389
390#endif // platform
Common Bluetooth A2DP functions.
Definition BluetoothA2DPCommon.h:182
const char * to_str(esp_a2d_connection_state_t state)
converts esp_a2d_connection_state_t to a string
Definition BluetoothA2DPCommon.cpp:375
virtual void set_scan_mode_connectable(bool connectable)
Defines if the bluetooth is connectable.
Definition BluetoothA2DPCommon.cpp:575
BluetoothA2DPSource implements a flexible, extensible A2DP Bluetooth audio source for ESP32.
Definition BluetoothA2DPSource.h:99
virtual void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param)
A2DP application state machine handler for each state.
Definition BluetoothA2DPSource.cpp:654
virtual int32_t get_audio_data_volume(uint8_t *data, int32_t len)
provides the audio after applying the volume
Definition BluetoothA2DPSource.cpp:188
virtual void start_raw(std::vector< const char * > names, music_data_cb_t callback=nullptr)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:200
void set_pin_code(const char *pin_code, esp_bt_pin_type_t pin_type)
Defines the pin code. If nothing is defined we use "1234".
Definition BluetoothA2DPSource.cpp:87
virtual void reset_last_connection()
resets the last connectioin so that we can reconnect
Definition BluetoothA2DPSource.cpp:220
virtual void start(std::vector< const char * > names, music_data_frames_cb_t callback)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:186
virtual void set_auto_reconnect(esp_bd_addr_t addr, int max_retries=3)
Definition BluetoothA2DPSource.h:127
void app_rc_ct_callback(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) override
callback function for AVRCP controller
Definition BluetoothA2DPSource.cpp:926
virtual void cancel_discovery()
Cancels the discovery.
Definition BluetoothA2DPSource.h:250
virtual void set_valid_cod_service(uint16_t filter)
Definition BluetoothA2DPSource.h:238
virtual int32_t get_audio_data(uint8_t *data, int32_t len)
provides the audio data to be sent
Definition BluetoothA2DPSource.cpp:195
virtual void start_raw(music_data_cb_t callback=nullptr)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:207
~BluetoothA2DPSource()
Destructor.
Definition BluetoothA2DPSource.cpp:80
const char * to_state_str(int state)
converts a APP_AV_STATE_ENUM to a string
Definition BluetoothA2DPSource.h:369
virtual bool is_valid_cod_service(uint32_t cod)
Definition BluetoothA2DPSource.cpp:296
BluetoothA2DPSource()
Constructor.
Definition BluetoothA2DPSource.cpp:60
unsigned long get_last_heart_beat()
Gets the time of the last heart beat.
Definition BluetoothA2DPSource.h:259
virtual void set_reset_ble(bool doInit)
Defines if the BLE should be reset on start.
Definition BluetoothA2DPSource.cpp:1095
virtual void start(const char *name, music_data_frames_cb_t callback)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:173
virtual void set_ssid_callback(bool(*callback)(const char *ssid, esp_bd_addr_t address, int rrsi))
Define callback to be notified about the found ssids.
Definition BluetoothA2DPSource.h:219
virtual void set_avrc_passthru_command_callback(void(*cb)(uint8_t key, bool isReleased))
Define the handler fur button presses on the remote bluetooth speaker.
Definition BluetoothA2DPSource.h:243
virtual void set_discovery_mode_callback(void(*callback)(esp_bt_gap_discovery_state_t discoveryMode))
Define callback to be notified about bt discovery mode state changes.
Definition BluetoothA2DPSource.h:226
virtual void set_data_source(Stream &data)
Defines a single Arduino Stream (e.g. File) as audio source.
Definition BluetoothA2DPSource.h:149
virtual void set_data_source_callback(Stream &(*next_stream)())
Provide a callback which provides streams.
Definition BluetoothA2DPSource.h:151
virtual void set_ssp_enabled(bool active)
activate Secure Simple Pairing
Definition BluetoothA2DPSource.h:113
virtual void start()
Definition BluetoothA2DPSource.h:158
virtual void set_data_callback(int32_t(cb)(uint8_t *data, int32_t len))
Defines the data callback.
Definition BluetoothA2DPSource.h:136
void app_a2d_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) override
callback function for A2DP source
Definition BluetoothA2DPSource.cpp:575
bool handle_reconnect_logic()
Definition BluetoothA2DPSource.cpp:700
virtual void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
Definition BluetoothA2DPSource.cpp:722
int32_t(* get_data_cb)(uint8_t *data, int32_t len)
callback for data
Definition BluetoothA2DPSource.h:266
virtual void set_auto_reconnect(bool active, int max_retries=AUTOCONNECT_TRY_NUM)
Definition BluetoothA2DPSource.h:118
virtual void set_local_name(const char *name)
Defines the local name.
Definition BluetoothA2DPSource.h:133
virtual void start(music_data_frames_cb_t callback)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:180
virtual void bt_app_av_sm_hdlr(uint16_t event, void *param)
A2DP application state machine.
Definition BluetoothA2DPSource.cpp:625
virtual void set_data_callback_in_frames(int32_t(cb)(Frame *data, int32_t len))
Defines the data callback.
Definition BluetoothA2DPSource.h:141
virtual void start_raw(const char *name, music_data_cb_t callback=nullptr)
Obsolete: use the start w/o callback and set the callback separately.
Definition BluetoothA2DPSource.h:194
bool is_active(unsigned long timeout=10000)
Check if the target speaker is still active by checking the time of the last heart beat.
Definition BluetoothA2DPSource.cpp:82
virtual void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
avrc CT event handler
Definition BluetoothA2DPSource.cpp:986
void end(bool releaseMemory=false) override
Ends the processing and releases the resources.
Definition BluetoothA2DPSource.cpp:163
virtual bool is_discovery_active()
Definition BluetoothA2DPSource.h:233
virtual void start(const char *name)
Starts the A2DP source.
Definition BluetoothA2DPSource.h:164
APP_AV_STATE
Buetooth A2DP global state.
Definition BluetoothA2DPSource.h:52
uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]
Bluetooth address.
Definition external_lists.h:107
Internal message to be sent for BluetoothA2DPSink and BluetoothA2DPSource.
Definition BluetoothA2DPCommon.h:137