├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── img
├── sc170503a1.png
├── sc180402a1.PNG
├── sc180402a2.PNG
└── sc180402a3.PNG
├── main
├── Kconfig.projbuild
├── bt_app_av.c
├── bt_app_av.h
├── bt_app_core.c
├── bt_app_core.h
├── component.mk
└── main.c
└── sdkconfig.defaults
/.gitignore:
--------------------------------------------------------------------------------
1 | sdkconfig
2 | sdkconfig.old
3 | build
4 |
5 | # Object files
6 | *.o
7 | *.ko
8 | *.obj
9 | *.elf
10 |
11 | # Precompiled Headers
12 | *.gch
13 | *.pch
14 |
15 | # Libraries
16 | *.lib
17 | *.a
18 | *.la
19 | *.lo
20 |
21 | # Shared objects (inc. Windows DLLs)
22 | *.dll
23 | *.so
24 | *.so.*
25 | *.dylib
26 |
27 | # Executables
28 | *.exe
29 | *.out
30 | *.app
31 | *.i*86
32 | *.x86_64
33 | *.hex
34 |
35 | # Debug files
36 | *.dSYM/
37 | *.su
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Hiroshi Narimatsu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a
3 | # project subdirectory.
4 | #
5 |
6 | PROJECT_NAME := bt-speaker
7 |
8 | include $(IDF_PATH)/make/project.mk
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ESP32_bt_speaker
2 | bluetooth speaker using I2S + built in DAC
3 |
4 | * esp-idfのexamples/bluetooth/a2dp_sinkを元に、ESP32内蔵DACから音声を出力します。
5 | * esp-idf環境用です。
6 |
7 | 2018年2月20日(火)追記
8 |
9 | * esp-idfが、かなり変更されたので更新しました。
10 | * esp-idfのexamples/bluetooth/a2dp_sinkがDAC/I2S DA
11 | 出力をサポートしたけど、まだ動かないので、
12 | これを動くように修正したものに置き換えました。
13 | * 以下の問題が残っています。解決策をご存じの方は、教えていだけますとありがたいです。
14 | * 音量を上げると音が割れる問題
15 | * 音の出力先を変えるなどして 通信がsuspendすると変な音が出続ける問題 (DMAバッファに音データが残る?)
16 |
17 | 2018年4月2日(月)追記
18 |
19 | * main/Kconfig.projbuild の追加忘れで、うまくコンパイル出来ない問題を修正しました。
20 | * 初回make時、或いはmake menuconfigの設定画面で
21 | * A2DP Example Configuration --> を選択
22 | * A2DP Sink Output (Internal DAC) ---> を選択
23 | * Internal DAC を選択してください。
24 | * Serial Flasher configでシリアルポートの設定も行ってください。
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ## 接続
34 |
35 |
36 |
37 | * 半固定抵抗ではなく、100Ωと1KΩで1/10程度に固定比で分圧しても問題ないと思います。
38 | * コンデンサの容量は 10uF程度にした方が音質がよくなるかもしれません。
39 |
40 | ## デモ動画
41 |
42 | * ESP32内蔵DA出力Bluetooth speaker
43 |
--------------------------------------------------------------------------------
/img/sc170503a1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h-nari/ESP32_bt_speaker/1a84c3aac2402e33b347c8af4a5dd4b087bfadfa/img/sc170503a1.png
--------------------------------------------------------------------------------
/img/sc180402a1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h-nari/ESP32_bt_speaker/1a84c3aac2402e33b347c8af4a5dd4b087bfadfa/img/sc180402a1.PNG
--------------------------------------------------------------------------------
/img/sc180402a2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h-nari/ESP32_bt_speaker/1a84c3aac2402e33b347c8af4a5dd4b087bfadfa/img/sc180402a2.PNG
--------------------------------------------------------------------------------
/img/sc180402a3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h-nari/ESP32_bt_speaker/1a84c3aac2402e33b347c8af4a5dd4b087bfadfa/img/sc180402a3.PNG
--------------------------------------------------------------------------------
/main/Kconfig.projbuild:
--------------------------------------------------------------------------------
1 | menu "A2DP Example Configuration"
2 |
3 | choice A2DP_SINK_OUTPUT
4 | prompt "A2DP Sink Output"
5 | default A2DP_SINK_OUTPUT_EXTERNAL_I2S
6 | help
7 | Select to use Internal DAC or external I2S driver
8 |
9 | config A2DP_SINK_OUTPUT_INTERNAL_DAC
10 | bool "Internal DAC"
11 | help
12 | Select this to use Internal DAC sink output
13 |
14 | config A2DP_SINK_OUTPUT_EXTERNAL_I2S
15 | bool "External I2S Codec"
16 | help
17 | Select this to use External I2S sink output
18 |
19 | endchoice
20 |
21 | config I2S_LRCK_PIN
22 | int "I2S LRCK (WS) GPIO"
23 | default 22
24 | depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S
25 | help
26 | GPIO number to use for I2S LRCK(WS) Driver.
27 |
28 | config I2S_BCK_PIN
29 | int "I2S BCK GPIO"
30 | default 26
31 | depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S
32 | help
33 | GPIO number to use for I2S BCK Driver.
34 |
35 | config I2S_DATA_PIN
36 | int "I2S DATA GPIO"
37 | default 25
38 | depends on A2DP_SINK_OUTPUT_EXTERNAL_I2S
39 | help
40 | GPIO number to use for I2S Data Driver.
41 |
42 |
43 | endmenu
44 |
--------------------------------------------------------------------------------
/main/bt_app_av.c:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | This example code is in the Public Domain (or CC0 licensed, at your option.)
4 |
5 | Unless required by applicable law or agreed to in writing, this
6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7 | CONDITIONS OF ANY KIND, either express or implied.
8 | */
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "esp_log.h"
15 |
16 | #include "bt_app_core.h"
17 | #include "bt_app_av.h"
18 | #include "esp_bt_main.h"
19 | #include "esp_bt_device.h"
20 | #include "esp_gap_bt_api.h"
21 | #include "esp_a2dp_api.h"
22 | #include "esp_avrc_api.h"
23 |
24 | #include "freertos/FreeRTOS.h"
25 | #include "freertos/task.h"
26 | #include "driver/i2s.h"
27 |
28 | /* a2dp event handler */
29 | static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param);
30 | /* avrc event handler */
31 | static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param);
32 |
33 | static uint32_t m_pkt_cnt = 0;
34 | static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED;
35 | static const char *m_a2d_conn_state_str[] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
36 | static const char *m_a2d_audio_state_str[] = {"Suspended", "Stopped", "Started"};
37 |
38 | /* callback for A2DP sink */
39 | void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
40 | {
41 | switch (event) {
42 | case ESP_A2D_CONNECTION_STATE_EVT:
43 | case ESP_A2D_AUDIO_STATE_EVT:
44 | case ESP_A2D_AUDIO_CFG_EVT: {
45 | bt_app_work_dispatch(bt_av_hdl_a2d_evt, event, param, sizeof(esp_a2d_cb_param_t), NULL);
46 | break;
47 | }
48 | default:
49 | ESP_LOGE(BT_AV_TAG, "Invalid A2DP event: %d", event);
50 | break;
51 | }
52 | }
53 |
54 | void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
55 | {
56 | TickType_t delay = 50 / portTICK_PERIOD_MS;
57 | if(len % 8){
58 | ESP_LOGE(BT_AV_TAG,"unexpected data len:%u",len);
59 | return;
60 | }
61 |
62 | for(int i=0; imeta_rsp.attr_length + 1);
86 | memcpy(attr_text, rc->meta_rsp.attr_text, rc->meta_rsp.attr_length);
87 | attr_text[rc->meta_rsp.attr_length] = 0;
88 |
89 | rc->meta_rsp.attr_text = attr_text;
90 | }
91 |
92 | void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)
93 | {
94 | switch (event) {
95 | case ESP_AVRC_CT_METADATA_RSP_EVT:
96 | bt_app_alloc_meta_buffer(param);
97 | case ESP_AVRC_CT_CONNECTION_STATE_EVT:
98 | case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT:
99 | case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
100 | case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
101 | bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL);
102 | break;
103 | }
104 | default:
105 | ESP_LOGE(BT_AV_TAG, "Invalid AVRC event: %d", event);
106 | break;
107 | }
108 | }
109 |
110 | static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
111 | {
112 | ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
113 | esp_a2d_cb_param_t *a2d = NULL;
114 | switch (event) {
115 | case ESP_A2D_CONNECTION_STATE_EVT: {
116 | a2d = (esp_a2d_cb_param_t *)(p_param);
117 | uint8_t *bda = a2d->conn_stat.remote_bda;
118 | ESP_LOGI(BT_AV_TAG, "A2DP connection state: %s, [%02x:%02x:%02x:%02x:%02x:%02x]",
119 | m_a2d_conn_state_str[a2d->conn_stat.state], bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
120 | break;
121 | }
122 | case ESP_A2D_AUDIO_STATE_EVT: {
123 | a2d = (esp_a2d_cb_param_t *)(p_param);
124 | ESP_LOGI(BT_AV_TAG, "A2DP audio state: %s", m_a2d_audio_state_str[a2d->audio_stat.state]);
125 | m_audio_state = a2d->audio_stat.state;
126 | if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) {
127 | m_pkt_cnt = 0;
128 | }
129 | break;
130 | }
131 | case ESP_A2D_AUDIO_CFG_EVT: {
132 | a2d = (esp_a2d_cb_param_t *)(p_param);
133 | ESP_LOGI(BT_AV_TAG, "A2DP audio stream configuration, codec type %d", a2d->audio_cfg.mcc.type);
134 | // for now only SBC stream is supported
135 | if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) {
136 | int sample_rate = 16000;
137 | char oct0 = a2d->audio_cfg.mcc.cie.sbc[0];
138 | if (oct0 & (0x01 << 6)) {
139 | sample_rate = 32000;
140 | } else if (oct0 & (0x01 << 5)) {
141 | sample_rate = 44100;
142 | } else if (oct0 & (0x01 << 4)) {
143 | sample_rate = 48000;
144 | }
145 | i2s_set_clk(0, sample_rate, 16, 2);
146 |
147 | ESP_LOGI(BT_AV_TAG, "Configure audio player %x-%x-%x-%x",
148 | a2d->audio_cfg.mcc.cie.sbc[0],
149 | a2d->audio_cfg.mcc.cie.sbc[1],
150 | a2d->audio_cfg.mcc.cie.sbc[2],
151 | a2d->audio_cfg.mcc.cie.sbc[3]);
152 | ESP_LOGI(BT_AV_TAG, "Audio player configured, sample rate=%d", sample_rate);
153 | }
154 | break;
155 | }
156 | default:
157 | ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
158 | break;
159 | }
160 | }
161 |
162 | static void bt_av_new_track()
163 | {
164 | //Register notifications and request metadata
165 | esp_avrc_ct_send_metadata_cmd(0, ESP_AVRC_MD_ATTR_TITLE | ESP_AVRC_MD_ATTR_ARTIST | ESP_AVRC_MD_ATTR_ALBUM | ESP_AVRC_MD_ATTR_GENRE);
166 | esp_avrc_ct_send_register_notification_cmd(1, ESP_AVRC_RN_TRACK_CHANGE, 0);
167 | }
168 |
169 | void bt_av_notify_evt_handler(uint8_t event_id, uint32_t event_parameter)
170 | {
171 | switch (event_id) {
172 | case ESP_AVRC_RN_TRACK_CHANGE:
173 | bt_av_new_track();
174 | break;
175 | }
176 | }
177 |
178 | static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param)
179 | {
180 | ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
181 | esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param);
182 | switch (event) {
183 | case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
184 | uint8_t *bda = rc->conn_stat.remote_bda;
185 | ESP_LOGI(BT_AV_TAG, "AVRC conn_state evt: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
186 | rc->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
187 |
188 | if (rc->conn_stat.connected) {
189 | bt_av_new_track();
190 | }
191 | break;
192 | }
193 | case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: {
194 | ESP_LOGI(BT_AV_TAG, "AVRC passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state);
195 | break;
196 | }
197 | case ESP_AVRC_CT_METADATA_RSP_EVT: {
198 | ESP_LOGI(BT_AV_TAG, "AVRC metadata rsp: attribute id 0x%x, %s", rc->meta_rsp.attr_id, rc->meta_rsp.attr_text);
199 | free(rc->meta_rsp.attr_text);
200 | break;
201 | }
202 | case ESP_AVRC_CT_CHANGE_NOTIFY_EVT: {
203 | ESP_LOGI(BT_AV_TAG, "AVRC event notification: %d, param: %d", rc->change_ntf.event_id, rc->change_ntf.event_parameter);
204 | bt_av_notify_evt_handler(rc->change_ntf.event_id, rc->change_ntf.event_parameter);
205 | break;
206 | }
207 | case ESP_AVRC_CT_REMOTE_FEATURES_EVT: {
208 | ESP_LOGI(BT_AV_TAG, "AVRC remote features %x", rc->rmt_feats.feat_mask);
209 | break;
210 | }
211 | default:
212 | ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
213 | break;
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/main/bt_app_av.h:
--------------------------------------------------------------------------------
1 | /*
2 | This example code is in the Public Domain (or CC0 licensed, at your option.)
3 |
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #ifndef __BT_APP_AV_H__
10 | #define __BT_APP_AV_H__
11 |
12 | #include
13 | #include "esp_a2dp_api.h"
14 | #include "esp_avrc_api.h"
15 |
16 | #define BT_AV_TAG "BT_AV"
17 |
18 | /**
19 | * @brief callback function for A2DP sink
20 | */
21 | void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param);
22 |
23 | /**
24 | * @brief callback function for A2DP sink audio data stream
25 | */
26 | void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len);
27 |
28 | /**
29 | * @brief callback function for AVRCP controller
30 | */
31 | void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param);
32 |
33 | #endif /* __BT_APP_AV_H__*/
34 |
--------------------------------------------------------------------------------
/main/bt_app_core.c:
--------------------------------------------------------------------------------
1 | /*
2 | This example code is in the Public Domain (or CC0 licensed, at your option.)
3 |
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include "freertos/xtensa_api.h"
13 | #include "freertos/FreeRTOSConfig.h"
14 | #include "freertos/FreeRTOS.h"
15 | #include "freertos/queue.h"
16 | #include "freertos/task.h"
17 | #include "esp_log.h"
18 | #include "bt_app_core.h"
19 |
20 | static void bt_app_task_handler(void *arg);
21 | static bool bt_app_send_msg(bt_app_msg_t *msg);
22 | static void bt_app_work_dispatched(bt_app_msg_t *msg);
23 |
24 | static xQueueHandle bt_app_task_queue = NULL;
25 | static xTaskHandle bt_app_task_handle = NULL;
26 |
27 | bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
28 | {
29 | ESP_LOGD(BT_APP_CORE_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);
30 |
31 | bt_app_msg_t msg;
32 | memset(&msg, 0, sizeof(bt_app_msg_t));
33 |
34 | msg.sig = BT_APP_SIG_WORK_DISPATCH;
35 | msg.event = event;
36 | msg.cb = p_cback;
37 |
38 | if (param_len == 0) {
39 | return bt_app_send_msg(&msg);
40 | } else if (p_params && param_len > 0) {
41 | if ((msg.param = malloc(param_len)) != NULL) {
42 | memcpy(msg.param, p_params, param_len);
43 | /* check if caller has provided a copy callback to do the deep copy */
44 | if (p_copy_cback) {
45 | p_copy_cback(&msg, msg.param, p_params);
46 | }
47 | return bt_app_send_msg(&msg);
48 | }
49 | }
50 |
51 | return false;
52 | }
53 |
54 | static bool bt_app_send_msg(bt_app_msg_t *msg)
55 | {
56 | if (msg == NULL) {
57 | return false;
58 | }
59 |
60 | if (xQueueSend(bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
61 | ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__);
62 | return false;
63 | }
64 | return true;
65 | }
66 |
67 | static void bt_app_work_dispatched(bt_app_msg_t *msg)
68 | {
69 | if (msg->cb) {
70 | msg->cb(msg->event, msg->param);
71 | }
72 | }
73 |
74 | static void bt_app_task_handler(void *arg)
75 | {
76 | bt_app_msg_t msg;
77 | for (;;) {
78 | if (pdTRUE == xQueueReceive(bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
79 | ESP_LOGD(BT_APP_CORE_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
80 | switch (msg.sig) {
81 | case BT_APP_SIG_WORK_DISPATCH:
82 | bt_app_work_dispatched(&msg);
83 | break;
84 | default:
85 | ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
86 | break;
87 | } // switch (msg.sig)
88 |
89 | if (msg.param) {
90 | free(msg.param);
91 | }
92 | }
93 | }
94 | }
95 |
96 | void bt_app_task_start_up(void)
97 | {
98 | bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
99 | xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, bt_app_task_handle);
100 | return;
101 | }
102 |
103 | void bt_app_task_shut_down(void)
104 | {
105 | if (bt_app_task_handle) {
106 | vTaskDelete(bt_app_task_handle);
107 | bt_app_task_handle = NULL;
108 | }
109 | if (bt_app_task_queue) {
110 | vQueueDelete(bt_app_task_queue);
111 | bt_app_task_queue = NULL;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/main/bt_app_core.h:
--------------------------------------------------------------------------------
1 | /*
2 | This example code is in the Public Domain (or CC0 licensed, at your option.)
3 |
4 | Unless required by applicable law or agreed to in writing, this
5 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 | CONDITIONS OF ANY KIND, either express or implied.
7 | */
8 |
9 | #ifndef __BT_APP_CORE_H__
10 | #define __BT_APP_CORE_H__
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #define BT_APP_CORE_TAG "BT_APP_CORE"
17 |
18 | #define BT_APP_SIG_WORK_DISPATCH (0x01)
19 |
20 | /**
21 | * @brief handler for the dispatched work
22 | */
23 | typedef void (* bt_app_cb_t) (uint16_t event, void *param);
24 |
25 | /* message to be sent */
26 | typedef struct {
27 | uint16_t sig; /*!< signal to bt_app_task */
28 | uint16_t event; /*!< message event id */
29 | bt_app_cb_t cb; /*!< context switch callback */
30 | void *param; /*!< parameter area needs to be last */
31 | } bt_app_msg_t;
32 |
33 | /**
34 | * @brief parameter deep-copy function to be customized
35 | */
36 | typedef void (* bt_app_copy_cb_t) (bt_app_msg_t *msg, void *p_dest, void *p_src);
37 |
38 | /**
39 | * @brief work dispatcher for the application task
40 | */
41 | bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
42 |
43 | void bt_app_task_start_up(void);
44 |
45 | void bt_app_task_shut_down(void);
46 |
47 | #endif /* __BT_APP_CORE_H__ */
48 |
--------------------------------------------------------------------------------
/main/component.mk:
--------------------------------------------------------------------------------
1 | #
2 | # "main" pseudo-component makefile.
3 | #
4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
5 |
6 |
--------------------------------------------------------------------------------
/main/main.c:
--------------------------------------------------------------------------------
1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 | //
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 | #include
16 | #include
17 | #include
18 | #include
19 | #include "freertos/FreeRTOS.h"
20 | #include "freertos/task.h"
21 | #include "nvs.h"
22 | #include "nvs_flash.h"
23 | #include "esp_system.h"
24 | #include "esp_log.h"
25 |
26 | #include "esp_bt.h"
27 | #include "bt_app_core.h"
28 | #include "bt_app_av.h"
29 | #include "esp_bt_main.h"
30 | #include "esp_bt_device.h"
31 | #include "esp_gap_bt_api.h"
32 | #include "esp_a2dp_api.h"
33 | #include "esp_avrc_api.h"
34 | #include "driver/i2s.h"
35 |
36 | /* event for handler "bt_av_hdl_stack_up */
37 | enum {
38 | BT_APP_EVT_STACK_UP = 0,
39 | };
40 |
41 | /* handler for bluetooth stack enabled events */
42 | static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
43 |
44 |
45 | void app_main()
46 | {
47 | /* Initialize NVS — it is used to store PHY calibration data */
48 | esp_err_t ret = nvs_flash_init();
49 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
50 | ESP_ERROR_CHECK(nvs_flash_erase());
51 | ret = nvs_flash_init();
52 | }
53 | ESP_ERROR_CHECK( ret );
54 |
55 | i2s_config_t i2s_config = {
56 | #ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
57 | .mode = I2S_MODE_DAC_BUILT_IN | I2S_MODE_MASTER | I2S_MODE_TX,
58 | #else
59 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
60 | #endif
61 | .sample_rate = 44100,
62 | .bits_per_sample = 16,
63 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
64 | .communication_format = I2S_COMM_FORMAT_I2S_MSB,
65 | .dma_buf_count = 6,
66 | .dma_buf_len = 60, //
67 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
68 | };
69 |
70 |
71 | i2s_driver_install(0, &i2s_config, 0, NULL);
72 | #ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
73 | i2s_set_pin(0, NULL);
74 | #else
75 | i2s_pin_config_t pin_config = {
76 | .bck_io_num = CONFIG_I2S_BCK_PIN,
77 | .ws_io_num = CONFIG_I2S_LRCK_PIN,
78 | .data_out_num = CONFIG_I2S_DATA_PIN,
79 | .data_in_num = -1 //Not used
80 | };
81 |
82 | i2s_set_pin(0, &pin_config);
83 | #endif
84 |
85 |
86 | ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
87 |
88 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
89 | if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
90 | ESP_LOGE(BT_AV_TAG, "%s initialize controller failed\n", __func__);
91 | return;
92 | }
93 |
94 | if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
95 | ESP_LOGE(BT_AV_TAG, "%s enable controller failed\n", __func__);
96 | return;
97 | }
98 |
99 | if (esp_bluedroid_init() != ESP_OK) {
100 | ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed\n", __func__);
101 | return;
102 | }
103 |
104 | if (esp_bluedroid_enable() != ESP_OK) {
105 | ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed\n", __func__);
106 | return;
107 | }
108 |
109 | /* create application task */
110 | bt_app_task_start_up();
111 |
112 | /* Bluetooth device name, connection mode and profile set up */
113 | bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
114 | }
115 |
116 |
117 | static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
118 | {
119 | ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event);
120 | switch (event) {
121 | case BT_APP_EVT_STACK_UP: {
122 | /* set up device name */
123 | char *dev_name = "ESP_SPEAKER";
124 | esp_bt_dev_set_device_name(dev_name);
125 |
126 | /* initialize A2DP sink */
127 | esp_a2d_register_callback(&bt_app_a2d_cb);
128 | esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
129 | esp_a2d_sink_init();
130 |
131 | /* initialize AVRCP controller */
132 | esp_avrc_ct_init();
133 | esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
134 |
135 | /* set discoverable and connectable mode, wait to be connected */
136 | esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
137 | break;
138 | }
139 | default:
140 | ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event);
141 | break;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/sdkconfig.defaults:
--------------------------------------------------------------------------------
1 | # Override some defaults so BT stack is enabled and
2 | # Classic BT is enabled and BT_DRAM_RELEASE is disabled
3 | CONFIG_BT_ENABLED=y
4 | CONFIG_BLUEDROID_ENABLED=y
5 | CONFIG_CLASSIC_BT_ENABLED=y
6 | CONFIG_A2DP_ENABLE=y
7 | CONFIG_A2DP_SINK_ENABLE=y
8 | CONFIG_A2DP_SRC_ENABLE=
9 | CONFIG_BT_SPP_ENABLED=
10 | CONFIG_GATTS_ENABLE=
11 | CONFIG_GATTC_ENABLE=
12 | CONFIG_BLE_SMP_ENABLE=
13 |
--------------------------------------------------------------------------------