mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-09 21:45:54 +00:00
example/a2dp_sink: collect per connection data in single struct
This commit is contained in:
parent
8cc81b50eb
commit
aac8d89404
@ -65,7 +65,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "btstack.h"
|
||||
@ -73,10 +72,6 @@
|
||||
|
||||
//#define AVRCP_BROWSING_ENABLED
|
||||
|
||||
// if volume control not supported by btstack_audio_sink, you can try to disable volume change notification
|
||||
// to force the A2DP Source to reduce volume by attenuating the audio stream
|
||||
#define SUPPORT_VOLUME_CHANGE_NOTIFICATION
|
||||
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
#include "btstack_stdin.h"
|
||||
#endif
|
||||
@ -92,6 +87,31 @@
|
||||
#define BYTES_PER_FRAME (2*NUM_CHANNELS)
|
||||
#define MAX_SBC_FRAME_SIZE 120
|
||||
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
static const char * device_addr_string = "5C:F3:70:60:7B:87"; // pts
|
||||
static bd_addr_t device_addr;
|
||||
#endif
|
||||
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
static uint8_t sdp_avdtp_sink_service_buffer[150];
|
||||
static uint8_t sdp_avrcp_target_service_buffer[150];
|
||||
static uint8_t sdp_avrcp_controller_service_buffer[200];
|
||||
static uint8_t device_id_sdp_service_buffer[100];
|
||||
|
||||
// we support all configurations with bitpool 2-53
|
||||
static uint8_t media_sbc_codec_capabilities[] = {
|
||||
0xFF,//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
|
||||
0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
|
||||
2, 53
|
||||
};
|
||||
|
||||
// WAV File
|
||||
#ifdef STORE_TO_WAV_FILE
|
||||
static uint32_t audio_frame_count = 0;
|
||||
static char * wav_filename = "a2dp_sink_demo.wav";
|
||||
#endif
|
||||
|
||||
// SBC Decoder for WAV file or live playback
|
||||
static btstack_sbc_decoder_state_t state;
|
||||
static btstack_sbc_mode_t mode = SBC_MODE_STANDARD;
|
||||
@ -105,77 +125,46 @@ static uint8_t sbc_frame_storage[(OPTIMAL_FRAMES_MAX + ADDITIONAL_FRAMES) * MAX_
|
||||
static btstack_ring_buffer_t sbc_frame_ring_buffer;
|
||||
static unsigned int sbc_frame_size;
|
||||
|
||||
// rest buffer for not fully used sbc frames, with additional frames for resampling
|
||||
// overflow buffer for not fully used sbc frames, with additional frames for resampling
|
||||
static uint8_t decoded_audio_storage[(128+16) * BYTES_PER_FRAME];
|
||||
static btstack_ring_buffer_t decoded_audio_ring_buffer;
|
||||
|
||||
static int audio_stream_started;
|
||||
|
||||
// temp storage of lower-layer request
|
||||
static int media_initialized = 0;
|
||||
static int audio_stream_started;
|
||||
static btstack_resample_t resample_instance;
|
||||
|
||||
// temp storage of lower-layer request for audio samples
|
||||
static int16_t * request_buffer;
|
||||
static int request_frames;
|
||||
|
||||
#define STORE_FROM_PLAYBACK
|
||||
|
||||
// WAV File
|
||||
#ifdef STORE_TO_WAV_FILE
|
||||
static uint32_t audio_frame_count = 0;
|
||||
static char * wav_filename = "a2dp_sink_demo.wav";
|
||||
#endif
|
||||
// sink state
|
||||
static int volume_percentage = 0;
|
||||
static avrcp_battery_status_t battery_status = AVRCP_BATTERY_STATUS_WARNING;
|
||||
|
||||
typedef struct {
|
||||
int reconfigure;
|
||||
|
||||
int num_channels;
|
||||
int sampling_frequency;
|
||||
int block_length;
|
||||
int subbands;
|
||||
int min_bitpool_value;
|
||||
int max_bitpool_value;
|
||||
uint8_t reconfigure;
|
||||
uint8_t num_channels;
|
||||
uint16_t sampling_frequency;
|
||||
uint8_t block_length;
|
||||
uint8_t subbands;
|
||||
uint8_t min_bitpool_value;
|
||||
uint8_t max_bitpool_value;
|
||||
btstack_sbc_channel_mode_t channel_mode;
|
||||
btstack_sbc_allocation_method_t allocation_method;
|
||||
} media_codec_configuration_sbc_t;
|
||||
|
||||
static media_codec_configuration_sbc_t sbc_configuration;
|
||||
static int volume_percentage = 0;
|
||||
static avrcp_battery_status_t battery_status = AVRCP_BATTERY_STATUS_WARNING;
|
||||
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
// pts:
|
||||
static const char * device_addr_string = "5C:F3:70:60:7B:87";
|
||||
// mac 2013: static const char * device_addr_string = "84:38:35:65:d1:15";
|
||||
// iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39";
|
||||
static bd_addr_t device_addr;
|
||||
#endif
|
||||
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
static uint8_t sdp_avdtp_sink_service_buffer[150];
|
||||
static uint8_t sdp_avrcp_target_service_buffer[150];
|
||||
static uint8_t sdp_avrcp_controller_service_buffer[200];
|
||||
static uint8_t device_id_sdp_service_buffer[100];
|
||||
|
||||
static uint16_t a2dp_cid = 0;
|
||||
static uint8_t a2dp_local_seid = 0;
|
||||
|
||||
static uint16_t avrcp_cid = 0;
|
||||
static uint8_t avrcp_connected = 0;
|
||||
static uint8_t avrcp_subevent_value[255];
|
||||
|
||||
static uint8_t media_sbc_codec_capabilities[] = {
|
||||
0xFF,//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
|
||||
0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
|
||||
2, 53
|
||||
};
|
||||
|
||||
static uint8_t media_sbc_codec_configuration[4];
|
||||
|
||||
static int media_initialized = 0;
|
||||
static btstack_resample_t resample_instance;
|
||||
typedef struct {
|
||||
media_codec_configuration_sbc_t sbc_configuration;
|
||||
uint8_t media_sbc_codec_configuration[4];
|
||||
uint16_t a2dp_cid;
|
||||
uint8_t a2dp_local_seid;
|
||||
uint16_t avrcp_cid;
|
||||
} source_connection_t;
|
||||
static source_connection_t source_connection;
|
||||
|
||||
/* @section Main Application Setup
|
||||
*
|
||||
* @text The Listing MainConfiguration shows how to setup AD2P Sink and AVRCP services.
|
||||
* @text The Listing MainConfiguration shows how to set up AD2P Sink and AVRCP services.
|
||||
* Besides calling init() method for each service, you'll also need to register several packet handlers:
|
||||
* - hci_packet_handler - handles legacy pairing, here by using fixed '0000' pin code.
|
||||
* - a2dp_sink_packet_handler - handles events on stream connection status (established, released), the media codec configuration, and, the status of the stream itself (opened, paused, stopped).
|
||||
@ -192,12 +181,12 @@ static btstack_resample_t resample_instance;
|
||||
* If you want to store the audio data in a file, you'll need to define STORE_TO_WAV_FILE.
|
||||
* If STORE_TO_WAV_FILE directive is defined, the SBC decoder needs to get initialized when a2dp_sink_packet_handler receives event A2DP_SUBEVENT_STREAM_STARTED.
|
||||
* The initialization of the SBC decoder requires a callback that handles PCM data:
|
||||
* - handle_pcm_data - handles PCM audio frames. Here, they are stored a in wav file if STORE_TO_WAV_FILE is defined, and/or played using the audio library.
|
||||
* - handle_pcm_data - handles PCM audio frames. Here, they are stored in a wav file if STORE_TO_WAV_FILE is defined, and/or played using the audio library.
|
||||
*/
|
||||
|
||||
/* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP services */
|
||||
static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * event, uint16_t event_size);
|
||||
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t event_size);
|
||||
static void handle_l2cap_media_data_packet(uint8_t seid, uint8_t *packet, uint16_t size);
|
||||
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
@ -221,16 +210,17 @@ static int a2dp_and_avrcp_setup(void){
|
||||
a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet);
|
||||
|
||||
// Create stream endpoint
|
||||
source_connection_t * connection = &source_connection;
|
||||
avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,
|
||||
AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),
|
||||
media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));
|
||||
AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),
|
||||
connection->media_sbc_codec_configuration, sizeof(connection->media_sbc_codec_configuration));
|
||||
if (!local_stream_endpoint){
|
||||
printf("A2DP Sink: not enough memory to create local stream endpoint\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Store stream enpoint's SEP ID, as it is used by A2DP API to indentify the stream endpoint
|
||||
a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
|
||||
// Store stream enpoint's SEP ID, as it is used by A2DP API to identify the stream endpoint
|
||||
connection->a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
|
||||
|
||||
// Initialize AVRCP service
|
||||
avrcp_init();
|
||||
@ -273,7 +263,7 @@ static int a2dp_and_avrcp_setup(void){
|
||||
sdp_register_service(device_id_sdp_service_buffer);
|
||||
|
||||
// Set local name with a template Bluetooth address, that will be automatically
|
||||
// replaced with a actual address once it is available, i.e. when BTstack boots
|
||||
// replaced with an actual address once it is available, i.e. when BTstack boots
|
||||
// up and starts talking to a Bluetooth module.
|
||||
gap_set_local_name("A2DP Sink Demo 00:00:00:00:00:00");
|
||||
|
||||
@ -482,16 +472,16 @@ static void handle_l2cap_media_data_packet(uint8_t seid, uint8_t *packet, uint16
|
||||
int sbc_frames_in_buffer = btstack_ring_buffer_bytes_available(&sbc_frame_ring_buffer) / sbc_frame_size;
|
||||
uint32_t resampling_factor;
|
||||
|
||||
// nomimal factor (fixed-point 2^16) and compensation offset
|
||||
uint32_t nomimal_factor = 0x10000;
|
||||
// nominal factor (fixed-point 2^16) and compensation offset
|
||||
uint32_t nominal_factor = 0x10000;
|
||||
uint32_t compensation = 0x00100;
|
||||
|
||||
if (sbc_frames_in_buffer < OPTIMAL_FRAMES_MIN){
|
||||
resampling_factor = nomimal_factor - compensation; // stretch samples
|
||||
resampling_factor = nominal_factor - compensation; // stretch samples
|
||||
} else if (sbc_frames_in_buffer <= OPTIMAL_FRAMES_MAX){
|
||||
resampling_factor = nomimal_factor; // nothing to do
|
||||
resampling_factor = nominal_factor; // nothing to do
|
||||
} else {
|
||||
resampling_factor = nomimal_factor + compensation; // compress samples
|
||||
resampling_factor = nominal_factor + compensation; // compress samples
|
||||
}
|
||||
|
||||
btstack_resample_set_factor(&resample_instance, resampling_factor);
|
||||
@ -551,14 +541,14 @@ static int read_media_data_header(uint8_t *packet, int size, int *offset, avdtp_
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dump_sbc_configuration(media_codec_configuration_sbc_t configuration){
|
||||
printf(" - num_channels: %d\n", configuration.num_channels);
|
||||
printf(" - sampling_frequency: %d\n", configuration.sampling_frequency);
|
||||
printf(" - channel_mode: %d\n", configuration.channel_mode);
|
||||
printf(" - block_length: %d\n", configuration.block_length);
|
||||
printf(" - subbands: %d\n", configuration.subbands);
|
||||
printf(" - allocation_method: %d\n", configuration.allocation_method);
|
||||
printf(" - bitpool_value [%d, %d] \n", configuration.min_bitpool_value, configuration.max_bitpool_value);
|
||||
static void dump_sbc_configuration(media_codec_configuration_sbc_t * configuration){
|
||||
printf(" - num_channels: %d\n", configuration->num_channels);
|
||||
printf(" - sampling_frequency: %d\n", configuration->sampling_frequency);
|
||||
printf(" - channel_mode: %d\n", configuration->channel_mode);
|
||||
printf(" - block_length: %d\n", configuration->block_length);
|
||||
printf(" - subbands: %d\n", configuration->subbands);
|
||||
printf(" - allocation_method: %d\n", configuration->allocation_method);
|
||||
printf(" - bitpool_value [%d, %d] \n", configuration->min_bitpool_value, configuration->max_bitpool_value);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@ -568,7 +558,9 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
uint16_t local_cid;
|
||||
uint8_t status;
|
||||
bd_addr_t address;
|
||||
|
||||
|
||||
source_connection_t * connection = &source_connection;
|
||||
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
|
||||
switch (packet[2]){
|
||||
@ -577,30 +569,28 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
status = avrcp_subevent_connection_established_get_status(packet);
|
||||
if (status != ERROR_CODE_SUCCESS){
|
||||
printf("AVRCP: Connection failed: status 0x%02x\n", status);
|
||||
avrcp_cid = 0;
|
||||
connection->avrcp_cid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
avrcp_cid = local_cid;
|
||||
avrcp_connected = 1;
|
||||
avrcp_subevent_connection_established_get_bd_addr(packet, address);
|
||||
printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(address), avrcp_cid);
|
||||
|
||||
avrcp_target_support_event(avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
|
||||
avrcp_target_support_event(avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED);
|
||||
avrcp_target_battery_status_changed(avrcp_cid, battery_status);
|
||||
connection->avrcp_cid = local_cid;
|
||||
avrcp_subevent_connection_established_get_bd_addr(packet, address);
|
||||
printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(address), connection->avrcp_cid);
|
||||
|
||||
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
|
||||
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED);
|
||||
avrcp_target_battery_status_changed(connection->avrcp_cid, battery_status);
|
||||
|
||||
// automatically enable notifications
|
||||
avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
|
||||
avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
|
||||
avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
avrcp_controller_enable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
|
||||
avrcp_controller_enable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
|
||||
avrcp_controller_enable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
return;
|
||||
}
|
||||
|
||||
case AVRCP_SUBEVENT_CONNECTION_RELEASED:
|
||||
printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
|
||||
avrcp_cid = 0;
|
||||
avrcp_connected = 0;
|
||||
connection->avrcp_cid = 0;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@ -610,10 +600,15 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
||||
static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
|
||||
|
||||
// helper to print c strings
|
||||
uint8_t avrcp_subevent_value[256];
|
||||
|
||||
source_connection_t * connection = &source_connection;
|
||||
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
|
||||
if (!avrcp_cid) return;
|
||||
if (connection->avrcp_cid == 0) return;
|
||||
|
||||
memset(avrcp_subevent_value, 0, sizeof(avrcp_subevent_value));
|
||||
switch (packet[2]){
|
||||
@ -736,7 +731,7 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
||||
printf("AVRCP Target : VOLUME UP (%s)\n", button_state);
|
||||
break;
|
||||
case AVRCP_OPERATION_ID_VOLUME_DOWN:
|
||||
printf("AVRCP Target : VOLUME UP (%s)\n", button_state);
|
||||
printf("AVRCP Target : VOLUME DOWN (%s)\n", button_state);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -771,49 +766,51 @@ static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint
|
||||
if (packet_type != HCI_EVENT_PACKET) return;
|
||||
if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
|
||||
|
||||
source_connection_t * connection = &source_connection;
|
||||
|
||||
switch (packet[2]){
|
||||
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:
|
||||
printf("A2DP Sink : Received non SBC codec - not implemented\n");
|
||||
break;
|
||||
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{
|
||||
printf("A2DP Sink : 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);
|
||||
sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
|
||||
sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
|
||||
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);
|
||||
connection->sbc_configuration.reconfigure = a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
|
||||
connection->sbc_configuration.num_channels = a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet);
|
||||
connection->sbc_configuration.sampling_frequency = a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
|
||||
connection->sbc_configuration.block_length = a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
|
||||
connection->sbc_configuration.subbands = a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
|
||||
connection->sbc_configuration.min_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet);
|
||||
connection->sbc_configuration.max_bitpool_value = a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
|
||||
|
||||
allocation_method = a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet);
|
||||
|
||||
// Adapt Bluetooth spec definition to SBC Encoder expected input
|
||||
sbc_configuration.allocation_method = (btstack_sbc_allocation_method_t)(allocation_method - 1);
|
||||
connection->sbc_configuration.allocation_method = (btstack_sbc_allocation_method_t)(allocation_method - 1);
|
||||
|
||||
switch (a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet)){
|
||||
case AVDTP_CHANNEL_MODE_JOINT_STEREO:
|
||||
sbc_configuration.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
|
||||
connection->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
|
||||
break;
|
||||
case AVDTP_CHANNEL_MODE_STEREO:
|
||||
sbc_configuration.channel_mode = SBC_CHANNEL_MODE_STEREO;
|
||||
connection->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_STEREO;
|
||||
break;
|
||||
case AVDTP_CHANNEL_MODE_DUAL_CHANNEL:
|
||||
sbc_configuration.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
|
||||
connection->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
|
||||
break;
|
||||
case AVDTP_CHANNEL_MODE_MONO:
|
||||
sbc_configuration.channel_mode = SBC_CHANNEL_MODE_MONO;
|
||||
connection->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_MONO;
|
||||
break;
|
||||
default:
|
||||
btstack_assert(false);
|
||||
break;
|
||||
}
|
||||
dump_sbc_configuration(sbc_configuration);
|
||||
dump_sbc_configuration(&connection->sbc_configuration);
|
||||
|
||||
if (sbc_configuration.reconfigure){
|
||||
if (connection->sbc_configuration.reconfigure){
|
||||
media_processing_close();
|
||||
}
|
||||
// prepare media processing
|
||||
media_processing_init(sbc_configuration);
|
||||
media_processing_init(connection->sbc_configuration);
|
||||
break;
|
||||
}
|
||||
case A2DP_SUBEVENT_STREAM_ESTABLISHED:
|
||||
@ -823,9 +820,10 @@ static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint
|
||||
printf("A2DP Sink : Streaming connection failed, status 0x%02x\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
|
||||
printf("A2DP Sink : Streaming connection is established, address %s, cid 0x%02X, local seid %d\n", bd_addr_to_str(address), a2dp_cid, a2dp_local_seid);
|
||||
|
||||
connection->a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
|
||||
printf("A2DP Sink : Streaming connection is established, address %s, cid 0x%02X, local seid %d\n",
|
||||
bd_addr_to_str(address), connection->a2dp_cid, connection->a2dp_local_seid);
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
// use address for outgoing connections
|
||||
memcpy(device_addr, address, 6);
|
||||
@ -915,22 +913,25 @@ static void stdin_process(char cmd){
|
||||
uint8_t volume;
|
||||
avrcp_battery_status_t old_battery_status;
|
||||
|
||||
source_connection_t * connection = &source_connection;
|
||||
|
||||
switch (cmd){
|
||||
case 'b':
|
||||
status = a2dp_sink_establish_stream(device_addr, a2dp_local_seid, &a2dp_cid);
|
||||
printf(" - Create AVDTP connection to addr %s, and local seid %d, expected cid 0x%02x.\n", bd_addr_to_str(device_addr), a2dp_local_seid, a2dp_cid);
|
||||
status = a2dp_sink_establish_stream(device_addr, connection->a2dp_local_seid, &connection->a2dp_cid);
|
||||
printf(" - Create AVDTP connection to addr %s, and local seid %d, expected cid 0x%02x.\n",
|
||||
bd_addr_to_str(device_addr), connection->a2dp_local_seid, connection->a2dp_cid);
|
||||
break;
|
||||
case 'B':
|
||||
printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||
a2dp_sink_disconnect(a2dp_cid);
|
||||
a2dp_sink_disconnect(connection->a2dp_cid);
|
||||
break;
|
||||
case 'c':
|
||||
printf(" - Create AVRCP connection to addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_connect(device_addr, &avrcp_cid);
|
||||
status = avrcp_connect(device_addr, &connection->avrcp_cid);
|
||||
break;
|
||||
case 'C':
|
||||
printf(" - AVRCP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||
status = avrcp_disconnect(avrcp_cid);
|
||||
status = avrcp_disconnect(connection->avrcp_cid);
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
@ -938,21 +939,21 @@ static void stdin_process(char cmd){
|
||||
break;
|
||||
case 'w':
|
||||
printf("Send delay report\n");
|
||||
avdtp_sink_delay_report(a2dp_cid, a2dp_local_seid, 100);
|
||||
avdtp_sink_delay_report(connection->a2dp_cid, connection->a2dp_local_seid, 100);
|
||||
break;
|
||||
// Volume Control
|
||||
case 't':
|
||||
volume_percentage = volume_percentage <= 90 ? volume_percentage + 10 : 100;
|
||||
volume = volume_percentage * 127 / 100;
|
||||
printf(" - volume up for 10 percent, %d%% (%d) \n", volume_percentage, volume);
|
||||
status = avrcp_target_volume_changed(avrcp_cid, volume);
|
||||
status = avrcp_target_volume_changed(connection->avrcp_cid, volume);
|
||||
avrcp_volume_changed(volume);
|
||||
break;
|
||||
case 'T':
|
||||
volume_percentage = volume_percentage >= 10 ? volume_percentage - 10 : 0;
|
||||
volume = volume_percentage * 127 / 100;
|
||||
printf(" - volume down for 10 percent, %d%% (%d) \n", volume_percentage, volume);
|
||||
status = avrcp_target_volume_changed(avrcp_cid, volume);
|
||||
status = avrcp_target_volume_changed(connection->avrcp_cid, volume);
|
||||
avrcp_volume_changed(volume);
|
||||
break;
|
||||
case 'V':
|
||||
@ -964,107 +965,107 @@ static void stdin_process(char cmd){
|
||||
battery_status = AVRCP_BATTERY_STATUS_NORMAL;
|
||||
}
|
||||
printf(" - toggle battery value, old %d, new %d\n", old_battery_status, battery_status);
|
||||
status = avrcp_target_battery_status_changed(avrcp_cid, battery_status);
|
||||
status = avrcp_target_battery_status_changed(connection->avrcp_cid, battery_status);
|
||||
break;
|
||||
case 'O':
|
||||
printf(" - get play status\n");
|
||||
status = avrcp_controller_get_play_status(avrcp_cid);
|
||||
status = avrcp_controller_get_play_status(connection->avrcp_cid);
|
||||
break;
|
||||
case 'j':
|
||||
printf(" - get now playing info\n");
|
||||
status = avrcp_controller_get_now_playing_info(avrcp_cid);
|
||||
status = avrcp_controller_get_now_playing_info(connection->avrcp_cid);
|
||||
break;
|
||||
case 'k':
|
||||
printf(" - play\n");
|
||||
status = avrcp_controller_play(avrcp_cid);
|
||||
status = avrcp_controller_play(connection->avrcp_cid);
|
||||
break;
|
||||
case 'K':
|
||||
printf(" - stop\n");
|
||||
status = avrcp_controller_stop(avrcp_cid);
|
||||
status = avrcp_controller_stop(connection->avrcp_cid);
|
||||
break;
|
||||
case 'L':
|
||||
printf(" - pause\n");
|
||||
status = avrcp_controller_pause(avrcp_cid);
|
||||
status = avrcp_controller_pause(connection->avrcp_cid);
|
||||
break;
|
||||
case 'u':
|
||||
printf(" - start fast forward\n");
|
||||
status = avrcp_controller_press_and_hold_fast_forward(avrcp_cid);
|
||||
status = avrcp_controller_press_and_hold_fast_forward(connection->avrcp_cid);
|
||||
break;
|
||||
case 'U':
|
||||
printf(" - stop fast forward\n");
|
||||
status = avrcp_controller_release_press_and_hold_cmd(avrcp_cid);
|
||||
status = avrcp_controller_release_press_and_hold_cmd(connection->avrcp_cid);
|
||||
break;
|
||||
case 'n':
|
||||
printf(" - start rewind\n");
|
||||
status = avrcp_controller_press_and_hold_rewind(avrcp_cid);
|
||||
status = avrcp_controller_press_and_hold_rewind(connection->avrcp_cid);
|
||||
break;
|
||||
case 'N':
|
||||
printf(" - stop rewind\n");
|
||||
status = avrcp_controller_release_press_and_hold_cmd(avrcp_cid);
|
||||
status = avrcp_controller_release_press_and_hold_cmd(connection->avrcp_cid);
|
||||
break;
|
||||
case 'i':
|
||||
printf(" - forward\n");
|
||||
status = avrcp_controller_forward(avrcp_cid);
|
||||
status = avrcp_controller_forward(connection->avrcp_cid);
|
||||
break;
|
||||
case 'I':
|
||||
printf(" - backward\n");
|
||||
status = avrcp_controller_backward(avrcp_cid);
|
||||
status = avrcp_controller_backward(connection->avrcp_cid);
|
||||
break;
|
||||
case 'M':
|
||||
printf(" - mute\n");
|
||||
status = avrcp_controller_mute(avrcp_cid);
|
||||
status = avrcp_controller_mute(connection->avrcp_cid);
|
||||
break;
|
||||
case 'r':
|
||||
printf(" - skip\n");
|
||||
status = avrcp_controller_skip(avrcp_cid);
|
||||
status = avrcp_controller_skip(connection->avrcp_cid);
|
||||
break;
|
||||
case 'q':
|
||||
printf(" - query repeat and shuffle mode\n");
|
||||
status = avrcp_controller_query_shuffle_and_repeat_modes(avrcp_cid);
|
||||
status = avrcp_controller_query_shuffle_and_repeat_modes(connection->avrcp_cid);
|
||||
break;
|
||||
case 'v':
|
||||
printf(" - repeat single track\n");
|
||||
status = avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK);
|
||||
status = avrcp_controller_set_repeat_mode(connection->avrcp_cid, AVRCP_REPEAT_MODE_SINGLE_TRACK);
|
||||
break;
|
||||
case 'x':
|
||||
printf(" - repeat all tracks\n");
|
||||
status = avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS);
|
||||
status = avrcp_controller_set_repeat_mode(connection->avrcp_cid, AVRCP_REPEAT_MODE_ALL_TRACKS);
|
||||
break;
|
||||
case 'X':
|
||||
printf(" - disable repeat mode\n");
|
||||
status = avrcp_controller_set_repeat_mode(avrcp_cid, AVRCP_REPEAT_MODE_OFF);
|
||||
status = avrcp_controller_set_repeat_mode(connection->avrcp_cid, AVRCP_REPEAT_MODE_OFF);
|
||||
break;
|
||||
case 'z':
|
||||
printf(" - shuffle all tracks\n");
|
||||
status = avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS);
|
||||
status = avrcp_controller_set_shuffle_mode(connection->avrcp_cid, AVRCP_SHUFFLE_MODE_ALL_TRACKS);
|
||||
break;
|
||||
case 'Z':
|
||||
printf(" - disable shuffle mode\n");
|
||||
status = avrcp_controller_set_shuffle_mode(avrcp_cid, AVRCP_SHUFFLE_MODE_OFF);
|
||||
status = avrcp_controller_set_shuffle_mode(connection->avrcp_cid, AVRCP_SHUFFLE_MODE_OFF);
|
||||
break;
|
||||
case 'a':
|
||||
printf("AVRCP: enable notification TRACK_CHANGED\n");
|
||||
avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
avrcp_controller_enable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
break;
|
||||
case 'A':
|
||||
printf("AVRCP: disable notification TRACK_CHANGED\n");
|
||||
avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
avrcp_controller_disable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||
break;
|
||||
case 'R':
|
||||
printf("AVRCP: enable notification PLAYBACK_POS_CHANGED\n");
|
||||
avrcp_controller_enable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED);
|
||||
avrcp_controller_enable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED);
|
||||
break;
|
||||
case 'P':
|
||||
printf("AVRCP: disable notification PLAYBACK_POS_CHANGED\n");
|
||||
avrcp_controller_disable_notification(avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED);
|
||||
avrcp_controller_disable_notification(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED);
|
||||
break;
|
||||
case 's':
|
||||
printf("AVRCP: send long button press REWIND\n");
|
||||
avrcp_controller_start_press_and_hold_cmd(avrcp_cid, AVRCP_OPERATION_ID_REWIND);
|
||||
avrcp_controller_start_press_and_hold_cmd(connection->avrcp_cid, AVRCP_OPERATION_ID_REWIND);
|
||||
break;
|
||||
case 'S':
|
||||
printf("AVRCP: release long button press REWIND\n");
|
||||
avrcp_controller_release_press_and_hold_cmd(avrcp_cid);
|
||||
avrcp_controller_release_press_and_hold_cmd(connection->avrcp_cid);
|
||||
break;
|
||||
default:
|
||||
show_usage();
|
||||
@ -1084,7 +1085,7 @@ int btstack_main(int argc, const char * argv[]){
|
||||
a2dp_and_avrcp_setup();
|
||||
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
// parse human readable Bluetooth address
|
||||
// parse human-readable Bluetooth address
|
||||
sscanf_bd_addr(device_addr_string, device_addr);
|
||||
btstack_stdin_setup(stdin_process);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user