diff --git a/apps/btshell/src/btshell.h b/apps/btshell/src/btshell.h index c2a2eb3e29..04b1c989a1 100644 --- a/apps/btshell/src/btshell.h +++ b/apps/btshell/src/btshell.h @@ -221,6 +221,7 @@ int btshell_broadcast_update(uint8_t adv_instance, int btshell_broadcast_start(uint8_t adv_instance); int btshell_broadcast_stop(uint8_t adv_instance); #endif +void btshell_audio_broadcast_sink_init(void); int btshell_gap_event(struct ble_gap_event *event, void *arg); void btshell_sync_stats(uint16_t handle); diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c index 4c00d7ba35..68f816e972 100644 --- a/apps/btshell/src/cmd.c +++ b/apps/btshell/src/cmd.c @@ -87,14 +87,14 @@ static const struct parse_arg_kv_pair cmd_peer_addr_types[] = { { NULL } }; -static const struct parse_arg_kv_pair cmd_addr_type[] = { +const struct parse_arg_kv_pair cmd_addr_type[] = { { "public", BLE_ADDR_PUBLIC }, { "random", BLE_ADDR_RANDOM }, { NULL } }; -static int +int parse_dev_addr(const char *prefix, const struct parse_arg_kv_pair *addr_types, ble_addr_t *addr) { @@ -4924,6 +4924,50 @@ static const struct shell_cmd btshell_commands[] = { .help = &leaudio_broadcast_stop_help, #endif }, +#endif +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + { + .sc_cmd = "broadcast-sink-create", + .sc_cmd_func = cmd_leaudio_broadcast_sink_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_create_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-destroy", + .sc_cmd_func = cmd_leaudio_broadcast_sink_destroy, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_destroy_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-pa-sync", + .sc_cmd_func = cmd_leaudio_broadcast_sink_pa_sync, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_pa_sync_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-pa-sync-term", + .sc_cmd_func = cmd_leaudio_broadcast_sink_pa_sync_term, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_pa_sync_term_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-big-sync", + .sc_cmd_func = cmd_leaudio_broadcast_sink_sync, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_big_sync_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-big-sync-term", + .sc_cmd_func = cmd_leaudio_broadcast_sink_big_sync_term, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_big_sync_term_help, +#endif + }, #endif /* BLE_ISO_BROADCAST_SOURCE */ #if MYNEWT_VAL(BLE_ISO) #if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) diff --git a/apps/btshell/src/cmd.h b/apps/btshell/src/cmd.h index 1477ea85c7..4795002cc5 100644 --- a/apps/btshell/src/cmd.h +++ b/apps/btshell/src/cmd.h @@ -24,12 +24,17 @@ #include "host/ble_uuid.h" #include +extern const struct parse_arg_kv_pair cmd_addr_type[]; + int parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body, uint8_t *out_body_len, uint8_t *out_suffix); int cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start, uint16_t *out_end); +int parse_dev_addr(const char *prefix, const struct parse_arg_kv_pair *addr_types, + ble_addr_t *addr); + void cmd_init(void); #endif diff --git a/apps/btshell/src/cmd_leaudio.c b/apps/btshell/src/cmd_leaudio.c index 2f31246cf8..c216936c39 100644 --- a/apps/btshell/src/cmd_leaudio.c +++ b/apps/btshell/src/cmd_leaudio.c @@ -17,12 +17,14 @@ * under the License. */ +#include "audio/ble_audio.h" #include "cmd_leaudio.h" #include "btshell.h" #include "console/console.h" +#include "shell/shell.h" #include "errno.h" -#if (MYNEWT_VAL(BLE_AUDIO)) +#if (MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE)) #include "audio/ble_audio_broadcast_source.h" int cmd_leaudio_base_add(int argc, char **argv) @@ -382,4 +384,479 @@ cmd_leaudio_broadcast_stop(int argc, char **argv) return btshell_broadcast_stop(adv_instance); } +#endif /* BLE_ISO_BROADCAST_SOURCE */ + +#if (MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)) +#include "audio/ble_audio_broadcast_sink.h" + +static struct ble_audio_event_listener audio_event_listener; + +static const char * +addr_type_str(uint8_t type) +{ + const struct parse_arg_kv_pair *kvs = cmd_addr_type; + int i; + + for (i = 0; kvs[i].key != NULL; i++) { + if (type == kvs[i].val) { + return kvs[i].key; + } + } + + return "unknown"; +} + +static void +print_codec_id(struct ble_audio_codec_id *codec_id) +{ + console_printf(" codec_id={0x%02x, 0x%04x, 0x%04x}", + codec_id->format, codec_id->company_id, codec_id->vendor_specific); +} + +static int +audio_event_handler(struct ble_audio_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT: { + struct ble_audio_event_broadcast_announcement *ev; + + ev = &event->broadcast_announcement; + + console_printf("BCST: broadcast_id=0x%6x sid=%d pa_interval=0x%04x" + " adv_addr_type=%s adv_addr=", + ev->broadcast_id, ev->ext_disc->sid, + ev->ext_disc->periodic_adv_itvl, + addr_type_str(ev->ext_disc->addr.type)); + print_addr(ev->ext_disc->addr.val); + console_printf("\n"); + + if (ev->svc_data_len > 0) { + console_printf(" svc_data="); + print_bytes(ev->svc_data, ev->svc_data_len); + console_printf("\n"); + } + + if (ev->pub_announcement_data != NULL) { + console_printf(" pba_features=0x%02x\n", + ev->pub_announcement_data->features); + if (ev->pub_announcement_data->metadata_len > 0) { + console_printf(" metadata="); + print_bytes(ev->pub_announcement_data->metadata, + ev->pub_announcement_data->metadata_len); + console_printf("\n"); + } + } + + if (ev->name != NULL) { + console_printf(" name=%.*s\n", ev->name->name_len, ev->name->name); + } + + break; + } + + case BLE_AUDIO_EVENT_BROADCAST_SINK_BASE_REPORT: { + struct ble_audio_event_broadcast_sink_base_report *ev; + struct ble_audio_base_iter subgroup_iter; + struct ble_audio_base_group group; + + ev = &event->base_report; + + console_printf("BASE: tx_power=%d rssi=%d base_len=%d\n", + ev->tx_power, ev->rssi, ev->base_length); + + rc = ble_audio_base_parse(ev->base, ev->base_length, &group, &subgroup_iter); + if (rc != 0){ + console_printf("Failed to parse BASE (%d)\n", rc); + return rc; + } + + console_printf(" presentation_delay=%d num_sub=%d\n", + group.presentation_delay, group.num_subgroups); + + for (uint8_t i = 0; i < group.num_subgroups; i++) { + struct ble_audio_base_subgroup subgroup; + struct ble_audio_base_iter bis_iter; + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + if (rc != 0){ + console_printf("Failed to parse BASE subgroup (%d)\n", rc); + return rc; + } + + print_codec_id(&subgroup.codec_id); + console_printf("\n"); + + if (subgroup.codec_spec_config_len > 0) { + console_printf(" config="); + print_bytes(subgroup.codec_spec_config, subgroup.codec_spec_config_len); + console_printf("\n"); + } + + if (subgroup.metadata_len > 0) { + console_printf(" metadata="); + print_bytes(subgroup.metadata, subgroup.metadata_len); + console_printf("\n"); + } + + console_printf(" num_bis=%d \n", subgroup.num_bis); + + for (uint8_t j = 0; j < subgroup.num_bis; j++) { + struct ble_audio_base_bis bis; + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + if (rc != 0){ + console_printf("Failed to parse BASE subgroup (%d)\n", rc); + return rc; + } + + console_printf(" bis_index=0x%02x \n", bis.index); + + if (bis.codec_spec_config_len > 0) { + console_printf(" config="); + print_bytes(bis.codec_spec_config, bis.codec_spec_config_len); + console_printf("\n"); + } + } + } + + break; + } + + default: + break; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_create_params[] = { + {"adv_addr_type", "usage: =[public|random], default: public"}, + {"adv_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, + {"broadcast_id", "usage: =[0-0xFFFFFF]"}, + {"sid", "usage: =[UINT8], default: 0"}, + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_create_help = { + .summary = "Create Broadcast Sink", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_create_params +}; +#endif + +int +cmd_leaudio_broadcast_sink_create(int argc, char **argv) +{ + struct ble_audio_broadcast_sink_create_params params = { 0 }; + ble_addr_t adv_addr; + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + rc = parse_dev_addr("adv_", cmd_addr_type, &adv_addr); + if (rc != 0) { + console_printf("invalid 'adv_addr' parameter\n"); + return rc; + } + + params.adv_addr = &adv_addr; + + params.broadcast_id = parse_arg_uint32("broadcast_id", &rc); + if (rc != 0) { + return rc; + } + + params.adv_sid = parse_arg_uint8("sid", &rc); + if (rc != 0) { + console_printf("invalid sid parameter\n"); + return rc; + } + + params.cb = audio_event_handler; + + rc = ble_audio_broadcast_sink_create(¶ms, &instance_id); + if (rc != 0) { + console_printf("Failed to create Audio Broadcast Sink instance (%d)\n", rc); + } else { + console_printf("Broadcast Sink instance_id %u created\n", instance_id); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_destroy_params[] = { + {"instance_id", "usage: ="}, + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_destroy_help = { + .summary = "Destroy Broadcast Sink", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_destroy_params +}; +#endif + +int +cmd_leaudio_broadcast_sink_destroy(int argc, char **argv) +{ + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + instance_id = parse_arg_uint8("instance_id", &rc); + if (rc != 0) { + console_printf("invalid instance_id parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_destroy(instance_id); + if (rc != 0) { + console_printf("Failed to destroy Audio Broadcast Sink instance (%d)\n", rc); + } else { + console_printf("Broadcast Sink instance_id %u destroyed\n", instance_id); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_pa_sync_params[] = { + {"instance_id", "usage: ="}, + {"skip", "usage: =[0-0x01F3], default: 0x0000"}, + {"sync_timeout", "usage: =[0x000A-0x4000], default: 0x07D0"}, + {"reports_disabled", "disable reports, usage: =[0-1], default: 0"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_pa_sync_help = { + .summary = "Sync to Broadcast Source PA", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_pa_sync_params +}; +#endif + +int +cmd_leaudio_broadcast_sink_pa_sync(int argc, char **argv) +{ + struct ble_gap_periodic_sync_params params = { 0 }; + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + instance_id = parse_arg_uint8("instance_id", &rc); + if (rc != 0) { + console_printf("invalid instance_id parameter\n"); + return rc; + } + + params.skip = parse_arg_uint16_dflt("skip", 0, &rc); + if (rc != 0) { + console_printf("invalid 'skip' parameter\n"); + return rc; + } + + params.sync_timeout = parse_arg_time_dflt("sync_timeout", 10000, 2000, &rc); + if (rc != 0) { + console_printf("invalid 'sync_timeout' parameter\n"); + return rc; + } + + params.reports_disabled = parse_arg_bool_dflt("reports_disabled", false, &rc); + if (rc != 0) { + console_printf("invalid 'reports_disabled' parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_pa_sync(instance_id, ¶ms); + if (rc != 0) { + console_printf("Failed to initiate PA Sync (%d)\n", rc); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_pa_sync_term_params[] = { + {"instance_id", "usage: ="}, + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_pa_sync_term_help = { + .summary = "Terminate PA Sync", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_pa_sync_term_params +}; +#endif + +int +cmd_leaudio_broadcast_sink_pa_sync_term(int argc, char **argv) +{ + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + instance_id = parse_arg_uint8("instance_id", &rc); + if (rc != 0) { + console_printf("invalid instance_id parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_pa_sync_term(instance_id); + if (rc != 0) { + console_printf("Failed to terminate PA Sync (%d)\n", rc); + } + + return rc; +} + +static int +iso_event_handler(struct ble_iso_event *event, void *arg) +{ + switch (event->type) { + case BLE_ISO_EVENT_ISO_RX: + break; + + default: + break; + } + + return 0; +} + + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_big_sync_params[] = { + {"instance_id", "usage: ="}, + {"bis_sync_mask", "mask of BIS indexes to sync, usage: ="}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_big_sync_help = { + .summary = "Sync to Audio Broadcast", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_big_sync_params +}; +#endif + +int +cmd_leaudio_broadcast_sink_sync(int argc, char **argv) +{ + struct ble_audio_broadcast_sink_bis_params bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)] = { 0 }; + struct ble_audio_broadcast_sink_big_sync_params big_params = { + .bis_params = bis_params, + }; + uint8_t bis_index = 0x01; + uint16_t bis_sync_mask; + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + instance_id = parse_arg_uint8("instance_id", &rc); + if (rc != 0) { + console_printf("invalid instance_id parameter\n"); + return rc; + } + + bis_sync_mask = parse_arg_uint16("bis_sync_mask", &rc); + if (rc != 0) { + console_printf("invalid 'bis_sync_mask' parameter\n"); + return rc; + } + + big_params.num_bis = __builtin_popcount(bis_sync_mask); + + for (uint8_t i = 0; i < big_params.num_bis; i++) { + while (bis_params[i].bis_index == 0) { + if (bis_sync_mask & (1 << (bis_index - 1))) { + bis_params[i].bis_index = bis_index; + bis_params[i].cb = iso_event_handler; + bis_params[i].cb_arg = NULL; + } + + bis_index++; + } + } + + rc = ble_audio_broadcast_sink_big_sync(instance_id, &big_params); + if (rc != 0) { + console_printf("Failed to synchronize sink (%d)\n", rc); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_big_sync_term_params[] = { + {"instance_id", "usage: ="}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_big_sync_term_help = { + .summary = "Terminate Audio Broadcast Sync", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_big_sync_term_params +}; #endif + +int +cmd_leaudio_broadcast_sink_big_sync_term(int argc, char **argv) +{ + uint8_t instance_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + instance_id = parse_arg_uint8("instance_id", &rc); + if (rc != 0) { + console_printf("invalid instance_id parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_big_sync_term(instance_id); + if (rc != 0) { + console_printf("Failed to terminate sink (%d)\n", rc); + } + + return rc; +} + +#endif /* BLE_AUDIO_BROADCAST_SINK */ + +void +btshell_audio_broadcast_sink_init(void) +{ +#if (MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)) + int rc; + + rc = ble_audio_event_listener_register(&audio_event_listener, + audio_event_handler, NULL); + assert(rc == 0); +#endif /* BLE_AUDIO_BROADCAST_SINK */ +} diff --git a/apps/btshell/src/cmd_leaudio.h b/apps/btshell/src/cmd_leaudio.h index 84fc458626..72c59156b6 100644 --- a/apps/btshell/src/cmd_leaudio.h +++ b/apps/btshell/src/cmd_leaudio.h @@ -43,4 +43,18 @@ int cmd_leaudio_broadcast_update(int argc, char **argv); int cmd_leaudio_broadcast_start(int argc, char **argv); int cmd_leaudio_broadcast_stop(int argc, char **argv); +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_create_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_destroy_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_pa_sync_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_pa_sync_term_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_big_sync_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_big_sync_term_help; + +int cmd_leaudio_broadcast_sink_create(int argc, char **argv); +int cmd_leaudio_broadcast_sink_destroy(int argc, char **argv); +int cmd_leaudio_broadcast_sink_pa_sync(int argc, char **argv); +int cmd_leaudio_broadcast_sink_pa_sync_term(int argc, char **argv); +int cmd_leaudio_broadcast_sink_sync(int argc, char **argv); +int cmd_leaudio_broadcast_sink_big_sync_term(int argc, char **argv); + #endif /* H_CMD_LEAUDIO_ */ diff --git a/apps/btshell/src/main.c b/apps/btshell/src/main.c index 0ba90ff131..cc3218d8c8 100644 --- a/apps/btshell/src/main.c +++ b/apps/btshell/src/main.c @@ -2078,6 +2078,10 @@ btshell_ext_scan(uint8_t own_addr_type, uint16_t duration, uint16_t period, const struct ble_gap_ext_disc_params *coded_params, void *cb_args) { + struct btshell_scan_opts *scan_opts = cb_args; + + console_printf("silent %d.", scan_opts->silent); + #if !MYNEWT_VAL(BLE_EXT_ADV) console_printf("BLE extended advertising not supported."); console_printf(" Configure nimble host to enable it\n"); @@ -3143,6 +3147,8 @@ mynewt_main(int argc, char **argv) btshell_init_ext_adv_restart(); + btshell_audio_broadcast_sink_init(); + while (1) { os_eventq_run(os_eventq_dflt_get()); } diff --git a/apps/btshell/syscfg.yml b/apps/btshell/syscfg.yml index 091a2df0c1..08bd066f5f 100644 --- a/apps/btshell/syscfg.yml +++ b/apps/btshell/syscfg.yml @@ -50,3 +50,6 @@ syscfg.vals: syscfg.vals.BLE_MESH: MSYS_1_BLOCK_COUNT: 16 + +syscfg.vals.BLE_AUDIO_BSNK: + BLE_AUDIO_BSNK_MAX: 1 diff --git a/nimble/host/audio/targets/btshell_native/pkg.yml b/nimble/host/audio/targets/btshell_native/pkg.yml index 67eb2d6fe5..7c129c62ff 100644 --- a/nimble/host/audio/targets/btshell_native/pkg.yml +++ b/nimble/host/audio/targets/btshell_native/pkg.yml @@ -24,3 +24,4 @@ pkg.description: Target for native btshell application with LE Audio pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.deps: + - nimble/host/audio diff --git a/nimble/host/audio/targets/btshell_native/syscfg.yml b/nimble/host/audio/targets/btshell_native/syscfg.yml index e9db007074..ce617216a0 100644 --- a/nimble/host/audio/targets/btshell_native/syscfg.yml +++ b/nimble/host/audio/targets/btshell_native/syscfg.yml @@ -64,6 +64,8 @@ syscfg.vals: BLE_ISO_MAX_BIGS: 1 BLE_ISO_MAX_BISES: 2 + BLE_AUDIO_BROADCAST_SINK: 1 + CONSOLE_UART: 1 CONSOLE_UART_BAUD: 1000000 CONSOLE_STICKY_PROMPT: 1