Arduino A2DP
BluetoothA2DPCommon.h
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 //
13 // Copyright 2020 Phil Schatzmann
14 
24 #pragma once
25 #include "config.h"
26 // If you use #include "I2S.h" the i2s functionality is hidden in a namespace
27 // this hack prevents any error messages
28 #ifdef _I2S_H_INCLUDED
29 using namespace esp_i2s;
30 #endif
31 // Compile only for ESP32
32 #if defined(CONFIG_IDF_TARGET_ESP32C2) || \
33  defined(CONFIG_IDF_TARGET_ESP32C3) || \
34  defined(CONFIG_IDF_TARGET_ESP32C5) || \
35  defined(CONFIG_IDF_TARGET_ESP32C6) || \
36  defined(CONFIG_IDF_TARGET_ESP32S2) || \
37  defined(CONFIG_IDF_TARGET_ESP32S3) || \
38  defined(CONFIG_IDF_TARGET_ESP32H2) || \
39  defined(CONFIG_IDF_TARGET_ESP32P4)
40 #error "ESP32C3, ESP32S2, ESP32S3... do not support A2DP"
41 #endif
42 
43 #include <math.h>
44 #include <stdbool.h>
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 
51 #include <vector>
52 
53 #include "esp_idf_version.h"
54 #include "freertos/FreeRTOS.h" // needed for ESP Arduino < 2.0
55 #include "freertos/FreeRTOSConfig.h"
56 #include "freertos/queue.h"
57 #include "freertos/task.h"
58 #include "freertos/timers.h"
59 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
60 #include "freertos/xtensa_api.h"
61 #else
62 #include "xtensa_api.h"
63 #endif
64 #include "A2DPVolumeControl.h"
65 #include "esp_a2dp_api.h"
66 #include "esp_avrc_api.h"
67 #include "esp_bt.h"
68 #include "esp_bt_device.h"
69 #include "esp_bt_main.h"
70 #include "esp_gap_bt_api.h"
71 #include "esp_spp_api.h"
72 #include "esp_task_wdt.h"
73 #include "esp_timer.h"
74 #include "nvs.h"
75 #include "nvs_flash.h"
76 
77 #ifdef ARDUINO_ARCH_ESP32
78 #include "esp32-hal-bt.h"
79 #include "esp32-hal-log.h"
80 #else
81 #include "esp_log.h"
82 #endif
83 
84 #if !defined(ESP_IDF_VERSION)
85 #error Unsupported ESP32 Version: Upgrade the ESP32 version in the Board Manager
86 #endif
87 
88 // Support for old and new IDF version
89 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0) && \
90  !defined(I2S_COMM_FORMAT_STAND_I2S)
91 // support for old idf releases
92 #define I2S_COMM_FORMAT_STAND_I2S \
93  (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB)
94 #define I2S_COMM_FORMAT_STAND_MSB \
95  (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB)
96 #define I2S_COMM_FORMAT_STAND_PCM_LONG \
97  (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG)
98 #define I2S_COMM_FORMAT_STAND_PCM_SHORT \
99  (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT)
100 #endif
101 
102 // Prior IDF 5 support
103 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
104 #define TaskHandle_t xTaskHandle
105 #define QueueHandle_t xQueueHandle
106 #define TickType_t portTickType
107 #endif
108 
109 #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
110 #define esp_bt_gap_set_device_name esp_bt_dev_set_device_name
111 #endif
112 
113 #define A2DP_DEPRECATED __attribute__((deprecated))
114 
115 #define BT_APP_SIG_WORK_DISPATCH (0x01)
116 
120 typedef void (*app_callback_t)(uint16_t event, void *param);
121 
124 typedef struct {
125  uint16_t sig;
126  uint16_t event;
128  void *param;
129 } bt_app_msg_t;
130 
131 #define BT_AV_TAG "BT_AV"
132 #define BT_RC_CT_TAG "RCCT"
133 #define BT_APP_TAG "BT_API"
134 
135 // AVRCP used transaction labels
136 #define APP_RC_CT_TL_GET_CAPS (0)
137 #define APP_RC_CT_TL_GET_META_DATA (1)
138 #define APP_RC_CT_TL_RN_TRACK_CHANGE (2)
139 #define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
140 #define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
141 
142 // common a2dp callbacks
143 extern "C" void ccall_bt_app_task_handler(void *arg);
144 extern "C" void ccall_app_gap_callback(esp_bt_gap_cb_event_t event,
145  esp_bt_gap_cb_param_t *param);
146 extern "C" void ccall_app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
147  esp_avrc_ct_cb_param_t *param);
148 extern "C" void ccall_app_a2d_callback(esp_a2d_cb_event_t event,
149  esp_a2d_cb_param_t *param);
150 extern "C" void ccall_av_hdl_stack_evt(uint16_t event, void *p_param);
151 
152 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
153 extern "C" void ccall_app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
154  esp_avrc_tg_cb_param_t *param);
155 extern "C" void ccall_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
156 #endif
157 
162 enum ReconnectStatus { NoReconnect, AutoReconnect, IsReconnecting };
163 
171  friend void ccall_bt_app_task_handler(void *arg);
172  friend void ccall_app_gap_callback(esp_bt_gap_cb_event_t event,
173  esp_bt_gap_cb_param_t *param);
174  friend void ccall_app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
175  esp_avrc_ct_cb_param_t *param);
176  friend void ccall_app_a2d_callback(esp_a2d_cb_event_t event,
177  esp_a2d_cb_param_t *param);
178  friend void ccall_av_hdl_stack_evt(uint16_t event, void *p_param);
179 
180 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
182  friend void ccall_app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
183  esp_avrc_tg_cb_param_t *param);
184  /* avrc TG event handler */
185  friend void ccall_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
186 #endif
187 
188  public:
192  virtual ~BluetoothA2DPCommon() = default;
193 
196  void set_auto_reconnect(bool active);
197 
199  virtual void disconnect();
200 
202  virtual bool reconnect();
203 
205  virtual bool connect_to(esp_bd_addr_t peer);
206 
208  virtual void set_connected(bool active);
209 
211  virtual void end(bool releaseMemory = false);
212 
214  virtual bool is_connected() {
215  return connection_state == ESP_A2D_CONNECTION_STATE_CONNECTED;
216  }
217 
219  virtual void set_volume(uint8_t volume) {
220  volume_value = std::min((int)volume, 0x7F);
221  ESP_LOGI(BT_AV_TAG, "set_volume: %d", volume_value);
222  volume_control()->set_volume(volume_value);
223  volume_control()->set_enabled(true);
224  is_volume_used = true;
225  }
226 
228  virtual int get_volume() { return is_volume_used ? volume_value : 0; }
229 
232  volume_control_ptr = ptr;
233  }
234 
236  virtual esp_a2d_audio_state_t get_audio_state();
237 
239  virtual esp_a2d_connection_state_t get_connection_state();
240 
243  virtual void set_on_connection_state_changed(
244  void (*callBack)(esp_a2d_connection_state_t state, void *),
245  void *obj = nullptr);
246 
249  virtual void set_on_audio_state_changed_post(
250  void (*callBack)(esp_a2d_audio_state_t state, void *),
251  void *obj = nullptr);
252 
254  virtual void set_on_audio_state_changed(
255  void (*callBack)(esp_a2d_audio_state_t state, void *),
256  void *obj = nullptr);
257 
260  virtual void debounce(void (*cb)(void), int ms);
261 
263  void log_free_heap();
264 
266  const char *to_str(esp_a2d_connection_state_t state);
267 
269  const char *to_str(esp_a2d_audio_state_t state);
270 
272  const char *to_str(esp_bd_addr_t bda);
273 
274 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
276  const char *to_str(esp_avrc_playback_stat_t state);
277 #endif
278 
280  void set_task_priority(UBaseType_t priority) { task_priority = priority; }
281 
284  void set_task_core(BaseType_t core) { task_core = core; }
285 
287  void set_event_queue_size(int size) { event_queue_size = size; }
288 
290  void set_event_stack_size(int size) { event_stack_size = size; }
291 
293  virtual esp_bd_addr_t *get_last_peer_address() { return &last_connection; }
294 
295 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
297  virtual void set_discoverability(esp_bt_discovery_mode_t d);
298 #endif
299 
301  virtual void set_connectable(bool connectable) {
302  set_scan_mode_connectable(connectable);
303  }
304 
306  virtual const char *get_name() { return bt_name; }
307 
309  virtual void clean_last_connection();
310 
313  virtual void set_default_bt_mode(esp_bt_mode_t mode) { bt_mode = mode; }
314 
315 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 1)
317  void set_bluedroid_config_t(esp_bluedroid_config_t cfg) {
318  bluedroid_config = cfg;
319  }
320 #endif
322  void delay_ms(uint32_t millis);
324  unsigned long get_millis();
325 
334  virtual void set_avrc_rn_events(std::vector<esp_avrc_rn_event_ids_t> events) {
335  avrc_rn_events = events;
336  }
337 
338  protected:
339  const char *bt_name = {0};
340  esp_bd_addr_t peer_bd_addr;
341  ReconnectStatus reconnect_status = NoReconnect;
342  unsigned long reconnect_timout = 0;
343  unsigned int default_reconnect_timout = 10000;
344  bool is_autoreconnect_allowed = false;
345  uint32_t debounce_ms = 0;
346  A2DPDefaultVolumeControl default_volume_control;
347  A2DPVolumeControl *volume_control_ptr = nullptr;
348  esp_bd_addr_t last_connection = {0, 0, 0, 0, 0, 0};
349  bool is_start_disabled = false;
350  bool is_target_status_active = true;
351  void (*connection_state_callback)(esp_a2d_connection_state_t state,
352  void *obj) = nullptr;
353  void (*audio_state_callback)(esp_a2d_audio_state_t state,
354  void *obj) = nullptr;
355  void (*audio_state_callback_post)(esp_a2d_audio_state_t state,
356  void *obj) = nullptr;
357  void *connection_state_obj = nullptr;
358  void *audio_state_obj = nullptr;
359  void *audio_state_obj_post = nullptr;
360  const char *m_a2d_conn_state_str[4] = {"Disconnected", "Connecting",
361  "Connected", "Disconnecting"};
362  const char *m_a2d_audio_state_str[4] = {"Suspended", "Started", "Suspended", "Suspended"};
363  const char *m_avrc_playback_state_str[5] = {"stopped", "playing", "paused",
364  "forward seek", "reverse seek"};
366  esp_a2d_connection_state_t connection_state =
368  UBaseType_t task_priority = configMAX_PRIORITIES - 10;
369  // volume
370  uint8_t volume_value = 0;
371  bool is_volume_used = false;
372  BaseType_t task_core = 1;
373 
374  int event_queue_size = 20;
375  int event_stack_size = 3072;
377  std::vector<esp_avrc_rn_event_ids_t> avrc_rn_events = {
378  ESP_AVRC_RN_VOLUME_CHANGE};
379 
380  QueueHandle_t app_task_queue = nullptr;
381  TaskHandle_t app_task_handle = nullptr;
382 
383 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 1)
384  esp_bluedroid_config_t bluedroid_config{.ssp_en = true};
385 #endif
386 
387  virtual void init_nvs();
388  virtual esp_err_t esp_a2d_connect(esp_bd_addr_t peer) = 0;
389  virtual const char *last_bda_nvs_name() = 0;
390  virtual void get_last_connection();
391  virtual void set_last_connection(esp_bd_addr_t bda);
392  virtual bool has_last_connection();
393  virtual bool read_address(const char *name, esp_bd_addr_t &bda);
394  virtual bool write_address(const char *name, esp_bd_addr_t bda);
395 
396  // change the scan mode
397  virtual void set_scan_mode_connectable(bool connectable);
398  virtual void set_scan_mode_connectable_default() = 0;
399 
402  return volume_control_ptr != nullptr ? volume_control_ptr
403  : &default_volume_control;
404  }
405 
406  virtual bool bt_start();
407  virtual esp_err_t bluedroid_init();
408  virtual esp_err_t esp_a2d_disconnect(esp_bd_addr_t remote_bda) = 0;
409  virtual void app_task_start_up();
410  virtual void app_task_shut_down();
411  virtual bool app_send_msg(bt_app_msg_t *msg);
412  virtual void app_task_handler(void *arg);
413  virtual void app_work_dispatched(bt_app_msg_t *msg);
414  virtual bool isSource() = 0;
415  // GAP callback
416  virtual void app_gap_callback(esp_bt_gap_cb_event_t event,
417  esp_bt_gap_cb_param_t *param) = 0;
419  virtual void app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
420  esp_avrc_ct_cb_param_t *param) = 0;
422  virtual void app_a2d_callback(esp_a2d_cb_event_t event,
423  esp_a2d_cb_param_t *param) = 0;
424  // handler for bluetooth stack enabled events
425  virtual void av_hdl_stack_evt(uint16_t event, void *p_param) = 0;
426 
427 #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
429  virtual void app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
430  esp_avrc_tg_cb_param_t *param) = 0;
431  virtual void av_hdl_avrc_tg_evt(uint16_t event, void *p_param) = 0;
432 #endif
433 
434 };
435 
436 extern BluetoothA2DPCommon *actual_bluetooth_a2dp_common;
void(* app_callback_t)(uint16_t event, void *param)
handler for the dispatched work
Definition: BluetoothA2DPCommon.h:120
Default implementation for handling of the volume of the audio data.
Definition: A2DPVolumeControl.h:105
Abstract class for handling of the volume of the audio data.
Definition: A2DPVolumeControl.h:45
Common Bluetooth A2DP functions.
Definition: BluetoothA2DPCommon.h:169
void set_event_stack_size(int size)
Defines the stack size of the event task (in bytes)
Definition: BluetoothA2DPCommon.h:290
virtual void set_volume(uint8_t volume)
Sets the volume (range 0 - 127)
Definition: BluetoothA2DPCommon.h:219
virtual int get_volume()
Determines the actual volume.
Definition: BluetoothA2DPCommon.h:228
void set_bluedroid_config_t(esp_bluedroid_config_t cfg)
Defines the esp_bluedroid_config_t: Available from IDF 5.2.1.
Definition: BluetoothA2DPCommon.h:317
virtual void set_avrc_rn_events(std::vector< esp_avrc_rn_event_ids_t > events)
Definition: BluetoothA2DPCommon.h:334
virtual void set_default_bt_mode(esp_bt_mode_t mode)
Definition: BluetoothA2DPCommon.h:313
virtual ~BluetoothA2DPCommon()=default
Destructor.
virtual bool is_connected()
Checks if A2DP is connected.
Definition: BluetoothA2DPCommon.h:214
void set_task_priority(UBaseType_t priority)
defines the task priority (the default value is configMAX_PRIORITIES - 10)
Definition: BluetoothA2DPCommon.h:280
void set_task_core(BaseType_t core)
Definition: BluetoothA2DPCommon.h:284
virtual void app_a2d_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)=0
callback function for A2DP source
virtual A2DPVolumeControl * volume_control()
provides access to the VolumeControl object
Definition: BluetoothA2DPCommon.h:401
virtual const char * get_name()
Provides the actual SSID name.
Definition: BluetoothA2DPCommon.h:306
virtual void set_volume_control(A2DPVolumeControl *ptr)
you can define a custom VolumeControl implementation
Definition: BluetoothA2DPCommon.h:231
virtual void set_connectable(bool connectable)
Bluetooth connectable.
Definition: BluetoothA2DPCommon.h:301
virtual esp_bd_addr_t * get_last_peer_address()
Provides the address of the last device.
Definition: BluetoothA2DPCommon.h:293
virtual void app_rc_ct_callback(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)=0
callback function for AVRCP controller
void set_event_queue_size(int size)
Defines the queue size of the event task.
Definition: BluetoothA2DPCommon.h:287
ReconnectStatus
Buetooth A2DP Reconnect Status.
Definition: BluetoothA2DPCommon.h:162
esp_a2d_audio_state_t
Buetooth A2DP datapath states.
Definition: external_lists.h:5
esp_a2d_connection_state_t
Buetooth A2DP connection states.
Definition: external_lists.h:16
esp_bt_discovery_mode_t
AVRCP discovery mode.
Definition: external_lists.h:85
esp_avrc_playback_stat_t
AVRCP current status of playback.
Definition: external_lists.h:72
esp_bt_mode_t
Bluetooth Controller mode.
Definition: external_lists.h:96
uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]
Bluetooth address.
Definition: external_lists.h:107
@ ESP_A2D_AUDIO_STATE_STOPPED
Definition: external_lists.h:8
@ ESP_A2D_CONNECTION_STATE_CONNECTED
Definition: external_lists.h:19
@ ESP_A2D_CONNECTION_STATE_DISCONNECTED
Definition: external_lists.h:17
@ ESP_BT_GENERAL_DISCOVERABLE
Definition: external_lists.h:88
@ ESP_BT_MODE_CLASSIC_BT
Definition: external_lists.h:99
Internal message to be sent for BluetoothA2DPSink and BluetoothA2DPSource.
Definition: BluetoothA2DPCommon.h:124
uint16_t sig
Definition: BluetoothA2DPCommon.h:125
app_callback_t cb
Definition: BluetoothA2DPCommon.h:127
uint16_t event
Definition: BluetoothA2DPCommon.h:126
void * param
Definition: BluetoothA2DPCommon.h:128