Skip to content

Add track info support for BT audio sink #2190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions libraries/BluetoothAudio/examples/A2DPSink/A2DPSink.ino
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void setup() {
a2dp.begin();
}

char *nowPlaying = nullptr;

void loop() {
if (BOOTSEL) {
if (status == A2DPSink::PAUSED) {
Expand All @@ -54,4 +56,9 @@ void loop() {
}
while (BOOTSEL);
}
if (!nowPlaying || strcmp(nowPlaying, a2dp.trackTitle())) {
free(nowPlaying);
nowPlaying = strdup(a2dp.trackTitle());
Serial.printf("NOW PLAYING: %s\n", nowPlaying);
}
}
16 changes: 16 additions & 0 deletions libraries/BluetoothAudio/src/A2DPSink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,14 @@ void A2DPSink::avrcp_controller_packet_handler(uint8_t packet_type, uint16_t cha
break;

case AVRCP_SUBEVENT_NOTIFICATION_TRACK_CHANGED:
_title[0] = 0;
_artist[0] = 0;
_album[0] = 0;
_genre[0] = 0;
avrcp_controller_get_now_playing_info(avrcp_connection->avrcp_cid);
if (_trackChangedCB) {
_trackChangedCB(_trackChangedData);
}
DEBUGV("AVRCP Controller: Track changed\n");
break;

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

case AVRCP_SUBEVENT_NOW_PLAYING_ARTIST_INFO:
if (avrcp_subevent_now_playing_artist_info_get_value_len(packet) > 0) {
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_artist_info_get_value(packet), avrcp_subevent_now_playing_artist_info_get_value_len(packet));
strncpy(_artist, (char *)avrcp_subevent_value, sizeof(_artist));
_artist[sizeof(_artist) - 1] = 0;
DEBUGV("AVRCP Controller: Artist %s\n", avrcp_subevent_value);
}
break;

case AVRCP_SUBEVENT_NOW_PLAYING_ALBUM_INFO:
if (avrcp_subevent_now_playing_album_info_get_value_len(packet) > 0) {
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_album_info_get_value(packet), avrcp_subevent_now_playing_album_info_get_value_len(packet));
strncpy(_album, (char *)avrcp_subevent_value, sizeof(_album));
_album[sizeof(_album) - 1] = 0;
DEBUGV("AVRCP Controller: Album %s\n", avrcp_subevent_value);
}
break;

case AVRCP_SUBEVENT_NOW_PLAYING_GENRE_INFO:
if (avrcp_subevent_now_playing_genre_info_get_value_len(packet) > 0) {
memcpy(avrcp_subevent_value, avrcp_subevent_now_playing_genre_info_get_value(packet), avrcp_subevent_now_playing_genre_info_get_value_len(packet));
strncpy(_genre, (char *)avrcp_subevent_value, sizeof(_genre));
_genre[sizeof(_genre) - 1] = 0;
DEBUGV("AVRCP Controller: Genre %s\n", avrcp_subevent_value);
}
break;
Expand Down
33 changes: 33 additions & 0 deletions libraries/BluetoothAudio/src/A2DPSink.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
class A2DPSink : public Stream {
public:
A2DPSink() {
_title[0] = 0;
_artist[0] = 0;
_album[0] = 0;
_genre[0] = 0;
}
virtual int available() override {
return 0; // Unreadable, this is output only
Expand Down Expand Up @@ -96,6 +100,11 @@ class A2DPSink : public Stream {
_connectData = cbData;
}

void onTrackChanged(void (*cb)(void *), void *cbData = nullptr) {
_trackChangedCB = cb;
_trackChangedData = cbData;
}

typedef enum { STOPPED, PLAYING, PAUSED } PlaybackStatus;
void onPlaybackStatus(void (*cb)(void *, PlaybackStatus), void *cbData = nullptr) {
_playbackStatusCB = cb;
Expand Down Expand Up @@ -190,6 +199,22 @@ class A2DPSink : public Stream {
}
}

const char *trackTitle() {
return _title;
}

const char *trackArtist() {
return _artist;
}

const char *trackAlbum() {
return _album;
}

const char *trackGenre() {
return _genre;
}

private:
void handle_pcm_data(int16_t * data, int num_audio_frames, int num_channels, int sample_rate, void * context);

Expand Down Expand Up @@ -224,6 +249,9 @@ class A2DPSink : public Stream {
void *_connectData;
void (*_playbackStatusCB)(void *, PlaybackStatus) = nullptr;
void *_playbackStatusData;
void (*_trackChangedCB)(void *) = nullptr;
void *_trackChangedData;

char *_name = nullptr;
uint8_t _sourceAddress[6];

Expand Down Expand Up @@ -301,4 +329,9 @@ class A2DPSink : public Stream {
a2dp_sink_avrcp_connection_t a2dp_sink_avrcp_connection;

int16_t output_buffer[(128 + 16) * NUM_CHANNELS]; // 16 * 8 * 2

char _title[64];
char _artist[64];
char _album[64];
char _genre[32];
};