1*3fb2c90bSMilanka Ringwald /* 2*3fb2c90bSMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3*3fb2c90bSMilanka Ringwald * 4*3fb2c90bSMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5*3fb2c90bSMilanka Ringwald * modification, are permitted provided that the following conditions 6*3fb2c90bSMilanka Ringwald * are met: 7*3fb2c90bSMilanka Ringwald * 8*3fb2c90bSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9*3fb2c90bSMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10*3fb2c90bSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*3fb2c90bSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12*3fb2c90bSMilanka Ringwald * documentation and/or other materials provided with the distribution. 13*3fb2c90bSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14*3fb2c90bSMilanka Ringwald * contributors may be used to endorse or promote products derived 15*3fb2c90bSMilanka Ringwald * from this software without specific prior written permission. 16*3fb2c90bSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17*3fb2c90bSMilanka Ringwald * personal benefit and not for any commercial purpose or for 18*3fb2c90bSMilanka Ringwald * monetary gain. 19*3fb2c90bSMilanka Ringwald * 20*3fb2c90bSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*3fb2c90bSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*3fb2c90bSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*3fb2c90bSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*3fb2c90bSMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*3fb2c90bSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*3fb2c90bSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*3fb2c90bSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*3fb2c90bSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*3fb2c90bSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*3fb2c90bSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*3fb2c90bSMilanka Ringwald * SUCH DAMAGE. 32*3fb2c90bSMilanka Ringwald * 33*3fb2c90bSMilanka Ringwald * Please inquire about commercial licensing options at 34*3fb2c90bSMilanka Ringwald * [email protected] 35*3fb2c90bSMilanka Ringwald * 36*3fb2c90bSMilanka Ringwald */ 37*3fb2c90bSMilanka Ringwald 38*3fb2c90bSMilanka Ringwald 39*3fb2c90bSMilanka Ringwald #include <stdint.h> 40*3fb2c90bSMilanka Ringwald #include <stdio.h> 41*3fb2c90bSMilanka Ringwald #include <stdlib.h> 42*3fb2c90bSMilanka Ringwald #include <string.h> 43*3fb2c90bSMilanka Ringwald 44*3fb2c90bSMilanka Ringwald #include "btstack.h" 45*3fb2c90bSMilanka Ringwald 46*3fb2c90bSMilanka Ringwald #include "hxcmod.h" 47*3fb2c90bSMilanka Ringwald #include "mods/mod.h" 48*3fb2c90bSMilanka Ringwald 49*3fb2c90bSMilanka Ringwald #define NUM_CHANNELS 2 50*3fb2c90bSMilanka Ringwald #define A2DP_SAMPLE_RATE 44100 51*3fb2c90bSMilanka Ringwald #define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS) 52*3fb2c90bSMilanka Ringwald #define FILL_AUDIO_BUFFER_TIMEOUT_MS 10 53*3fb2c90bSMilanka Ringwald 54*3fb2c90bSMilanka Ringwald #ifndef M_PI 55*3fb2c90bSMilanka Ringwald #define M_PI 3.14159265 56*3fb2c90bSMilanka Ringwald #endif 57*3fb2c90bSMilanka Ringwald #define TABLE_SIZE_441HZ 100 58*3fb2c90bSMilanka Ringwald 59*3fb2c90bSMilanka Ringwald typedef struct { 60*3fb2c90bSMilanka Ringwald int left_phase; 61*3fb2c90bSMilanka Ringwald int right_phase; 62*3fb2c90bSMilanka Ringwald } paTestData; 63*3fb2c90bSMilanka Ringwald 64*3fb2c90bSMilanka Ringwald typedef enum { 65*3fb2c90bSMilanka Ringwald STREAM_SINE, 66*3fb2c90bSMilanka Ringwald STREAM_MOD 67*3fb2c90bSMilanka Ringwald } stream_data_source_t; 68*3fb2c90bSMilanka Ringwald 69*3fb2c90bSMilanka Ringwald static uint8_t media_sbc_codec_capabilities[] = { 70*3fb2c90bSMilanka Ringwald (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, 71*3fb2c90bSMilanka Ringwald 0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS, 72*3fb2c90bSMilanka Ringwald 2, 53 73*3fb2c90bSMilanka Ringwald }; 74*3fb2c90bSMilanka Ringwald 75*3fb2c90bSMilanka Ringwald static const int16_t sine_int16[] = { 76*3fb2c90bSMilanka Ringwald 0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557, 77*3fb2c90bSMilanka Ringwald 19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466, 78*3fb2c90bSMilanka Ringwald 31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738, 79*3fb2c90bSMilanka Ringwald 31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886, 80*3fb2c90bSMilanka Ringwald 19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057, 81*3fb2c90bSMilanka Ringwald 0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557, 82*3fb2c90bSMilanka Ringwald -19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466, 83*3fb2c90bSMilanka Ringwald -31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738, 84*3fb2c90bSMilanka Ringwald -31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886, 85*3fb2c90bSMilanka Ringwald -19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057, 86*3fb2c90bSMilanka Ringwald }; 87*3fb2c90bSMilanka Ringwald 88*3fb2c90bSMilanka Ringwald static char * device_name = "A2DP Source BTstack"; 89*3fb2c90bSMilanka Ringwald 90*3fb2c90bSMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 91*3fb2c90bSMilanka Ringwald // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; 92*3fb2c90bSMilanka Ringwald // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; 93*3fb2c90bSMilanka Ringwald // mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; 94*3fb2c90bSMilanka Ringwald // phone 2013: static bd_addr_t remote = {0xD8, 0xBB, 0x2C, 0xDF, 0xF0, 0xF2}; 95*3fb2c90bSMilanka Ringwald // minijambox: 96*3fb2c90bSMilanka Ringwald static bd_addr_t remote = {0x00, 0x21, 0x3c, 0xac, 0xf7, 0x38}; 97*3fb2c90bSMilanka Ringwald // head phones: static bd_addr_t remote = {0x00, 0x18, 0x09, 0x28, 0x50, 0x18}; 98*3fb2c90bSMilanka Ringwald // bt dongle: -u 02-04-01 99*3fb2c90bSMilanka Ringwald // static bd_addr_t remote = {0x00, 0x15, 0x83, 0x5F, 0x9D, 0x46}; 100*3fb2c90bSMilanka Ringwald #endif 101*3fb2c90bSMilanka Ringwald 102*3fb2c90bSMilanka Ringwald static uint8_t sdp_avdtp_source_service_buffer[150]; 103*3fb2c90bSMilanka Ringwald static uint8_t media_sbc_codec_configuration[4]; 104*3fb2c90bSMilanka Ringwald 105*3fb2c90bSMilanka Ringwald typedef struct { 106*3fb2c90bSMilanka Ringwald uint16_t a2dp_cid; 107*3fb2c90bSMilanka Ringwald uint8_t local_seid; 108*3fb2c90bSMilanka Ringwald 109*3fb2c90bSMilanka Ringwald uint32_t time_audio_data_sent; // ms 110*3fb2c90bSMilanka Ringwald uint32_t acc_num_missed_samples; 111*3fb2c90bSMilanka Ringwald uint32_t samples_ready; 112*3fb2c90bSMilanka Ringwald btstack_timer_source_t fill_audio_buffer_timer; 113*3fb2c90bSMilanka Ringwald uint8_t streaming; 114*3fb2c90bSMilanka Ringwald 115*3fb2c90bSMilanka Ringwald int max_media_payload_size; 116*3fb2c90bSMilanka Ringwald 117*3fb2c90bSMilanka Ringwald uint8_t sbc_storage[1030]; 118*3fb2c90bSMilanka Ringwald uint16_t sbc_storage_count; 119*3fb2c90bSMilanka Ringwald uint8_t sbc_ready_to_send; 120*3fb2c90bSMilanka Ringwald 121*3fb2c90bSMilanka Ringwald } a2dp_media_sending_context_t; 122*3fb2c90bSMilanka Ringwald 123*3fb2c90bSMilanka Ringwald static a2dp_media_sending_context_t media_tracker; 124*3fb2c90bSMilanka Ringwald 125*3fb2c90bSMilanka Ringwald static paTestData sin_data; 126*3fb2c90bSMilanka Ringwald 127*3fb2c90bSMilanka Ringwald static int hxcmod_initialized = 0; 128*3fb2c90bSMilanka Ringwald static modcontext mod_context; 129*3fb2c90bSMilanka Ringwald static tracker_buffer_state trkbuf; 130*3fb2c90bSMilanka Ringwald 131*3fb2c90bSMilanka Ringwald static uint8_t local_seid = 0; 132*3fb2c90bSMilanka Ringwald stream_data_source_t data_source = STREAM_SINE; 133*3fb2c90bSMilanka Ringwald 134*3fb2c90bSMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 135*3fb2c90bSMilanka Ringwald 136*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context); 137*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context); 138*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context); 139*3fb2c90bSMilanka Ringwald 140*3fb2c90bSMilanka Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 141*3fb2c90bSMilanka Ringwald UNUSED(channel); 142*3fb2c90bSMilanka Ringwald UNUSED(size); 143*3fb2c90bSMilanka Ringwald uint8_t status; 144*3fb2c90bSMilanka Ringwald switch (packet_type) { 145*3fb2c90bSMilanka Ringwald 146*3fb2c90bSMilanka Ringwald case HCI_EVENT_PACKET: 147*3fb2c90bSMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 148*3fb2c90bSMilanka Ringwald case HCI_EVENT_A2DP_META: 149*3fb2c90bSMilanka Ringwald switch (packet[2]){ 150*3fb2c90bSMilanka Ringwald case A2DP_SUBEVENT_STREAM_ESTABLISHED: 151*3fb2c90bSMilanka Ringwald status = a2dp_subevent_stream_established_get_status(packet); 152*3fb2c90bSMilanka Ringwald if (status){ 153*3fb2c90bSMilanka Ringwald printf("Stream establishment failed: status 0x%02x.\n", status); 154*3fb2c90bSMilanka Ringwald break; 155*3fb2c90bSMilanka Ringwald } 156*3fb2c90bSMilanka Ringwald media_tracker.local_seid = a2dp_subevent_stream_established_get_local_seid(packet); 157*3fb2c90bSMilanka Ringwald media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); 158*3fb2c90bSMilanka Ringwald printf("Stream established: a2dp cid 0x%02x, local seid %d, remote seid %d.\n", 159*3fb2c90bSMilanka Ringwald media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet)); 160*3fb2c90bSMilanka Ringwald break; 161*3fb2c90bSMilanka Ringwald 162*3fb2c90bSMilanka Ringwald case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:{ 163*3fb2c90bSMilanka Ringwald if (local_seid != media_tracker.local_seid) break; 164*3fb2c90bSMilanka Ringwald 165*3fb2c90bSMilanka Ringwald int num_bytes_in_frame = btstack_sbc_encoder_sbc_buffer_length(); 166*3fb2c90bSMilanka Ringwald int bytes_in_storage = media_tracker.sbc_storage_count; 167*3fb2c90bSMilanka Ringwald uint8_t num_frames = bytes_in_storage / num_bytes_in_frame; 168*3fb2c90bSMilanka Ringwald 169*3fb2c90bSMilanka Ringwald a2dp_source_stream_send_media_payload(media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0); 170*3fb2c90bSMilanka Ringwald media_tracker.sbc_storage_count = 0; 171*3fb2c90bSMilanka Ringwald media_tracker.sbc_ready_to_send = 0; 172*3fb2c90bSMilanka Ringwald break; 173*3fb2c90bSMilanka Ringwald } 174*3fb2c90bSMilanka Ringwald case A2DP_SUBEVENT_STREAM_STARTED: 175*3fb2c90bSMilanka Ringwald if (local_seid != media_tracker.local_seid) break; 176*3fb2c90bSMilanka Ringwald if (!a2dp_source_stream_endpoint_ready(media_tracker.a2dp_cid, media_tracker.local_seid)) break; 177*3fb2c90bSMilanka Ringwald a2dp_fill_audio_buffer_timer_start(&media_tracker); 178*3fb2c90bSMilanka Ringwald printf("Stream started.\n"); 179*3fb2c90bSMilanka Ringwald break; 180*3fb2c90bSMilanka Ringwald 181*3fb2c90bSMilanka Ringwald case A2DP_SUBEVENT_STREAM_SUSPENDED: 182*3fb2c90bSMilanka Ringwald printf("Stream paused.\n"); 183*3fb2c90bSMilanka Ringwald a2dp_fill_audio_buffer_timer_pause(&media_tracker); 184*3fb2c90bSMilanka Ringwald break; 185*3fb2c90bSMilanka Ringwald 186*3fb2c90bSMilanka Ringwald case A2DP_SUBEVENT_STREAM_RELEASED: 187*3fb2c90bSMilanka Ringwald printf("Stream released.\n"); 188*3fb2c90bSMilanka Ringwald a2dp_fill_audio_buffer_timer_stop(&media_tracker); 189*3fb2c90bSMilanka Ringwald break; 190*3fb2c90bSMilanka Ringwald default: 191*3fb2c90bSMilanka Ringwald printf("AVDTP Source demo: event 0x%02x is not implemented\n", packet[2]); 192*3fb2c90bSMilanka Ringwald break; 193*3fb2c90bSMilanka Ringwald } 194*3fb2c90bSMilanka Ringwald break; 195*3fb2c90bSMilanka Ringwald default: 196*3fb2c90bSMilanka Ringwald break; 197*3fb2c90bSMilanka Ringwald } 198*3fb2c90bSMilanka Ringwald break; 199*3fb2c90bSMilanka Ringwald default: 200*3fb2c90bSMilanka Ringwald // other packet type 201*3fb2c90bSMilanka Ringwald break; 202*3fb2c90bSMilanka Ringwald } 203*3fb2c90bSMilanka Ringwald } 204*3fb2c90bSMilanka Ringwald 205*3fb2c90bSMilanka Ringwald static void produce_sine_audio(int16_t * pcm_buffer, void *user_data, int num_samples_to_write){ 206*3fb2c90bSMilanka Ringwald paTestData *data = (paTestData*)user_data; 207*3fb2c90bSMilanka Ringwald int count; 208*3fb2c90bSMilanka Ringwald for (count = 0; count < num_samples_to_write ; count++){ 209*3fb2c90bSMilanka Ringwald pcm_buffer[count * 2] = sine_int16[data->left_phase]; 210*3fb2c90bSMilanka Ringwald pcm_buffer[count * 2 + 1] = sine_int16[data->right_phase]; 211*3fb2c90bSMilanka Ringwald 212*3fb2c90bSMilanka Ringwald data->left_phase += 1; 213*3fb2c90bSMilanka Ringwald if (data->left_phase >= TABLE_SIZE_441HZ){ 214*3fb2c90bSMilanka Ringwald data->left_phase -= TABLE_SIZE_441HZ; 215*3fb2c90bSMilanka Ringwald } 216*3fb2c90bSMilanka Ringwald data->right_phase += 1; 217*3fb2c90bSMilanka Ringwald if (data->right_phase >= TABLE_SIZE_441HZ){ 218*3fb2c90bSMilanka Ringwald data->right_phase -= TABLE_SIZE_441HZ; 219*3fb2c90bSMilanka Ringwald } 220*3fb2c90bSMilanka Ringwald } 221*3fb2c90bSMilanka Ringwald } 222*3fb2c90bSMilanka Ringwald 223*3fb2c90bSMilanka Ringwald static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){ 224*3fb2c90bSMilanka Ringwald hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf); 225*3fb2c90bSMilanka Ringwald } 226*3fb2c90bSMilanka Ringwald 227*3fb2c90bSMilanka Ringwald static void produce_audio(int16_t * pcm_buffer, int num_samples){ 228*3fb2c90bSMilanka Ringwald switch (data_source){ 229*3fb2c90bSMilanka Ringwald case STREAM_SINE: 230*3fb2c90bSMilanka Ringwald produce_sine_audio(pcm_buffer, &sin_data, num_samples); 231*3fb2c90bSMilanka Ringwald break; 232*3fb2c90bSMilanka Ringwald case STREAM_MOD: 233*3fb2c90bSMilanka Ringwald produce_mod_audio(pcm_buffer, num_samples); 234*3fb2c90bSMilanka Ringwald break; 235*3fb2c90bSMilanka Ringwald } 236*3fb2c90bSMilanka Ringwald } 237*3fb2c90bSMilanka Ringwald 238*3fb2c90bSMilanka Ringwald static int fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){ 239*3fb2c90bSMilanka Ringwald // perform sbc encodin 240*3fb2c90bSMilanka Ringwald int total_num_bytes_read = 0; 241*3fb2c90bSMilanka Ringwald int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames(); 242*3fb2c90bSMilanka Ringwald while (context->samples_ready >= num_audio_samples_per_sbc_buffer 243*3fb2c90bSMilanka Ringwald && (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){ 244*3fb2c90bSMilanka Ringwald 245*3fb2c90bSMilanka Ringwald uint8_t pcm_frame[256*BYTES_PER_AUDIO_SAMPLE]; 246*3fb2c90bSMilanka Ringwald 247*3fb2c90bSMilanka Ringwald produce_audio((int16_t *) pcm_frame, num_audio_samples_per_sbc_buffer); 248*3fb2c90bSMilanka Ringwald btstack_sbc_encoder_process_data((int16_t *) pcm_frame); 249*3fb2c90bSMilanka Ringwald 250*3fb2c90bSMilanka Ringwald uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length(); 251*3fb2c90bSMilanka Ringwald uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer(); 252*3fb2c90bSMilanka Ringwald 253*3fb2c90bSMilanka Ringwald total_num_bytes_read += num_audio_samples_per_sbc_buffer; 254*3fb2c90bSMilanka Ringwald memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size); 255*3fb2c90bSMilanka Ringwald context->sbc_storage_count += sbc_frame_size; 256*3fb2c90bSMilanka Ringwald context->samples_ready -= num_audio_samples_per_sbc_buffer; 257*3fb2c90bSMilanka Ringwald } 258*3fb2c90bSMilanka Ringwald return total_num_bytes_read; 259*3fb2c90bSMilanka Ringwald } 260*3fb2c90bSMilanka Ringwald 261*3fb2c90bSMilanka Ringwald static void avdtp_fill_audio_buffer_timeout_handler(btstack_timer_source_t * timer){ 262*3fb2c90bSMilanka Ringwald a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer); 263*3fb2c90bSMilanka Ringwald btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS); 264*3fb2c90bSMilanka Ringwald btstack_run_loop_add_timer(&context->fill_audio_buffer_timer); 265*3fb2c90bSMilanka Ringwald uint32_t now = btstack_run_loop_get_time_ms(); 266*3fb2c90bSMilanka Ringwald 267*3fb2c90bSMilanka Ringwald uint32_t update_period_ms = FILL_AUDIO_BUFFER_TIMEOUT_MS; 268*3fb2c90bSMilanka Ringwald if (context->time_audio_data_sent > 0){ 269*3fb2c90bSMilanka Ringwald update_period_ms = now - context->time_audio_data_sent; 270*3fb2c90bSMilanka Ringwald } 271*3fb2c90bSMilanka Ringwald 272*3fb2c90bSMilanka Ringwald uint32_t num_samples = (update_period_ms * A2DP_SAMPLE_RATE) / 1000; 273*3fb2c90bSMilanka Ringwald context->acc_num_missed_samples += (update_period_ms * A2DP_SAMPLE_RATE) % 1000; 274*3fb2c90bSMilanka Ringwald 275*3fb2c90bSMilanka Ringwald while (context->acc_num_missed_samples >= 1000){ 276*3fb2c90bSMilanka Ringwald num_samples++; 277*3fb2c90bSMilanka Ringwald context->acc_num_missed_samples -= 1000; 278*3fb2c90bSMilanka Ringwald } 279*3fb2c90bSMilanka Ringwald context->time_audio_data_sent = now; 280*3fb2c90bSMilanka Ringwald context->samples_ready += num_samples; 281*3fb2c90bSMilanka Ringwald 282*3fb2c90bSMilanka Ringwald if (context->sbc_ready_to_send) return; 283*3fb2c90bSMilanka Ringwald 284*3fb2c90bSMilanka Ringwald fill_sbc_audio_buffer(context); 285*3fb2c90bSMilanka Ringwald 286*3fb2c90bSMilanka Ringwald if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){ 287*3fb2c90bSMilanka Ringwald // schedule sending 288*3fb2c90bSMilanka Ringwald context->sbc_ready_to_send = 1; 289*3fb2c90bSMilanka Ringwald a2dp_source_stream_endpoint_request_can_send_now(context->local_seid); 290*3fb2c90bSMilanka Ringwald } 291*3fb2c90bSMilanka Ringwald } 292*3fb2c90bSMilanka Ringwald 293*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context){ 294*3fb2c90bSMilanka Ringwald context->max_media_payload_size = a2dp_max_media_payload_size(context->local_seid); 295*3fb2c90bSMilanka Ringwald context->sbc_storage_count = 0; 296*3fb2c90bSMilanka Ringwald context->sbc_ready_to_send = 0; 297*3fb2c90bSMilanka Ringwald context->streaming = 1; 298*3fb2c90bSMilanka Ringwald btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); 299*3fb2c90bSMilanka Ringwald btstack_run_loop_set_timer_handler(&context->fill_audio_buffer_timer, avdtp_fill_audio_buffer_timeout_handler); 300*3fb2c90bSMilanka Ringwald btstack_run_loop_set_timer_context(&context->fill_audio_buffer_timer, context); 301*3fb2c90bSMilanka Ringwald btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS); 302*3fb2c90bSMilanka Ringwald btstack_run_loop_add_timer(&context->fill_audio_buffer_timer); 303*3fb2c90bSMilanka Ringwald } 304*3fb2c90bSMilanka Ringwald 305*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context){ 306*3fb2c90bSMilanka Ringwald context->time_audio_data_sent = 0; 307*3fb2c90bSMilanka Ringwald context->acc_num_missed_samples = 0; 308*3fb2c90bSMilanka Ringwald context->samples_ready = 0; 309*3fb2c90bSMilanka Ringwald context->streaming = 1; 310*3fb2c90bSMilanka Ringwald context->sbc_storage_count = 0; 311*3fb2c90bSMilanka Ringwald context->sbc_ready_to_send = 0; 312*3fb2c90bSMilanka Ringwald btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); 313*3fb2c90bSMilanka Ringwald } 314*3fb2c90bSMilanka Ringwald 315*3fb2c90bSMilanka Ringwald static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context){ 316*3fb2c90bSMilanka Ringwald // context->time_audio_data_sent = 0; 317*3fb2c90bSMilanka Ringwald btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer); 318*3fb2c90bSMilanka Ringwald } 319*3fb2c90bSMilanka Ringwald 320*3fb2c90bSMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 321*3fb2c90bSMilanka Ringwald 322*3fb2c90bSMilanka Ringwald static void show_usage(void){ 323*3fb2c90bSMilanka Ringwald bd_addr_t iut_address; 324*3fb2c90bSMilanka Ringwald gap_local_bd_addr(iut_address); 325*3fb2c90bSMilanka Ringwald printf("\n--- Bluetooth AVDTP SOURCE Test Console %s ---\n", bd_addr_to_str(iut_address)); 326*3fb2c90bSMilanka Ringwald printf("c - create connection to addr %s\n", bd_addr_to_str(remote)); 327*3fb2c90bSMilanka Ringwald printf("x - start streaming sine\n"); 328*3fb2c90bSMilanka Ringwald if (hxcmod_initialized){ 329*3fb2c90bSMilanka Ringwald printf("z - start streaming '%s'\n", mod_name); 330*3fb2c90bSMilanka Ringwald } 331*3fb2c90bSMilanka Ringwald printf("p - pause streaming\n"); 332*3fb2c90bSMilanka Ringwald printf("C - disconnect\n"); 333*3fb2c90bSMilanka Ringwald printf("Ctrl-c - exit\n"); 334*3fb2c90bSMilanka Ringwald printf("---\n"); 335*3fb2c90bSMilanka Ringwald } 336*3fb2c90bSMilanka Ringwald 337*3fb2c90bSMilanka Ringwald static void stdin_process(char cmd){ 338*3fb2c90bSMilanka Ringwald switch (cmd){ 339*3fb2c90bSMilanka Ringwald case 'c': 340*3fb2c90bSMilanka Ringwald printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(remote)); 341*3fb2c90bSMilanka Ringwald a2dp_source_establish_stream(remote, local_seid, &media_tracker.a2dp_cid); 342*3fb2c90bSMilanka Ringwald break; 343*3fb2c90bSMilanka Ringwald case 'x': 344*3fb2c90bSMilanka Ringwald printf("Playing sine.\n"); 345*3fb2c90bSMilanka Ringwald data_source = STREAM_SINE; 346*3fb2c90bSMilanka Ringwald a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 347*3fb2c90bSMilanka Ringwald break; 348*3fb2c90bSMilanka Ringwald case 'z': 349*3fb2c90bSMilanka Ringwald printf("Playing mod.\n"); 350*3fb2c90bSMilanka Ringwald data_source = STREAM_MOD; 351*3fb2c90bSMilanka Ringwald a2dp_source_start_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 352*3fb2c90bSMilanka Ringwald break; 353*3fb2c90bSMilanka Ringwald case 'p': 354*3fb2c90bSMilanka Ringwald printf("Pause stream.\n"); 355*3fb2c90bSMilanka Ringwald a2dp_source_pause_stream(media_tracker.a2dp_cid, media_tracker.local_seid); 356*3fb2c90bSMilanka Ringwald break; 357*3fb2c90bSMilanka Ringwald case 'C': 358*3fb2c90bSMilanka Ringwald printf("Disconnect\n"); 359*3fb2c90bSMilanka Ringwald a2dp_source_disconnect(media_tracker.a2dp_cid); 360*3fb2c90bSMilanka Ringwald break; 361*3fb2c90bSMilanka Ringwald default: 362*3fb2c90bSMilanka Ringwald show_usage(); 363*3fb2c90bSMilanka Ringwald break; 364*3fb2c90bSMilanka Ringwald } 365*3fb2c90bSMilanka Ringwald } 366*3fb2c90bSMilanka Ringwald #endif 367*3fb2c90bSMilanka Ringwald 368*3fb2c90bSMilanka Ringwald 369*3fb2c90bSMilanka Ringwald int btstack_main(int argc, const char * argv[]); 370*3fb2c90bSMilanka Ringwald int btstack_main(int argc, const char * argv[]){ 371*3fb2c90bSMilanka Ringwald UNUSED(argc); 372*3fb2c90bSMilanka Ringwald (void)argv; 373*3fb2c90bSMilanka Ringwald 374*3fb2c90bSMilanka Ringwald /* Register for HCI events */ 375*3fb2c90bSMilanka Ringwald hci_event_callback_registration.callback = &packet_handler; 376*3fb2c90bSMilanka Ringwald hci_add_event_handler(&hci_event_callback_registration); 377*3fb2c90bSMilanka Ringwald 378*3fb2c90bSMilanka Ringwald l2cap_init(); 379*3fb2c90bSMilanka Ringwald // Initialize AVDTP Source 380*3fb2c90bSMilanka Ringwald a2dp_source_init(); 381*3fb2c90bSMilanka Ringwald a2dp_source_register_packet_handler(&packet_handler); 382*3fb2c90bSMilanka Ringwald 383*3fb2c90bSMilanka Ringwald local_seid = a2dp_source_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)); 384*3fb2c90bSMilanka Ringwald 385*3fb2c90bSMilanka Ringwald // Initialize SDP 386*3fb2c90bSMilanka Ringwald sdp_init(); 387*3fb2c90bSMilanka Ringwald memset(sdp_avdtp_source_service_buffer, 0, sizeof(sdp_avdtp_source_service_buffer)); 388*3fb2c90bSMilanka Ringwald a2dp_source_create_sdp_record(sdp_avdtp_source_service_buffer, 0x10002, 1, NULL, NULL); 389*3fb2c90bSMilanka Ringwald sdp_register_service(sdp_avdtp_source_service_buffer); 390*3fb2c90bSMilanka Ringwald 391*3fb2c90bSMilanka Ringwald gap_set_local_name(device_name); 392*3fb2c90bSMilanka Ringwald gap_discoverable_control(1); 393*3fb2c90bSMilanka Ringwald gap_set_class_of_device(0x200408); 394*3fb2c90bSMilanka Ringwald 395*3fb2c90bSMilanka Ringwald hxcmod_initialized = hxcmod_init(&mod_context); 396*3fb2c90bSMilanka Ringwald if (hxcmod_initialized){ 397*3fb2c90bSMilanka Ringwald hxcmod_setcfg(&mod_context, A2DP_SAMPLE_RATE, 16, 1, 1, 1); 398*3fb2c90bSMilanka Ringwald hxcmod_load(&mod_context, (void *) &mod_data, mod_len); 399*3fb2c90bSMilanka Ringwald printf("loaded mod '%s', size %u\n", mod_name, mod_len); 400*3fb2c90bSMilanka Ringwald } 401*3fb2c90bSMilanka Ringwald 402*3fb2c90bSMilanka Ringwald // turn on! 403*3fb2c90bSMilanka Ringwald hci_power_control(HCI_POWER_ON); 404*3fb2c90bSMilanka Ringwald 405*3fb2c90bSMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 406*3fb2c90bSMilanka Ringwald btstack_stdin_setup(stdin_process); 407*3fb2c90bSMilanka Ringwald #endif 408*3fb2c90bSMilanka Ringwald return 0; 409*3fb2c90bSMilanka Ringwald } 410