Arduino A2DP
Loading...
Searching...
No Matches
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
26// Compile only for ESP32
27#ifdef ARDUINO_ARCH_ESP32
28# include "sdkconfig.h"
29#endif
30#if defined(CONFIG_IDF_TARGET_ESP32)
31# define IS_VALID_PLATFORM true
32#elif defined(CONFIG_IDF_TARGET_ESP32S31)
33# define IS_VALID_PLATFORM true
34#else
35# error "Please read the ESP32-A2DP Wiki about the supported Platforms!"
36# define IS_VALID_PLATFORM false
37#endif
38
39// Continue only for ESP32
40#if IS_VALID_PLATFORM
41
42#include "config.h"
43// If you use #include "I2S.h" the i2s functionality is hidden in a namespace
44// this hack prevents any error messages
45#ifdef _I2S_H_INCLUDED
46using namespace esp_i2s;
47#endif
48
49#include <math.h>
50#include <stdbool.h>
51#include <stdint.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56
57#include <vector>
58
59#include "esp_idf_version.h"
60#include "freertos/FreeRTOS.h" // needed for ESP Arduino < 2.0
61#include "freertos/FreeRTOSConfig.h"
62#include "freertos/queue.h"
63#include "freertos/task.h"
64#include "freertos/timers.h"
65#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
66#include "freertos/xtensa_api.h"
67#else
68#include "xtensa_api.h"
69#endif
70#include "A2DPVolumeControl.h"
71#include "esp_a2dp_api.h"
72#include "esp_avrc_api.h"
73#include "esp_bt.h"
74#include "esp_bt_device.h"
75#include "esp_bt_main.h"
76#include "esp_gap_bt_api.h"
77#include "esp_spp_api.h"
78#include "esp_task_wdt.h"
79#include "esp_timer.h"
80#include "nvs.h"
81#include "nvs_flash.h"
82#include "map"
83
84// Memory management ESP32 Core 3.3.7 and later:
85// https://github.com/espressif/arduino-esp32/issues/12371
86#if __has_include("esp32-hal-bt-mem.h")
87#include "esp32-hal-bt-mem.h"
88#endif
89
90#ifdef ARDUINO_ARCH_ESP32
91#include "esp32-hal-bt.h"
92#include "esp32-hal-log.h"
93#else
94#include "esp_log.h"
95#endif
96
97#if !defined(ESP_IDF_VERSION)
98#error Unsupported ESP32 Version: Upgrade the ESP32 version in the Board Manager
99#endif
100
101// Support for old and new IDF version
102#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0) && \
103 !defined(I2S_COMM_FORMAT_STAND_I2S)
104// support for old idf releases
105#define I2S_COMM_FORMAT_STAND_I2S \
106 (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB)
107#define I2S_COMM_FORMAT_STAND_MSB \
108 (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB)
109#define I2S_COMM_FORMAT_STAND_PCM_LONG \
110 (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG)
111#define I2S_COMM_FORMAT_STAND_PCM_SHORT \
112 (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT)
113#endif
114
115// Prior IDF 5 support
116#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
117#define TaskHandle_t xTaskHandle
118#define QueueHandle_t xQueueHandle
119#define TickType_t portTickType
120#endif
121
122#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
123#define esp_bt_gap_set_device_name esp_bt_dev_set_device_name
124#endif
125
126#define A2DP_DEPRECATED __attribute__((deprecated))
127
128#define BT_APP_SIG_WORK_DISPATCH (0x01)
129
133typedef void (*app_callback_t)(uint16_t event, void *param);
134
137typedef struct {
138 uint16_t sig;
139 uint16_t event;
141 void *param;
143
144#define BT_AV_TAG "BT_AV"
145#define BT_RC_CT_TAG "RCCT"
146#define BT_APP_TAG "BT_API"
147
148// AVRCP used transaction labels
149#define APP_RC_CT_TL_GET_CAPS (0)
150#define APP_RC_CT_TL_GET_META_DATA (1)
151#define APP_RC_CT_TL_RN_TRACK_CHANGE (2)
152#define APP_RC_CT_TL_RN_PLAYBACK_CHANGE (3)
153#define APP_RC_CT_TL_RN_PLAY_POS_CHANGE (4)
154
155// common a2dp callbacks
156extern "C" void ccall_bt_app_task_handler(void *arg);
157extern "C" void ccall_app_gap_callback(esp_bt_gap_cb_event_t event,
158 esp_bt_gap_cb_param_t *param);
159extern "C" void ccall_app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
160 esp_avrc_ct_cb_param_t *param);
161extern "C" void ccall_app_a2d_callback(esp_a2d_cb_event_t event,
162 esp_a2d_cb_param_t *param);
163extern "C" void ccall_av_hdl_stack_evt(uint16_t event, void *p_param);
164
165#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
166extern "C" void ccall_app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
167 esp_avrc_tg_cb_param_t *param);
168extern "C" void ccall_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
169#endif
170
175enum ReconnectStatus { NoReconnect, AutoReconnect, IsReconnecting };
176
184 friend void ccall_bt_app_task_handler(void *arg);
185 friend void ccall_app_gap_callback(esp_bt_gap_cb_event_t event,
186 esp_bt_gap_cb_param_t *param);
187 friend void ccall_app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
188 esp_avrc_ct_cb_param_t *param);
189 friend void ccall_app_a2d_callback(esp_a2d_cb_event_t event,
190 esp_a2d_cb_param_t *param);
191 friend void ccall_av_hdl_stack_evt(uint16_t event, void *p_param);
192
193#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
195 friend void ccall_app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
196 esp_avrc_tg_cb_param_t *param);
197 /* avrc TG event handler */
198 friend void ccall_av_hdl_avrc_tg_evt(uint16_t event, void *p_param);
199#endif
200
201 public:
205 virtual ~BluetoothA2DPCommon() = default;
206
209 void set_auto_reconnect(bool active);
210
212 virtual void disconnect();
213
215 virtual bool reconnect();
216
218 virtual bool connect_to(esp_bd_addr_t peer);
219
221 virtual void set_connected(bool active);
222
224 virtual void end(bool releaseMemory = false);
225
227 virtual bool is_connected() {
228 return connection_state == ESP_A2D_CONNECTION_STATE_CONNECTED;
229 }
230
232 virtual void set_volume(uint8_t volume) {
233 if (is_volume_used && volume_value == volume) {
234 return;
235 }
236 volume_value = std::min((int)volume, 0x7F);
237 ESP_LOGI(BT_AV_TAG, "set_volume: %d", volume_value);
238 volume_control()->set_volume(volume_value);
240 is_volume_used = true;
241#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
242 if (isSource() && is_connected()){
243 esp_avrc_ct_send_set_absolute_volume_cmd(0, volume_value);
244 }
245#endif
246 }
247
249 virtual int get_volume() { return is_volume_used ? volume_value : 0; }
250
253 volume_control_ptr = ptr;
254 }
255
258
261
265 void (*callBack)(esp_a2d_connection_state_t state, void *),
266 void *obj = nullptr);
267
271 void (*callBack)(esp_a2d_audio_state_t state, void *),
272 void *obj = nullptr);
273
275 virtual void set_on_audio_state_changed(
276 void (*callBack)(esp_a2d_audio_state_t state, void *),
277 void *obj = nullptr);
278
281 virtual void debounce(void (*cb)(void), int ms);
282
284 void log_free_heap();
285
287 const char *to_str(esp_a2d_connection_state_t state);
288
290 const char *to_str(esp_a2d_audio_state_t state);
291
293 const char *to_str(esp_bd_addr_t bda);
294
296 const char *to_str(esp_bt_gap_discovery_state_t state);
297
298#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
300 const char *to_str(esp_avrc_playback_stat_t state);
301#endif
302
304 void set_task_priority(UBaseType_t priority) { task_priority = priority; }
305
308 void set_task_core(BaseType_t core) { task_core = core; }
309
311 void set_event_queue_size(int size) { event_queue_size = size; }
312
314 void set_event_stack_size(int size) { event_stack_size = size; }
315
317 virtual esp_bd_addr_t *get_last_peer_address() { return &last_connection; }
318
319#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
322#endif
323
325 virtual void set_connectable(bool connectable) {
326 set_scan_mode_connectable(connectable);
327 }
328
330 virtual const char *get_name() { return bt_name; }
331
333 virtual void clean_last_connection();
334
337 virtual void set_default_bt_mode(esp_bt_mode_t mode) { bt_mode = mode; }
338
339#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 1)
341 void set_bluedroid_config_t(esp_bluedroid_config_t cfg) {
342 bluedroid_config = cfg;
343 }
344#endif
346 void delay_ms(uint32_t millis);
348 unsigned long get_millis();
349
358 virtual void set_avrc_rn_events(std::vector<esp_avrc_rn_event_ids_t> events) {
359 avrc_rn_events = events;
360 }
361
363 void set_reference(void* ref, int type = 0);
365 void* get_reference(int type = 0);
368 references.clear();
369 }
370
371 protected:
372 const char *bt_name = {0};
373 esp_bd_addr_t peer_bd_addr;
374 ReconnectStatus reconnect_status = NoReconnect;
375 unsigned long reconnect_timout = 0;
376 unsigned int default_reconnect_timout = 10000;
377 bool is_autoreconnect_allowed = false;
378 uint32_t debounce_ms = 0;
379 A2DPDefaultVolumeControl default_volume_control;
380 A2DPVolumeControl *volume_control_ptr = nullptr;
381 esp_bd_addr_t last_connection = {0, 0, 0, 0, 0, 0};
382 bool is_start_disabled = false;
383 bool is_target_status_active = true;
384 void (*connection_state_callback)(esp_a2d_connection_state_t state,
385 void *obj) = nullptr;
386 void (*audio_state_callback)(esp_a2d_audio_state_t state,
387 void *obj) = nullptr;
388 void (*audio_state_callback_post)(esp_a2d_audio_state_t state,
389 void *obj) = nullptr;
390 void *connection_state_obj = nullptr;
391 void *audio_state_obj = nullptr;
392 void *audio_state_obj_post = nullptr;
393 const char *m_a2d_conn_state_str[4] = {"Disconnected", "Connecting",
394 "Connected", "Disconnecting"};
395 const char *m_a2d_audio_state_str[4] = {"Suspended", "Started", "Suspended", "Suspended"};
396 const char *m_avrc_playback_state_str[5] = {"stopped", "playing", "paused",
397 "forward seek", "reverse seek"};
398 const char *m_esp_bt_gap_discovery_state_t[2] = {"Stopped", "Started"};
400 esp_a2d_connection_state_t connection_state =
402 UBaseType_t task_priority = configMAX_PRIORITIES - 10;
403 // volume
404 uint8_t volume_value = 0;
405 bool is_volume_used = false;
406 bool is_bluedroid_initialized = false;
407 BaseType_t task_core = 1;
408
409 int event_queue_size = 20;
410 int event_stack_size = 3072;
412 std::vector<esp_avrc_rn_event_ids_t> avrc_rn_events = {
413 ESP_AVRC_RN_VOLUME_CHANGE};
414
415 QueueHandle_t app_task_queue = nullptr;
416 TaskHandle_t app_task_handle = nullptr;
417 std::map<int, void*> references;
418
419#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 1)
420 esp_bluedroid_config_t bluedroid_config{.ssp_en = true};
421#endif
422
423 virtual void init_nvs();
424 virtual esp_err_t esp_a2d_connect(esp_bd_addr_t peer) = 0;
425 virtual const char *last_bda_nvs_name() = 0;
426 virtual bool get_last_connection();
427 virtual void set_last_connection(esp_bd_addr_t bda);
428 virtual bool has_last_connection();
429 virtual bool read_address(const char *name, esp_bd_addr_t &bda);
430 virtual bool write_address(const char *name, esp_bd_addr_t bda);
431
432 // change the scan mode
433 virtual void set_scan_mode_connectable(bool connectable);
434 virtual void set_scan_mode_connectable_default() = 0;
435
438 return volume_control_ptr != nullptr ? volume_control_ptr
439 : &default_volume_control;
440 }
441
442 virtual bool bt_start();
443 virtual esp_err_t bluedroid_init();
444 virtual esp_err_t esp_a2d_disconnect(esp_bd_addr_t remote_bda) = 0;
445 virtual void app_task_start_up();
446 virtual void app_task_shut_down();
447 virtual bool app_send_msg(bt_app_msg_t *msg);
448 virtual void app_task_handler(void *arg);
449 virtual void app_work_dispatched(bt_app_msg_t *msg);
450 virtual bool isSource() = 0;
451 // GAP callback
452 virtual void app_gap_callback(esp_bt_gap_cb_event_t event,
453 esp_bt_gap_cb_param_t *param) = 0;
455 virtual void app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
456 esp_avrc_ct_cb_param_t *param) = 0;
458 virtual void app_a2d_callback(esp_a2d_cb_event_t event,
459 esp_a2d_cb_param_t *param) = 0;
460 // handler for bluetooth stack enabled events
461 virtual void av_hdl_stack_evt(uint16_t event, void *p_param) = 0;
462
463#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
465 virtual void app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
466 esp_avrc_tg_cb_param_t *param) = 0;
467 virtual void av_hdl_avrc_tg_evt(uint16_t event, void *p_param) = 0;
468#endif
469
470};
471
472extern BluetoothA2DPCommon *actual_bluetooth_a2dp_common;
473
474#endif // platform
void(* app_callback_t)(uint16_t event, void *param)
handler for the dispatched work
Definition BluetoothA2DPCommon.h:133
Default implementation for handling of the volume of the audio data.
Definition A2DPVolumeControl.h:151
Abstract class for handling of the volume of the audio data.
Definition A2DPVolumeControl.h:54
virtual void set_volume(uint8_t volume)=0
Sets the volume level (pure virtual function)
void set_enabled(bool enabled)
Enables or disables volume control.
Definition A2DPVolumeControl.h:112
Common Bluetooth A2DP functions.
Definition BluetoothA2DPCommon.h:182
void set_event_stack_size(int size)
Defines the stack size of the event task (in bytes)
Definition BluetoothA2DPCommon.h:314
virtual void set_connected(bool active)
Calls disconnect or reconnect.
Definition BluetoothA2DPCommon.cpp:109
virtual void set_volume(uint8_t volume)
Sets the volume (range 0 - 127)
Definition BluetoothA2DPCommon.h:232
virtual int get_volume()
Determines the actual volume.
Definition BluetoothA2DPCommon.h:249
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:341
virtual void set_on_audio_state_changed_post(void(*callBack)(esp_a2d_audio_state_t state, void *), void *obj=nullptr)
Definition BluetoothA2DPCommon.cpp:353
virtual void set_avrc_rn_events(std::vector< esp_avrc_rn_event_ids_t > events)
Definition BluetoothA2DPCommon.h:358
void delay_ms(uint32_t millis)
calls vTaskDelay to pause for the indicated number of milliseconds
Definition BluetoothA2DPCommon.cpp:609
const char * to_str(esp_a2d_connection_state_t state)
converts esp_a2d_connection_state_t to a string
Definition BluetoothA2DPCommon.cpp:375
void set_reference(void *ref, int type=0)
Store a reference to an object (e.g. to use in the callbacks)
Definition BluetoothA2DPCommon.cpp:626
virtual void set_default_bt_mode(esp_bt_mode_t mode)
Definition BluetoothA2DPCommon.h:337
virtual const char * get_name()
Provides the actual SSID name.
Definition BluetoothA2DPCommon.h:330
virtual ~BluetoothA2DPCommon()=default
Destructor.
virtual esp_a2d_connection_state_t get_connection_state()
Determine the connection state.
Definition BluetoothA2DPCommon.cpp:75
void set_auto_reconnect(bool active)
Definition BluetoothA2DPCommon.cpp:81
virtual bool is_connected()
Checks if A2DP is connected using the connection state received from the speaker.
Definition BluetoothA2DPCommon.h:227
virtual void set_on_audio_state_changed(void(*callBack)(esp_a2d_audio_state_t state, void *), void *obj=nullptr)
Set the callback that is called when the audio state is changed.
Definition BluetoothA2DPCommon.cpp:345
unsigned long get_millis()
Provides the time in milliseconds since the last system boot.
Definition BluetoothA2DPCommon.cpp:618
void set_task_priority(UBaseType_t priority)
defines the task priority (the default value is configMAX_PRIORITIES - 10)
Definition BluetoothA2DPCommon.h:304
void set_task_core(BaseType_t core)
Definition BluetoothA2DPCommon.h:308
virtual void app_a2d_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)=0
callback function for A2DP source
friend void ccall_bt_app_task_handler(void *arg)
task handler
Definition BluetoothA2DPCommon.cpp:22
virtual esp_a2d_audio_state_t get_audio_state()
Determine the actual audio state.
Definition BluetoothA2DPCommon.cpp:71
virtual void end(bool releaseMemory=false)
Closes the connection and stops A2DP.
Definition BluetoothA2DPCommon.cpp:131
virtual void set_volume_control(A2DPVolumeControl *ptr)
you can define a custom VolumeControl implementation
Definition BluetoothA2DPCommon.h:252
virtual bool connect_to(esp_bd_addr_t peer)
Connnects to the indicated address.
Definition BluetoothA2DPCommon.cpp:98
void log_free_heap()
Logs the free heap.
Definition BluetoothA2DPCommon.cpp:370
BluetoothA2DPCommon()
Default constructor.
Definition BluetoothA2DPCommon.cpp:67
void * get_reference(int type=0)
Get the reference to an object (e.g. to use in the callbacks)
Definition BluetoothA2DPCommon.cpp:634
virtual void set_connectable(bool connectable)
Bluetooth connectable.
Definition BluetoothA2DPCommon.h:325
virtual bool bt_start()
Startup logic as implemented by Arduino.
Definition BluetoothA2DPCommon.cpp:403
virtual void set_discoverability(esp_bt_discovery_mode_t d)
Bluetooth discoverability.
Definition BluetoothA2DPCommon.cpp:566
virtual A2DPVolumeControl * volume_control()
provides access to the VolumeControl object
Definition BluetoothA2DPCommon.h:437
virtual void clean_last_connection()
clean last connection (delete)
Definition BluetoothA2DPCommon.cpp:286
void clear_references()
Clear all references.
Definition BluetoothA2DPCommon.h:367
virtual void debounce(void(*cb)(void), int ms)
Definition BluetoothA2DPCommon.cpp:361
virtual void set_on_connection_state_changed(void(*callBack)(esp_a2d_connection_state_t state, void *), void *obj=nullptr)
Set the callback that is called when the connection state is changed.
Definition BluetoothA2DPCommon.cpp:337
virtual void disconnect()
Closes the connection.
Definition BluetoothA2DPCommon.cpp:118
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
virtual bool reconnect()
Reconnects to the last device.
Definition BluetoothA2DPCommon.cpp:86
friend void ccall_app_rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t *param)
handle esp_avrc_tg_cb_event_t
Definition BluetoothA2DPCommon.cpp:53
virtual esp_bd_addr_t * get_last_peer_address()
Provides the address of the last device.
Definition BluetoothA2DPCommon.h:317
void set_event_queue_size(int size)
Defines the queue size of the event task.
Definition BluetoothA2DPCommon.h:311
virtual void set_scan_mode_connectable(bool connectable)
Defines if the bluetooth is connectable.
Definition BluetoothA2DPCommon.cpp:575
ReconnectStatus
Buetooth A2DP Reconnect Status.
Definition BluetoothA2DPCommon.h:175
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_SUSPEND
Definition external_lists.h:6
@ 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:137
uint16_t sig
Definition BluetoothA2DPCommon.h:138
app_callback_t cb
Definition BluetoothA2DPCommon.h:140
uint16_t event
Definition BluetoothA2DPCommon.h:139
void * param
Definition BluetoothA2DPCommon.h:141