diff --git a/CHANGELOG.md b/CHANGELOG.md index ffc4d4e72..966076f72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - btstack_stdin_embedded: use timer to poll RTT input, fix for tickless RTOS - gatt_client: return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER for invalid connection handle - A2DP: emit A2DP_SUBEVENT_STREAM_ESTABLISHED with if connection fails, e.g. because of Page Timeout +- A2DP: use samples as timestamp, fixes issue with Apple Airpods Pro 2nd Gen - PBAP Client: make pbap_set_property_selector work for Pull Phonebook - esp32: fix power amplifier control on Lyra T v4.3 diff --git a/example/a2dp_source_demo.c b/example/a2dp_source_demo.c index a65fdf2a9..fbeb5835c 100644 --- a/example/a2dp_source_demo.c +++ b/example/a2dp_source_demo.c @@ -101,7 +101,8 @@ typedef struct { btstack_timer_source_t audio_timer; uint8_t streaming; int max_media_payload_size; - + uint32_t rtp_timestamp; + uint8_t sbc_storage[SBC_STORAGE_SIZE]; uint16_t sbc_storage_count; uint8_t sbc_ready_to_send; @@ -351,10 +352,16 @@ static void a2dp_demo_hexcmod_configure_sample_rate(int sample_rate){ static void a2dp_demo_send_media_packet(void){ int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); int bytes_in_storage = media_tracker.sbc_storage_count; - uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; + uint8_t num_sbc_frames = bytes_in_storage / num_bytes_in_frame; // Prepend SBC Header - media_tracker.sbc_storage[0] = num_frames; // (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames; - avdtp_source_stream_send_media_payload_rtp(media_tracker.a2dp_cid, media_tracker.local_seid, 0, media_tracker.sbc_storage, bytes_in_storage + 1); + media_tracker.sbc_storage[0] = num_sbc_frames; // (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames; + a2dp_source_stream_send_media_payload_rtp(media_tracker.a2dp_cid, media_tracker.local_seid, 0, + media_tracker.rtp_timestamp, + media_tracker.sbc_storage, bytes_in_storage + 1); + + // update rtp_timestamp + unsigned int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames(); + media_tracker.rtp_timestamp += num_sbc_frames * num_audio_samples_per_sbc_buffer; media_tracker.sbc_storage_count = 0; media_tracker.sbc_ready_to_send = 0; diff --git a/src/classic/a2dp_source.c b/src/classic/a2dp_source.c index 142529b39..28c55381a 100644 --- a/src/classic/a2dp_source.c +++ b/src/classic/a2dp_source.c @@ -207,8 +207,10 @@ int a2dp_max_media_payload_size(uint16_t avdtp_cid, uint8_t local_seid){ return avdtp_max_media_payload_size(avdtp_cid, local_seid); } -uint8_t a2dp_source_stream_send_media_payload_rtp(uint16_t a2dp_cid, uint8_t local_seid, uint8_t marker, uint8_t * payload, uint16_t payload_size){ - return avdtp_source_stream_send_media_payload_rtp(a2dp_cid, local_seid, marker, payload, payload_size); +uint8_t +a2dp_source_stream_send_media_payload_rtp(uint16_t a2dp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp, + uint8_t *payload, uint16_t payload_size) { + return avdtp_source_stream_send_media_payload_rtp(a2dp_cid, local_seid, marker, timestamp, payload, payload_size); } uint8_t a2dp_source_stream_send_media_packet(uint16_t a2dp_cid, uint8_t local_seid, const uint8_t * packet, uint16_t size){ diff --git a/src/classic/a2dp_source.h b/src/classic/a2dp_source.h index 295b8346e..35ecba29a 100644 --- a/src/classic/a2dp_source.h +++ b/src/classic/a2dp_source.h @@ -165,12 +165,15 @@ int a2dp_max_media_payload_size(uint16_t a2dp_cid, uint8_t local_seid); * @param a2dp_cid A2DP channel identifier. * @param local_seid ID of a local stream endpoint. * @param marker + * @param timestamp in sample rate units * @param payload * @param payload_size * @param marker * @return status */ -uint8_t a2dp_source_stream_send_media_payload_rtp(uint16_t a2dp_cid, uint8_t local_seid, uint8_t marker, uint8_t * payload, uint16_t payload_size); +uint8_t +a2dp_source_stream_send_media_payload_rtp(uint16_t a2dp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp, + uint8_t *payload, uint16_t payload_size); /** * @brief Send media packet diff --git a/src/classic/avdtp_source.c b/src/classic/avdtp_source.c index 535403983..791f36b61 100644 --- a/src/classic/avdtp_source.c +++ b/src/classic/avdtp_source.c @@ -188,7 +188,9 @@ avdtp_source_setup_media_header(uint8_t *media_packet, uint8_t marker, uint16_t big_endian_store_32(media_packet, pos, ssrc); // only used for multicast } -uint8_t avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t local_seid, uint8_t marker, const uint8_t * payload, uint16_t payload_size){ +uint8_t +avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp, + const uint8_t *payload, uint16_t payload_size) { UNUSED(avdtp_cid); avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); @@ -207,7 +209,6 @@ uint8_t avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t l if (packet_size > buffer_size) return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED; l2cap_reserve_packet_buffer(); uint8_t * media_packet = l2cap_get_outgoing_buffer(); - uint32_t timestamp = btstack_run_loop_get_time_ms(); avdtp_source_setup_media_header(media_packet, marker, stream_endpoint->sequence_number, timestamp); (void)memcpy(&media_packet[AVDTP_MEDIA_PAYLOAD_HEADER_SIZE], payload, payload_size); stream_endpoint->sequence_number++; diff --git a/src/classic/avdtp_source.h b/src/classic/avdtp_source.h index 30688aa61..d029b7fc5 100644 --- a/src/classic/avdtp_source.h +++ b/src/classic/avdtp_source.h @@ -251,11 +251,14 @@ uint8_t avdtp_source_stream_send_media_packet(uint16_t avdtp_cid, uint8_t local_ * @param avdtp_cid AVDTP channel identifier. * @param local_seid ID of a local stream endpoint. * @param marker + * @param timestamp in sample rate units * @param payload * @param size * @return status */ -uint8_t avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t local_seid, uint8_t marker, const uint8_t * payload, uint16_t size); +uint8_t +avdtp_source_stream_send_media_payload_rtp(uint16_t avdtp_cid, uint8_t local_seid, uint8_t marker, uint32_t timestamp, + const uint8_t *payload, uint16_t size); /** * @brief Request to send a media packet. Packet can be then sent on reception of AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW event.