mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-23 01:21:28 +00:00
a2dp_source: suppport stream reconfiguration (a2dp_source_reconfigure_stream_sampling_frequency)
This commit is contained in:
parent
6da84376d1
commit
cfd2437ec6
@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
- GATT Client: stop timer on disconnect - fixes use after free / crash
|
||||
- L2CAP: Use valid signaling identifier for L2CAP Connection Parameter Update Request
|
||||
|
||||
### Added
|
||||
- A2DP Source: Support stream reconfiguration (a2dp_source_reconfigure_stream_sampling_frequency)
|
||||
|
||||
## Changes August 2018
|
||||
|
||||
### Added
|
||||
|
@ -213,9 +213,9 @@ typedef struct {
|
||||
static const char title[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
|
||||
avrcp_track_t tracks[] = {
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "AVRCP Demo", "monotone", 12345},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "AVRCP Demo", "vivid", 12345},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "AVRCP Demo", "vivid", 12345},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 1, "Sine", "Generated", "A2DP Source Demo", "monotone", 12345},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, 2, "Nao-deceased", "Decease", "A2DP Source Demo", "vivid", 12345},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, 3, (char *)title, "Decease", "A2DP Source Demo", "vivid", 12345},
|
||||
};
|
||||
int current_track_index;
|
||||
avrcp_play_status_info_t play_info;
|
||||
@ -432,7 +432,7 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui
|
||||
#ifndef HAVE_BTSTACK_STDIN
|
||||
if (hci_event_packet_get_type(packet) == BTSTACK_EVENT_STATE){
|
||||
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
|
||||
printf("Create AVDTP Source connection to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
printf("Create A2DP Source connection to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
|
||||
if (status != ERROR_CODE_SUCCESS){
|
||||
printf("Could not perform command, status 0x%2x\n", status);
|
||||
@ -448,7 +448,10 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui
|
||||
}
|
||||
|
||||
if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
|
||||
switch (packet[2]){
|
||||
|
||||
printf("A2DP Meta %x\n", hci_event_a2dp_meta_get_subevent_code(packet));
|
||||
|
||||
switch (hci_event_a2dp_meta_get_subevent_code(packet)){
|
||||
case A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
|
||||
a2dp_subevent_signaling_connection_established_get_bd_addr(packet, address);
|
||||
cid = a2dp_subevent_signaling_connection_established_get_a2dp_cid(packet);
|
||||
@ -464,7 +467,6 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui
|
||||
break;
|
||||
|
||||
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{
|
||||
printf("A2DP Source: Received SBC codec configuration.\n");
|
||||
sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
|
||||
sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet);
|
||||
sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
|
||||
@ -475,17 +477,13 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui
|
||||
sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet);
|
||||
sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
|
||||
sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length;
|
||||
printf("A2DP Source: Received SBC codec configuration, sampling frequency %u.\n", sbc_configuration.sampling_frequency);
|
||||
|
||||
btstack_sbc_encoder_init(&sbc_encoder_state, SBC_MODE_STANDARD,
|
||||
sbc_configuration.block_length, sbc_configuration.subbands,
|
||||
sbc_configuration.allocation_method, sbc_configuration.sampling_frequency,
|
||||
sbc_configuration.max_bitpool_value,
|
||||
sbc_configuration.channel_mode);
|
||||
|
||||
// status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
|
||||
// if (status != ERROR_CODE_SUCCESS){
|
||||
// printf("Could not perform command, status 0x%2x\n", status);
|
||||
// }
|
||||
break;
|
||||
}
|
||||
|
||||
@ -503,12 +501,16 @@ static void a2dp_source_packet_handler(uint8_t packet_type, uint16_t channel, ui
|
||||
}
|
||||
printf("A2DP Source: Stream established, address %s, a2dp cid 0x%02x, local seid %d, remote seid %d.\n", bd_addr_to_str(address),
|
||||
media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet));
|
||||
printf("A2DP Source: Start playing mod, a2dp cid 0x%02x.\n", media_tracker.a2dp_cid);
|
||||
media_tracker.stream_opened = 1;
|
||||
data_source = STREAM_MOD;
|
||||
status = a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
|
||||
break;
|
||||
|
||||
case A2DP_SUBEVENT_STREAM_RECONFIGURED:
|
||||
status = a2dp_subevent_stream_reconfigured_get_status(packet);
|
||||
printf("A2DP Source: Reconfigured, status 0x%02x\n", status);
|
||||
break;
|
||||
|
||||
case A2DP_SUBEVENT_STREAM_STARTED:
|
||||
play_info.status = AVRCP_PLAYBACK_STATUS_PLAYING;
|
||||
if (media_tracker.avrcp_cid){
|
||||
@ -643,8 +645,8 @@ static void show_usage(void){
|
||||
bd_addr_t iut_address;
|
||||
gap_local_bd_addr(iut_address);
|
||||
printf("\n--- Bluetooth A2DP Source/AVRCP Target Demo %s ---\n", bd_addr_to_str(iut_address));
|
||||
printf("b - AVDTP Source create connection to addr %s\n", device_addr_string);
|
||||
printf("B - AVDTP Source disconnect\n");
|
||||
printf("b - A2DP Source create connection to addr %s\n", device_addr_string);
|
||||
printf("B - A2DP Source disconnect\n");
|
||||
printf("c - AVRCP Target create connection to addr %s\n", device_addr_string);
|
||||
printf("C - AVRCP Target disconnect\n");
|
||||
|
||||
@ -653,6 +655,8 @@ static void show_usage(void){
|
||||
printf("z - start streaming '%s'\n", mod_name);
|
||||
}
|
||||
printf("p - pause streaming\n");
|
||||
printf("w - reconfigure stream for 44100 Hz\n");
|
||||
printf("e - reconfigure stream for 48000 Hz\n");
|
||||
|
||||
printf("\n--- Bluetooth AVRCP Target Commands %s ---\n", bd_addr_to_str(iut_address));
|
||||
printf("---\n");
|
||||
@ -663,10 +667,10 @@ static void stdin_process(char cmd){
|
||||
switch (cmd){
|
||||
case 'b':
|
||||
status = a2dp_source_establish_stream(device_addr, media_tracker.local_seid, &media_tracker.a2dp_cid);
|
||||
printf("%c - Create AVDTP Source connection to addr %s, cid 0x%02x.\n", cmd, bd_addr_to_str(device_addr), media_tracker.a2dp_cid);
|
||||
printf("%c - Create A2DP Source connection to addr %s, cid 0x%02x.\n", cmd, bd_addr_to_str(device_addr), media_tracker.a2dp_cid);
|
||||
break;
|
||||
case 'B':
|
||||
printf("%c - AVDTP Source Disconnect from cid 0x%2x\n", cmd, media_tracker.a2dp_cid);
|
||||
printf("%c - A2DP Source Disconnect from cid 0x%2x\n", cmd, media_tracker.a2dp_cid);
|
||||
status = a2dp_source_disconnect(media_tracker.a2dp_cid);
|
||||
break;
|
||||
case 'c':
|
||||
@ -707,6 +711,26 @@ static void stdin_process(char cmd){
|
||||
status = a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (!media_tracker.stream_opened) break;
|
||||
if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){
|
||||
printf("Stream cannot be reconfigured while playing, please pause stream first\n");
|
||||
break;
|
||||
}
|
||||
printf("%c - Reconfigure for 44100 Hz.\n", cmd);
|
||||
status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 44100);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (!media_tracker.stream_opened) break;
|
||||
if (play_info.status == AVRCP_PLAYBACK_STATUS_PLAYING){
|
||||
printf("Stream cannot be reconfigured while playing, please pause stream first\n");
|
||||
break;
|
||||
}
|
||||
printf("%c - Reconfigure for 48000 Hz.\n", cmd);
|
||||
status = a2dp_source_reconfigure_stream_sampling_frequency(media_tracker.a2dp_cid, 48000);
|
||||
break;
|
||||
|
||||
default:
|
||||
show_usage();
|
||||
return;
|
||||
|
@ -39,7 +39,6 @@
|
||||
#define __BTSTACK_FILE__ "a2dp_source.c"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -200,6 +199,20 @@ static void a2dp_signaling_emit_control_command(btstack_packet_handler_t callbac
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void a2dp_signaling_emit_reconfigured(btstack_packet_handler_t callback, uint16_t cid, uint8_t local_seid, uint8_t status){
|
||||
if (!callback) return;
|
||||
uint8_t event[7];
|
||||
int pos = 0;
|
||||
event[pos++] = HCI_EVENT_A2DP_META;
|
||||
event[pos++] = sizeof(event) - 2;
|
||||
event[pos++] = A2DP_SUBEVENT_STREAM_RECONFIGURED;
|
||||
little_endian_store_16(event, pos, cid);
|
||||
pos += 2;
|
||||
event[pos++] = local_seid;
|
||||
event[pos++] = status;
|
||||
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
@ -365,6 +378,11 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
|
||||
avdtp_source_set_configuration(cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid, sc.local_stream_endpoint->remote_configuration_bitmap, sc.local_stream_endpoint->remote_configuration);
|
||||
break;
|
||||
}
|
||||
case A2DP_W2_RECONFIGURE_WITH_SEID:
|
||||
log_info("A2DP reconfigured");
|
||||
a2dp_signaling_emit_reconfigured(a2dp_source_context.a2dp_callback, cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), 0);
|
||||
app_state = A2DP_STREAMING_OPENED;
|
||||
break;
|
||||
case A2DP_W2_OPEN_STREAM_WITH_SEID:{
|
||||
log_info("A2DP open stream ");
|
||||
app_state = A2DP_W4_OPEN_STREAM_WITH_SEID;
|
||||
@ -474,6 +492,51 @@ uint8_t a2dp_source_disconnect(uint16_t a2dp_cid){
|
||||
return avdtp_disconnect(a2dp_cid, &a2dp_source_context);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_reconfigure_stream_sampling_frequency(uint16_t a2dp_cid, uint32_t sampling_frequency){
|
||||
// UNUSED(sampling_frequency);
|
||||
|
||||
log_info("a2dp_source_reconfigure_stream");
|
||||
|
||||
memcpy(sc.local_stream_endpoint->reconfigure_media_codec_sbc_info, sc.local_stream_endpoint->remote_sep.configuration.media_codec.media_codec_information, 4);
|
||||
|
||||
// update sampling frequency
|
||||
uint8_t config = sc.local_stream_endpoint->reconfigure_media_codec_sbc_info[0] & 0x0f;
|
||||
switch (sampling_frequency){
|
||||
case 48000:
|
||||
config |= (AVDTP_SBC_48000 << 4);
|
||||
break;
|
||||
case 44100:
|
||||
config |= (AVDTP_SBC_44100 << 4);
|
||||
break;
|
||||
case 32000:
|
||||
config |= (AVDTP_SBC_32000 << 4);
|
||||
break;
|
||||
case 16000:
|
||||
config |= (AVDTP_SBC_16000 << 4);
|
||||
break;
|
||||
default:
|
||||
log_error("Unsupported sampling frequency %u", sampling_frequency);
|
||||
return ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
|
||||
}
|
||||
sc.local_stream_endpoint->reconfigure_media_codec_sbc_info[0] = config;
|
||||
|
||||
avdtp_capabilities_t new_configuration;
|
||||
new_configuration.media_codec.media_type = AVDTP_AUDIO;
|
||||
new_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
|
||||
new_configuration.media_codec.media_codec_information_len = 4;
|
||||
new_configuration.media_codec.media_codec_information = sc.local_stream_endpoint->reconfigure_media_codec_sbc_info;
|
||||
|
||||
// sttart reconfigure
|
||||
app_state = A2DP_W2_RECONFIGURE_WITH_SEID;
|
||||
return avdtp_source_reconfigure(
|
||||
a2dp_cid,
|
||||
avdtp_stream_endpoint_seid(sc.local_stream_endpoint),
|
||||
sc.active_remote_sep->seid,
|
||||
1 << AVDTP_MEDIA_CODEC,
|
||||
new_configuration
|
||||
);
|
||||
}
|
||||
|
||||
uint8_t a2dp_source_start_stream(uint16_t a2dp_cid, uint8_t local_seid){
|
||||
return avdtp_start_stream(a2dp_cid, local_seid, &a2dp_source_context);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
#define __A2DP_SOURCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "avdtp.h"
|
||||
#include "classic/avdtp.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
@ -109,6 +109,13 @@ void a2dp_source_register_packet_handler(btstack_packet_handler_t callback);
|
||||
*/
|
||||
uint8_t a2dp_source_establish_stream(bd_addr_t remote, uint8_t local_seid, uint16_t * out_a2dp_cid);
|
||||
|
||||
/**
|
||||
* @brief Reconfigure stream.
|
||||
* @param local_seid ID assigned to a local stream endpoint
|
||||
* @param sampling_frequency New sampling frequency to use. Cannot be called while stream is active
|
||||
*/
|
||||
uint8_t a2dp_source_reconfigure_stream_sampling_frequency(uint16_t a2dp_cid, uint32_t sampling_frequency);
|
||||
|
||||
/**
|
||||
* @brief Start stream.
|
||||
* @param a2dp_cid A2DP channel identifyer.
|
||||
|
Loading…
x
Reference in New Issue
Block a user