Skip to content

Commit 6d6433f

Browse files
Add track info support for BT audio sink (earlephilhower#2190)
1 parent bf38549 commit 6d6433f

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

libraries/BluetoothAudio/examples/A2DPSink/A2DPSink.ino

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ void setup() {
4343
a2dp.begin();
4444
}
4545

46+
char *nowPlaying = nullptr;
47+
4648
void loop() {
4749
if (BOOTSEL) {
4850
if (status == A2DPSink::PAUSED) {
@@ -54,4 +56,9 @@ void loop() {
5456
}
5557
while (BOOTSEL);
5658
}
59+
if (!nowPlaying || strcmp(nowPlaying, a2dp.trackTitle())) {
60+
free(nowPlaying);
61+
nowPlaying = strdup(a2dp.trackTitle());
62+
Serial.printf("NOW PLAYING: %s\n", nowPlaying);
63+
}
5764
}

libraries/BluetoothAudio/src/A2DPSink.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,14 @@ void A2DPSink::avrcp_controller_packet_handler(uint8_t packet_type, uint16_t cha
559559
break;
560560

561561
case AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED:
562+
_title[0] = 0;
563+
_artist[0] = 0;
564+
_album[0] = 0;
565+
_genre[0] = 0;
566+
avrcp_controller_get_now_playing_info(avrcp_connection->avrcp_cid);
567+
if (_trackChangedCB) {
568+
_trackChangedCB(_trackChangedData);
569+
}
562570
DEBUGV("AVRCP Controller: Track changed\n");
563571
break;
564572

@@ -585,27 +593,35 @@ void A2DPSink::avrcp_controller_packet_handler(uint8_t packet_type, uint16_t cha
585593
case AVRCP_SUBEVENT_NOW_PLAYING_TITLE_INFO:
586594
if (avrcp_subevent_now_playing_title_info_get_value_len(packet) > 0) {
587595
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_title_info_get_value(packet), avrcp_subevent_now_playing_title_info_get_value_len(packet));
596+
strncpy(_title, (char *)avrcp_subevent_value, sizeof(_title));
597+
_title[sizeof(_title) - 1] = 0;
588598
DEBUGV("AVRCP Controller: Title %s\n", avrcp_subevent_value);
589599
}
590600
break;
591601

592602
case AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO:
593603
if (avrcp_subevent_now_playing_artist_info_get_value_len(packet) > 0) {
594604
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_artist_info_get_value(packet), avrcp_subevent_now_playing_artist_info_get_value_len(packet));
605+
strncpy(_artist, (char *)avrcp_subevent_value, sizeof(_artist));
606+
_artist[sizeof(_artist) - 1] = 0;
595607
DEBUGV("AVRCP Controller: Artist %s\n", avrcp_subevent_value);
596608
}
597609
break;
598610

599611
case AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO:
600612
if (avrcp_subevent_now_playing_album_info_get_value_len(packet) > 0) {
601613
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_album_info_get_value(packet), avrcp_subevent_now_playing_album_info_get_value_len(packet));
614+
strncpy(_album, (char *)avrcp_subevent_value, sizeof(_album));
615+
_album[sizeof(_album) - 1] = 0;
602616
DEBUGV("AVRCP Controller: Album %s\n", avrcp_subevent_value);
603617
}
604618
break;
605619

606620
case AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO:
607621
if (avrcp_subevent_now_playing_genre_info_get_value_len(packet) > 0) {
608622
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_genre_info_get_value(packet), avrcp_subevent_now_playing_genre_info_get_value_len(packet));
623+
strncpy(_genre, (char *)avrcp_subevent_value, sizeof(_genre));
624+
_genre[sizeof(_genre) - 1] = 0;
609625
DEBUGV("AVRCP Controller: Genre %s\n", avrcp_subevent_value);
610626
}
611627
break;

libraries/BluetoothAudio/src/A2DPSink.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
class A2DPSink : public Stream {
3434
public:
3535
A2DPSink() {
36+
_title[0] = 0;
37+
_artist[0] = 0;
38+
_album[0] = 0;
39+
_genre[0] = 0;
3640
}
3741
virtual int available() override {
3842
return 0; // Unreadable, this is output only
@@ -96,6 +100,11 @@ class A2DPSink : public Stream {
96100
_connectData = cbData;
97101
}
98102

103+
void onTrackChanged(void (*cb)(void *), void *cbData = nullptr) {
104+
_trackChangedCB = cb;
105+
_trackChangedData = cbData;
106+
}
107+
99108
typedef enum { STOPPED, PLAYING, PAUSED } PlaybackStatus;
100109
void onPlaybackStatus(void (*cb)(void *, PlaybackStatus), void *cbData = nullptr) {
101110
_playbackStatusCB = cb;
@@ -190,6 +199,22 @@ class A2DPSink : public Stream {
190199
}
191200
}
192201

202+
const char *trackTitle() {
203+
return _title;
204+
}
205+
206+
const char *trackArtist() {
207+
return _artist;
208+
}
209+
210+
const char *trackAlbum() {
211+
return _album;
212+
}
213+
214+
const char *trackGenre() {
215+
return _genre;
216+
}
217+
193218
private:
194219
void handle_pcm_data(int16_t * data, int num_audio_frames, int num_channels, int sample_rate, void * context);
195220

@@ -224,6 +249,9 @@ class A2DPSink : public Stream {
224249
void *_connectData;
225250
void (*_playbackStatusCB)(void *, PlaybackStatus) = nullptr;
226251
void *_playbackStatusData;
252+
void (*_trackChangedCB)(void *) = nullptr;
253+
void *_trackChangedData;
254+
227255
char *_name = nullptr;
228256
uint8_t _sourceAddress[6];
229257

@@ -301,4 +329,9 @@ class A2DPSink : public Stream {
301329
a2dp_sink_avrcp_connection_t a2dp_sink_avrcp_connection;
302330

303331
int16_t output_buffer[(128 + 16) * NUM_CHANNELS]; // 16 * 8 * 2
332+
333+
char _title[64];
334+
char _artist[64];
335+
char _album[64];
336+
char _genre[32];
304337
};

0 commit comments

Comments
 (0)