Merge branch 'avdtp-source2' into develop

This commit is contained in:
Milanka Ringwald 2017-05-19 17:46:45 +02:00
commit 3e3fbf3df6
32 changed files with 5079 additions and 1202 deletions

1289
3rd-party/hxcmod-player/hxcmod.c vendored Normal file

File diff suppressed because it is too large Load Diff

215
3rd-party/hxcmod-player/hxcmod.h vendored Normal file
View File

@ -0,0 +1,215 @@
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0--1--1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
// File : hxcmod.h
// Contains: a tiny mod player
//
// Written by: Jean François DEL NERO
//
// Change History (most recent first):
///////////////////////////////////////////////////////////////////////////////////
#ifndef MODPLAY_DEF
#define MODPLAY_DEF
// Basic type
typedef unsigned char muchar;
typedef unsigned short muint;
typedef short mint;
typedef unsigned long mulong;
#define NUMMAXCHANNELS 32
#define MAXNOTES 12*12
#define SAMPLE_RATE 44100
//
// MOD file structures
//
#pragma pack(1)
typedef struct {
muchar name[22];
muint length;
muchar finetune;
muchar volume;
muint reppnt;
muint replen;
} sample;
typedef struct {
muchar sampperiod;
muchar period;
muchar sampeffect;
muchar effect;
} note;
typedef struct {
muchar title[20];
sample samples[31];
muchar length;
muchar protracker;
muchar patterntable[128];
muchar signature[4];
muchar speed;
} module;
#pragma pack()
//
// HxCMod Internal structures
//
typedef struct {
char * sampdata;
muint sampnum;
muint length;
muint reppnt;
muint replen;
mulong samppos;
muint period;
muchar volume;
mulong ticks;
muchar effect;
muchar parameffect;
muint effect_code;
mint decalperiod;
mint portaspeed;
mint portaperiod;
mint vibraperiod;
mint Arpperiods[3];
muchar ArpIndex;
mint oldk;
muchar volumeslide;
muchar vibraparam;
muchar vibrapointeur;
muchar finetune;
muchar cut_param;
muint patternloopcnt;
muint patternloopstartpoint;
} channel;
typedef struct {
module song;
char * sampledata[31];
note * patterndata[128];
mulong playrate;
muint tablepos;
muint patternpos;
muint patterndelay;
muint jump_loop_effect;
muchar bpm;
mulong patternticks;
mulong patterntickse;
mulong patternticksaim;
mulong sampleticksconst;
mulong samplenb;
channel channels[NUMMAXCHANNELS];
muint number_of_channels;
muint fullperiod[MAXNOTES * 8];
muint mod_loaded;
mint last_r_sample;
mint last_l_sample;
mint stereo;
mint stereo_separation;
mint bits;
mint filter;
} modcontext;
//
// Player states structures
//
typedef struct track_state_
{
unsigned char instrument_number;
unsigned short cur_period;
unsigned char cur_volume;
unsigned short cur_effect;
unsigned short cur_parameffect;
}track_state;
typedef struct tracker_state_
{
int number_of_tracks;
int bpm;
int speed;
int cur_pattern;
int cur_pattern_pos;
int cur_pattern_table_pos;
unsigned int buf_index;
track_state tracks[32];
}tracker_state;
typedef struct tracker_state_instrument_
{
char name[22];
int active;
}tracker_state_instrument;
typedef struct tracker_buffer_state_
{
int nb_max_of_state;
int nb_of_state;
int cur_rd_index;
int sample_step;
char name[64];
tracker_state_instrument instruments[31];
tracker_state * track_state_buf;
}tracker_buffer_state;
///////////////////////////////////////////////////////////////////////////////////
// HxCMOD Core API:
// -------------------------------------------
// int hxcmod_init(modcontext * modctx)
//
// - Initialize the modcontext buffer. Must be called before doing anything else.
// Return 1 if success. 0 in case of error.
// -------------------------------------------
// int hxcmod_load( modcontext * modctx, void * mod_data, int mod_data_size )
//
// - "Load" a MOD from memory (from "mod_data" with size "mod_data_size").
// Return 1 if success. 0 in case of error.
// -------------------------------------------
// void hxcmod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, unsigned long nbsample, tracker_buffer_state * trkbuf )
//
// - Generate and return the next samples chunk to outbuffer.
// nbsample specify the number of stereo 16bits samples you want.
// The output format is signed 44100Hz 16-bit Stereo PCM samples.
// The output buffer size in byte must be equal to ( nbsample * 2 * 2 ).
// The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 is unused.
// -------------------------------------------
// void hxcmod_unload( modcontext * modctx )
// - "Unload" / clear the player status.
// -------------------------------------------
///////////////////////////////////////////////////////////////////////////////////
int hxcmod_init( modcontext * modctx );
int hxcmod_setcfg( modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
int hxcmod_load( modcontext * modctx, void * mod_data, int mod_data_size );
void hxcmod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, unsigned long nbsample, tracker_buffer_state * trkbuf );
void hxcmod_unload( modcontext * modctx );
#endif

3
3rd-party/hxcmod-player/mods/mod.h vendored Normal file
View File

@ -0,0 +1,3 @@
extern unsigned char mod_data[];
extern unsigned int mod_len;
extern const char * mod_name;

View File

@ -0,0 +1,641 @@
#include "mod.h"
unsigned char mod_data[] = {
0x64, 0x65, 0x63, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20,
0x64, 0x69, 0x73, 0x65, 0x61, 0x73, 0x65, 0x00, 0x62, 0x79, 0x20, 0x6e,
0x61, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x40, 0x00, 0x08,
0x00, 0x40, 0x74, 0x61, 0x6e, 0x78, 0x7a, 0x20, 0x74, 0x6f, 0x20, 0x61,
0x73, 0x74, 0x72, 0x6f, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x00,
0x02, 0x22, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6c, 0x2d,
0x74, 0x72, 0x69, 0x63, 0x6b, 0x20, 0x26, 0x20, 0x64, 0x72, 0x75, 0x6d,
0x20, 0x73, 0x6d, 0x70, 0x73, 0x00, 0x00, 0x48, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x69, 0x27, 0x64, 0x20, 0x74, 0x65, 0x6c, 0x6c, 0x20, 0x79,
0x6f, 0x75, 0x20, 0x79, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x61, 0x00,
0x00, 0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6f, 0x6f, 0x6c,
0x20, 0x64, 0x75, 0x64, 0x65, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x79,
0x6f, 0x75, 0x20, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x6b, 0x6e, 0x6f, 0x77,
0x20, 0x74, 0x68, 0x61, 0x74, 0x21, 0x20, 0x68, 0x65, 0x68, 0x65, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6f, 0x20, 0x6d,
0x79, 0x20, 0x70, 0x61, 0x6c, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x66, 0x72,
0x65, 0x65, 0x73, 0x74, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3a, 0x20, 0x77, 0x68, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20,
0x66, 0x23, 0x63, 0x6b, 0x20, 0x77, 0x61, 0x73, 0x6e, 0x27, 0x74, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6c, 0x69, 0x73, 0x74, 0x3f, 0x21, 0x3f, 0x20, 0x69, 0x74,
0x27, 0x73, 0x20, 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x3a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x79, 0x6f, 0x75, 0x20, 0x69, 0x6c, 0x6c, 0x69, 0x74, 0x65,
0x72, 0x61, 0x74, 0x65, 0x20, 0x73, 0x68, 0x69, 0x74, 0x73, 0x21, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6f, 0x20, 0x6d,
0x79, 0x20, 0x70, 0x61, 0x6c, 0x20, 0x6d, 0x69, 0x63, 0x6b, 0x2d, 0x65,
0x79, 0x3a, 0x6d, 0x69, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x62, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x61, 0x69,
0x74, 0x20, 0x75, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x61, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x38, 0x30, 0x30,
0x20, 0x64, 0x75, 0x64, 0x6f, 0x21, 0x20, 0x63, 0x79, 0x61, 0x20, 0x6c,
0x38, 0x65, 0x72, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x67, 0x72, 0x65, 0x65, 0x74, 0x73, 0x20, 0x66, 0x6c, 0x65,
0x63, 0x6b, 0x65, 0x72, 0x20, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x66, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x20, 0x66,
0x61, 0x74, 0x20, 0x61, 0x73, 0x73, 0x20, 0x28, 0x72, 0x61, 0x63, 0x65,
0x6b, 0x61, 0x6b, 0x29, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6d, 0x69, 0x71, 0x2c, 0x70, 0x61, 0x74, 0x2c, 0x73, 0x6f,
0x62, 0x2c, 0x61, 0x73, 0x74, 0x72, 0x6f, 0x2c, 0x6b, 0x68, 0x64, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x63, 0x6c, 0x61,
0x78, 0x6f, 0x6e, 0x28, 0x66, 0x75, 0x6e, 0x6e, 0x79, 0x20, 0x6e, 0x61,
0x6d, 0x65, 0x29, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x73, 0x79, 0x6e, 0x63, 0x2c, 0x74, 0x63, 0x62, 0x2c, 0x74,
0x73, 0x6c, 0x2c, 0x72, 0x65, 0x62, 0x65, 0x6c, 0x73, 0x2c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x6a, 0x69, 0x6d,
0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x6e, 0x75,
0x72, 0x73, 0x65, 0x72, 0x79, 0x20, 0x20, 0x73, 0x79, 0x6e, 0x64, 0x69,
0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x03, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4d, 0x2e, 0x4b, 0x2e, 0x02, 0x3a, 0x3e, 0x94, 0x01, 0xe0, 0x46, 0x05,
0x02, 0xd0, 0x4c, 0x06, 0x01, 0xac, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00,
0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x46, 0x05,
0x01, 0xfc, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94,
0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x20, 0x02, 0x3a, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x93, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x14, 0x00,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3,
0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x46, 0x05,
0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x3f, 0x08, 0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x68, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00, 0x02, 0x3a, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3,
0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x02, 0x3a, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3,
0x00, 0xb4, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x20, 0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x93, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x14, 0x00, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x46, 0x05,
0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0x3a, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x00, 0x00, 0x2c, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x1e, 0xff,
0x01, 0xac, 0x2e, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08,
0x00, 0x00, 0x04, 0x81, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x82,
0x00, 0x00, 0x0f, 0x08, 0x01, 0xe0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x01, 0xc5, 0x16, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x3a, 0x3e, 0x94, 0x02, 0xd0, 0x46, 0x05, 0x00, 0x00, 0x4c, 0x06,
0x01, 0xac, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00, 0x02, 0x80, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0xfa, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x03, 0x58, 0x46, 0x05,
0x02, 0xfa, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0xac, 0x16, 0x05, 0x03, 0x58, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0xd0, 0x46, 0x05, 0x03, 0x58, 0x0e, 0xd3,
0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0xfa, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x00, 0xd6, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x03, 0x58, 0x46, 0x05,
0x02, 0xfa, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x80, 0x46, 0x05, 0x03, 0x58, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x20, 0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0xac, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x93, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xd6, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x14, 0x00, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05,
0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x01, 0xfc, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x3a, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x80, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0x3a, 0x46, 0x05,
0x02, 0xd0, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x3f, 0x08,
0x01, 0x68, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x68, 0x14, 0x00,
0x00, 0x71, 0x20, 0x00, 0x01, 0x7d, 0x46, 0x05, 0x01, 0x68, 0x0e, 0xd3,
0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xac, 0x46, 0x05,
0x01, 0x7d, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0x7d, 0x46, 0x05, 0x01, 0xac, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x94, 0x01, 0xac, 0x46, 0x05, 0x01, 0x7d, 0x0e, 0xd3,
0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05,
0x01, 0xac, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xac, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x01, 0xe0, 0x46, 0x05, 0x01, 0xac, 0x0e, 0xd3,
0x00, 0xb4, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xfc, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x01, 0xe0, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3, 0x00, 0xb4, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3,
0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x20,
0x02, 0x80, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x00, 0xb4, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x01, 0x68, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x68, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x93,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3, 0x00, 0xb4, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x40, 0x14, 0x00, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x01, 0xe0, 0x0e, 0xd3, 0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xfc, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xd0, 0x46, 0x05, 0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x80, 0x0e, 0xd3, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0xe0, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x3a, 0x46, 0x05, 0x01, 0xe0, 0x0e, 0xd3,
0x00, 0xa0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x80, 0x46, 0x05, 0x01, 0xfc, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x3a, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xd0, 0x46, 0x05,
0x02, 0x3a, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x80, 0x46, 0x05, 0x02, 0xd0, 0x0e, 0xd3, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x94, 0x02, 0xd0, 0x46, 0x05, 0x02, 0x80, 0x0e, 0xd3,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x3e, 0x94, 0x03, 0x58, 0x41, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x01, 0x7d, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00,
0x02, 0xfa, 0x44, 0x82, 0x00, 0x00, 0x4c, 0x10, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x03, 0x58, 0x01, 0x0e,
0x01, 0x7d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x01,
0x02, 0xfa, 0x04, 0x82, 0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94,
0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x06, 0x01,
0x01, 0x7d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x06, 0x10,
0x00, 0x00, 0x04, 0x00, 0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x06, 0x01, 0x00, 0xbe, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x06, 0x10,
0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x10, 0x01, 0x7d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x10,
0x01, 0x7d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x20, 0x01, 0xfc, 0x43, 0x22,
0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x03, 0x22, 0x00, 0x00, 0x04, 0x00, 0x01, 0x7d, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x01, 0xfc, 0x03, 0x22,
0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x93, 0x00, 0x00, 0x06, 0x03,
0x00, 0x00, 0x03, 0x22, 0x00, 0xbe, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0x3a, 0x43, 0x22, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x14, 0x00,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x03, 0x22, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x02, 0x3a, 0x03, 0x22, 0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x22, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xa6, 0x43, 0x20,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x03, 0x58, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0xfa, 0x43, 0x20, 0x02, 0xa6, 0x03, 0x20,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00,
0x03, 0x58, 0x03, 0x20, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x02, 0xfa, 0x03, 0x20, 0x00, 0x8f, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0xfa, 0x43, 0x20,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94,
0x02, 0xa6, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x02, 0x3a, 0x3f, 0x08, 0x02, 0x80, 0x43, 0x20, 0x02, 0xfa, 0x03, 0x20,
0x01, 0x40, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x00, 0x06, 0x02,
0x02, 0xa6, 0x03, 0x20, 0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x01, 0xfc, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x04, 0x00,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x02, 0x80, 0x43, 0x20,
0x01, 0xfc, 0x03, 0x20, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x04, 0x00, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0xa6, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x06, 0x01, 0x02, 0xa6, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x04, 0x00,
0x00, 0xa0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x02, 0x3a, 0x43, 0x20,
0x00, 0x00, 0x04, 0x00, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x02, 0x80, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x20, 0x02, 0xfa, 0x43, 0x20, 0x02, 0x3a, 0x03, 0x20,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0xa6, 0x43, 0x20,
0x02, 0x80, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0xfa, 0x43, 0x20, 0x02, 0xfa, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x93, 0x02, 0xa6, 0x43, 0x20, 0x02, 0xa6, 0x03, 0x20,
0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x02, 0x80, 0x43, 0x20,
0x02, 0xfa, 0x03, 0x20, 0x01, 0x1d, 0x14, 0x00, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x02, 0xa6, 0x03, 0x20, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x02, 0x80, 0x03, 0x20,
0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x06, 0x0a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x01, 0xfc, 0x43, 0x08, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x03, 0x08,
0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x03, 0x10, 0x01, 0xfc, 0x03, 0x08, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x03, 0x08,
0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x03, 0x10, 0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x10, 0x01, 0x1d, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x3e, 0x94,
0x03, 0x58, 0x41, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7d, 0x14, 0x00,
0x00, 0x71, 0x20, 0x00, 0x02, 0xfa, 0x44, 0x82, 0x00, 0x00, 0x4c, 0x10,
0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x03, 0x58, 0x01, 0x0e, 0x01, 0x7d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x06, 0x01, 0x02, 0xfa, 0x04, 0x82, 0x01, 0x7d, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x94, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x04, 0x00,
0x00, 0xbe, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x01,
0x00, 0x00, 0x06, 0x01, 0x01, 0x7d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x04, 0x00, 0x01, 0x7d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x06, 0x01,
0x00, 0xbe, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x10,
0x00, 0x00, 0x06, 0x10, 0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x10,
0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x0c, 0x10, 0x01, 0x7d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x20,
0x01, 0xfc, 0x43, 0x22, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x03, 0x22, 0x00, 0x00, 0x04, 0x00,
0x01, 0x7d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x01, 0xfc, 0x03, 0x22, 0x01, 0x7d, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x93,
0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x22, 0x00, 0xbe, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x02, 0x3a, 0x43, 0x22, 0x00, 0x00, 0x04, 0x00,
0x01, 0x1d, 0x14, 0x00, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x03, 0x22,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x04, 0x00, 0x02, 0x3a, 0x03, 0x22, 0x01, 0x1d, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x22,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x43, 0x20,
0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xa6, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x03, 0x58, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x02, 0xfa, 0x43, 0x20,
0x02, 0xa6, 0x03, 0x20, 0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x01, 0xfc, 0x43, 0x30, 0x03, 0x58, 0x03, 0x20, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00, 0x02, 0xfa, 0x03, 0x20,
0x00, 0x8f, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x01, 0xfc, 0x03, 0x30, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x03,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0xfa, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2e, 0x94, 0x02, 0xa6, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x3f, 0x08, 0x02, 0x80, 0x43, 0x20,
0x02, 0xfa, 0x03, 0x20, 0x01, 0x40, 0x14, 0x00, 0x00, 0x71, 0x20, 0x00,
0x00, 0x00, 0x06, 0x02, 0x02, 0xa6, 0x03, 0x20, 0x00, 0x00, 0x06, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x01, 0xac, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20,
0x01, 0x40, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x02,
0x00, 0x00, 0x04, 0x00, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x94,
0x01, 0x7d, 0x43, 0x20, 0x01, 0xac, 0x03, 0x20, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x04, 0x00,
0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x01, 0xfc, 0x43, 0x20,
0x01, 0x7d, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xa0, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0xfc, 0x03, 0x20,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x06, 0x01,
0x00, 0x00, 0x04, 0x00, 0x00, 0xa0, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x02, 0x3a, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00, 0x01, 0x40, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x02, 0x80, 0x43, 0x20, 0x00, 0x00, 0x04, 0x00,
0x01, 0x40, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x20, 0x02, 0xfa, 0x43, 0x20,
0x02, 0x3a, 0x03, 0x20, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0xa6, 0x43, 0x20, 0x02, 0x80, 0x03, 0x20, 0x01, 0x40, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x02, 0xfa, 0x43, 0x20, 0x02, 0xfa, 0x03, 0x20,
0x01, 0x40, 0x16, 0x0a, 0x00, 0x71, 0x2e, 0x93, 0x02, 0xa6, 0x43, 0x20,
0x02, 0xa6, 0x03, 0x20, 0x00, 0xa0, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x02, 0x3a, 0x43, 0x20, 0x02, 0xfa, 0x03, 0x20, 0x01, 0x1d, 0x14, 0x00,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00, 0x02, 0xa6, 0x03, 0x20,
0x00, 0x00, 0x06, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x02, 0x3a, 0x03, 0x20, 0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a,
0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x06, 0x0a, 0x00, 0x00, 0x04, 0x00,
0x00, 0x8f, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00, 0x01, 0xfc, 0x43, 0x08,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10,
0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x03, 0x10, 0x01, 0xfc, 0x03, 0x08,
0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2c, 0x10, 0x00, 0x00, 0x03, 0x10,
0x00, 0x00, 0x03, 0x08, 0x01, 0x1d, 0x16, 0x0a, 0x02, 0x3a, 0x30, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x10, 0x00, 0x8f, 0x16, 0x0a,
0x02, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x10,
0x01, 0x1d, 0x16, 0x0a, 0x01, 0xac, 0x2c, 0x40, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x01, 0x1d, 0x16, 0x0a, 0x00, 0x71, 0x2b, 0x01,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x8f, 0x16, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3b, 0xc4, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x1f, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xe9, 0xe9, 0xe9, 0xe9,
0xe9, 0xe9, 0xe9, 0xe9, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb,
0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xc4, 0xc4, 0xc4, 0xc4,
0xc4, 0xc4, 0xc4, 0xc4, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb7,
0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xbb, 0xbb, 0xbb, 0xbb,
0xbb, 0xbb, 0xbb, 0xbb, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0x00, 0x00, 0x66, 0x4e, 0x66, 0x56, 0x48, 0x2a, 0x80, 0x1c, 0xff, 0x80,
0x80, 0x80, 0x80, 0x80, 0x8d, 0xac, 0xf8, 0x2f, 0x7f, 0x7e, 0x7e, 0x7e,
0x7e, 0x7e, 0x5d, 0xbe, 0x72, 0xf6, 0x02, 0x80, 0xda, 0xbb, 0x9f, 0x5a,
0x60, 0x3d, 0x2b, 0x3b, 0x2c, 0x1d, 0x0b, 0xc3, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x88, 0x98, 0xc8, 0xd5, 0xcc, 0x1a, 0xc9, 0x0d, 0xe3, 0x00,
0x3e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x67, 0x56,
0x07, 0x47, 0x06, 0xda, 0xfb, 0xc8, 0xa9, 0x80, 0x99, 0x80, 0x80, 0x83,
0x82, 0x80, 0x80, 0x82, 0x88, 0xaa, 0xb3, 0xc7, 0xf0, 0x2a, 0x43, 0x4e,
0x7f, 0x41, 0x7f, 0x22, 0x7f, 0x7e, 0x7e, 0x68, 0x6c, 0x7f, 0x71, 0x11,
0x1e, 0x2e, 0x05, 0x21, 0x15, 0x07, 0x24, 0x1e, 0x38, 0x18, 0xfc, 0xdd,
0xc6, 0xd2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa1, 0x80, 0x8a,
0xcb, 0xad, 0xda, 0xde, 0xdf, 0x0a, 0x18, 0x19, 0x7e, 0x5b, 0x7f, 0x71,
0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x64, 0x61, 0x20, 0x60, 0x13, 0x1d, 0x0e,
0xe4, 0xb8, 0xac, 0xb2, 0x80, 0xab, 0x80, 0x85, 0x80, 0x80, 0xae, 0xcd,
0xba, 0xfa, 0xc8, 0xce, 0xd3, 0x46, 0xe7, 0x0a, 0xe7, 0xee, 0xfe, 0x10,
0xf7, 0x4e, 0x49, 0x5d, 0x68, 0x51, 0x7f, 0x6c, 0x7f, 0x7e, 0x7e, 0x62,
0x33, 0x40, 0x4c, 0x12, 0x2a, 0x05, 0x17, 0xeb, 0xf9, 0xc4, 0x80, 0x9f,
0xa7, 0x80, 0x80, 0xee, 0x91, 0x9a, 0xa3, 0xd4, 0x83, 0xac, 0xca, 0xdf,
0xbc, 0xb2, 0xe3, 0xd9, 0xfc, 0x50, 0x09, 0x54, 0x4e, 0x7f, 0x62, 0x7f,
0x62, 0x7f, 0x7e, 0x7e, 0x4c, 0x65, 0x5d, 0x35, 0x2b, 0xff, 0x00, 0xec,
0xd1, 0xc3, 0xf1, 0xdf, 0xd1, 0x89, 0xbd, 0xb7, 0x93, 0x8f, 0xe8, 0x80,
0xd2, 0xca, 0xb0, 0xe0, 0xc6, 0x07, 0xd0, 0x01, 0x36, 0x28, 0x29, 0x62,
0x47, 0x3e, 0x65, 0x3a, 0x04, 0x52, 0x03, 0x3f, 0x34, 0x1f, 0x32, 0x58,
0x1b, 0xfd, 0x43, 0x0c, 0x2f, 0x09, 0xfe, 0x1d, 0xea, 0xfd, 0x07, 0xb2,
0x2d, 0xad, 0xb3, 0xa2, 0xc5, 0xa5, 0xab, 0xa5, 0xb2, 0x8d, 0xbf, 0x91,
0xc1, 0xcb, 0xc1, 0xeb, 0xe4, 0x0f, 0x21, 0x19, 0x74, 0x17, 0x4f, 0x35,
0x47, 0x7f, 0x3a, 0x67, 0x75, 0x76, 0x3d, 0x57, 0x4f, 0x36, 0x31, 0xfb,
0x00, 0xdb, 0xee, 0xd1, 0xf5, 0xda, 0xac, 0xdc, 0xba, 0xb7, 0xe6, 0xba,
0xc6, 0xa6, 0xcf, 0xd3, 0xe2, 0xd0, 0xce, 0xce, 0x07, 0xbb, 0xeb, 0x00,
0x07, 0x14, 0x1d, 0x0e, 0x26, 0x17, 0x2a, 0x22, 0x60, 0x36, 0x71, 0x68,
0x4f, 0x30, 0x55, 0x15, 0x2a, 0x52, 0x25, 0x1a, 0x25, 0x04, 0x09, 0xc2,
0xee, 0xc2, 0xd5, 0xea, 0xe4, 0xb4, 0xeb, 0xc2, 0xc3, 0xca, 0xa5, 0xd4,
0x9c, 0xd7, 0xe2, 0xb6, 0x05, 0xc7, 0xda, 0xdb, 0x0d, 0xe5, 0x20, 0x23,
0x5b, 0x26, 0x58, 0x3f, 0x4e, 0x47, 0x41, 0x59, 0x49, 0x5c, 0x52, 0x1f,
0x61, 0x28, 0x1c, 0x0e, 0xf7, 0xed, 0xe8, 0xd8, 0xf2, 0xaf, 0xf4, 0xc3,
0xc5, 0xbe, 0xc9, 0xc2, 0xbe, 0xb5, 0xc7, 0xbe, 0xce, 0xeb, 0xea, 0x09,
0xdf, 0x02, 0x12, 0x07, 0xf7, 0x24, 0x01, 0x08, 0x28, 0x18, 0x3e, 0x49,
0x44, 0x63, 0x41, 0x2c, 0x46, 0x1f, 0x56, 0x14, 0x18, 0x0f, 0xf6, 0x06,
0xdf, 0x00, 0xd0, 0xbd, 0xeb, 0x04, 0xd5, 0xee, 0xe6, 0xdc, 0xd9, 0xbc,
0xdd, 0xbe, 0xfc, 0xb7, 0xe7, 0xd6, 0xd6, 0xd9, 0xff, 0xfd, 0xce, 0xff,
0xec, 0x02, 0x1d, 0x22, 0x20, 0x20, 0x45, 0x49, 0x60, 0x3f, 0x41, 0x4b,
0x34, 0x1a, 0x2f, 0x2a, 0x18, 0xfb, 0x13, 0xf2, 0xdf, 0xd0, 0xe3, 0xdb,
0xdb, 0x06, 0x17, 0xf1, 0xed, 0xee, 0xdd, 0xde, 0xed, 0xdb, 0xd7, 0xe7,
0xb9, 0x11, 0xdb, 0xe7, 0x0a, 0xe7, 0xe9, 0xd4, 0x06, 0x0c, 0x29, 0xfb,
0x1f, 0x0b, 0x33, 0x20, 0xfe, 0x2e, 0x2b, 0x14, 0x16, 0x2a, 0x2c, 0x28,
0x3a, 0x1d, 0x1b, 0x24, 0x03, 0x31, 0xe1, 0x06, 0xcd, 0xfd, 0xd1, 0xd5,
0xf5, 0xda, 0xe5, 0xc8, 0xcc, 0xd1, 0xee, 0xc7, 0xe7, 0xda, 0xcf, 0xf6,
0xcf, 0xfb, 0xe8, 0x26, 0xec, 0x0f, 0xf8, 0x1a, 0x24, 0x37, 0x10, 0x18,
0x25, 0x19, 0x20, 0x39, 0x0b, 0x19, 0x1b, 0x1c, 0x10, 0x17, 0x07, 0x21,
0x12, 0x03, 0x21, 0xf3, 0x16, 0xec, 0xf5, 0xe6, 0xe8, 0xd6, 0xca, 0xe4,
0xf2, 0xd5, 0xe7, 0xef, 0xf9, 0xd3, 0xf9, 0xe3, 0xe8, 0xf0, 0xe5, 0xd7,
0xfd, 0x08, 0xf3, 0x14, 0x0b, 0x0d, 0x19, 0x22, 0x0e, 0x07, 0x11, 0x1f,
0x12, 0x34, 0x05, 0x2b, 0x11, 0x2c, 0x26, 0x1f, 0x1a, 0x1a, 0x20, 0xf9,
0x16, 0xe4, 0xec, 0xe9, 0xdf, 0xe0, 0xed, 0xeb, 0xc5, 0xcc, 0xd3, 0xdd,
0xdb, 0xf0, 0x03, 0xf8, 0xdd, 0xee, 0x10, 0xfd, 0x02, 0xf6, 0xff, 0xf3,
0x1a, 0x20, 0x05, 0x20, 0x21, 0x1f, 0x1a, 0x13, 0xfd, 0x15, 0x01, 0x13,
0x0e, 0xeb, 0x0e, 0x0c, 0x0c, 0x21, 0xed, 0x23, 0xfc, 0x00, 0xe5, 0xe7,
0xee, 0xdc, 0xe6, 0xe3, 0xe8, 0xfd, 0xf9, 0x0d, 0x0a, 0x07, 0x0f, 0x07,
0xfe, 0x12, 0xe5, 0xf0, 0xef, 0xed, 0xe2, 0xe5, 0xea, 0xe7, 0xf3, 0xfe,
0x0c, 0x0b, 0x11, 0x18, 0x21, 0x20, 0x20, 0x0b, 0x1b, 0x19, 0x19, 0x0d,
0x0d, 0xf8, 0x01, 0x0b, 0x0a, 0x0c, 0x0a, 0xff, 0x04, 0x0c, 0xec, 0xef,
0xfb, 0xdb, 0xe7, 0xd6, 0xd3, 0xf3, 0xd9, 0xf9, 0xdb, 0xe8, 0xf6, 0xf3,
0xf3, 0x11, 0xf5, 0x0e, 0xff, 0x10, 0x03, 0x19, 0x0e, 0x21, 0x0f, 0x1e,
0x12, 0x20, 0x13, 0x1b, 0x15, 0xf5, 0xfd, 0x04, 0xfe, 0xf7, 0xf1, 0xff,
0xed, 0xff, 0x10, 0xf7, 0x02, 0x16, 0xf1, 0x03, 0x03, 0xf7, 0x05, 0x06,
0x07, 0x06, 0xed, 0xf7, 0x00, 0x05, 0x13, 0xfb, 0x01, 0x10, 0xea, 0xfd,
0xf8, 0xe4, 0xef, 0xe6, 0xef, 0xf6, 0x11, 0x00, 0x00, 0x02, 0x00, 0x06,
0x10, 0xfd, 0x0a, 0x0d, 0x00, 0xeb, 0x09, 0x03, 0x09, 0x14, 0x12, 0x05,
0xfc, 0x0e, 0x16, 0x1a, 0x18, 0x01, 0x17, 0xfe, 0xf2, 0xf5, 0xea, 0xe7,
0xdb, 0xea, 0xea, 0xf7, 0xf0, 0xf9, 0xf9, 0x01, 0x01, 0x0b, 0xf9, 0x07,
0xfd, 0xfd, 0x07, 0xf9, 0xfb, 0x02, 0x12, 0x04, 0x04, 0x19, 0x10, 0x09,
0x1a, 0x0b, 0xf8, 0x12, 0x03, 0xec, 0x1a, 0xee, 0xfa, 0x13, 0x07, 0x0e,
0x05, 0x05, 0x14, 0xf6, 0xfd, 0xf8, 0xdf, 0xf8, 0xf3, 0xe4, 0xfe, 0xfa,
0x02, 0x13, 0xf9, 0x0c, 0xf9, 0x10, 0xf7, 0x0d, 0x03, 0x03, 0xf3, 0x03,
0x00, 0xeb, 0x03, 0xe3, 0xe5, 0xed, 0xed, 0x0d, 0x07, 0x08, 0x23, 0x21,
0x0b, 0x0a, 0x1b, 0x0b, 0x10, 0x03, 0x0b, 0x0a, 0xef, 0xf6, 0x06, 0xfc,
0xec, 0xe2, 0x00, 0xf9, 0x09, 0x00, 0x06, 0xf9, 0xf9, 0xf9, 0x01, 0xfa,
0x01, 0x05, 0xfa, 0x06, 0x05, 0x10, 0x10, 0x06, 0x06, 0x01, 0x01, 0x06,
0x00, 0x0d, 0x10, 0x02, 0xfc, 0xff, 0x05, 0xfe, 0x03, 0xf2, 0xf8, 0xee,
0x00, 0xe7, 0x00, 0xf1, 0xf4, 0xf7, 0xf5, 0xfa, 0x01, 0x0f, 0x0a, 0x11,
0x0b, 0x0e, 0x0d, 0x13, 0x14, 0x0a, 0x0a, 0x0a, 0x00, 0x07, 0xfc, 0x03,
0x00, 0xff, 0xf5, 0xf6, 0xff, 0xf8, 0xfa, 0xfd, 0xef, 0xf6, 0xf7, 0xf8,
0xf5, 0xf6, 0x01, 0xf9, 0xfc, 0xf4, 0x03, 0xfe, 0x01, 0x00, 0x02, 0xfc,
0xfd, 0x07, 0x0a, 0x02, 0x05, 0x06, 0x09, 0x10, 0x05, 0x0b, 0x14, 0x03,
0x06, 0x06, 0x06, 0x09, 0x05, 0xfe, 0xfe, 0xfd, 0xf6, 0xf8, 0xf9, 0xf9,
0xfa, 0xfb, 0xfb, 0xfd, 0x01, 0xfa, 0x00, 0x00, 0xf9, 0xfa, 0xfe, 0xff,
0xfe, 0xfe, 0x01, 0xff, 0xfe, 0x00, 0x01, 0x00, 0x01, 0x05, 0x00, 0x04,
0x08, 0x03, 0x09, 0x03, 0x06, 0x01, 0x09, 0x07, 0x07, 0x03, 0x02, 0xfe,
0xff, 0xfe, 0xfe, 0xf9, 0xfa, 0xfa, 0xfd, 0xfb, 0xfc, 0xfd, 0xff, 0xfd,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x37, 0x2a, 0x15, 0x16, 0xfa, 0xd6, 0xd6, 0xd8, 0xbc,
0xa3, 0x91, 0x85, 0x82, 0x82, 0x84, 0x88, 0x94, 0xaa, 0xc3, 0xe0, 0xfc,
0x14, 0x2e, 0x49, 0x5e, 0x6c, 0x74, 0x78, 0x74, 0x6c, 0x62, 0x56, 0x45,
0x2e, 0x14, 0xfc, 0xe4, 0xc9, 0xae, 0x93, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8d, 0x9e, 0xb4, 0xc9, 0xdf, 0xf3,
0x06, 0x19, 0x2e, 0x45, 0x5b, 0x70, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7c, 0x73, 0x69, 0x5a, 0x48, 0x33, 0x1f, 0x0a, 0xf6, 0xe1, 0xcd,
0xb7, 0xa2, 0x8c, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x85, 0x94, 0xa3, 0xae, 0xba, 0xc6, 0xd0, 0xdb, 0xe8, 0xf7,
0x02, 0x0c, 0x18, 0x25, 0x32, 0x3e, 0x46, 0x4a, 0x4c, 0x4f, 0x50, 0x4f,
0x4e, 0x49, 0x43, 0x3c, 0x36, 0x30, 0x28, 0x21, 0x1a, 0x13, 0x0c, 0x04,
0xff, 0xfa, 0xf6, 0xf2, 0xf1, 0xf1, 0xf0, 0xf1, 0xf3, 0xf6, 0xf8, 0x00,
0x00, 0xff, 0x99, 0x4e, 0x66, 0x56, 0x48, 0x2a, 0x80, 0x1c, 0xff, 0x80,
0x80, 0x80, 0x80, 0x00
};
unsigned int mod_len = 7600;
const char * mod_name = "nao-deceased by disease";

Binary file not shown.

119
3rd-party/hxcmod-player/readme.txt vendored Normal file
View File

@ -0,0 +1,119 @@
Local copy used for A2DP Source demo in BTstack.
Github repository: https://github.com/jfdelnero/HxCModPlayer
Thanks for providing this nice and compact implementation!
--------------------------------------------------------------------------------------
Original readme.txt
--------------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------//
//-----------H----H--X----X-----CCCCC----22222----0000-----0000------11----------//
//----------H----H----X-X-----C--------------2---0----0---0----0---1-1-----------//
//---------HHHHHH-----X------C----------22222---0----0---0----0-----1------------//
//--------H----H----X--X----C----------2-------0----0---0----0-----1-------------//
//-------H----H---X-----X---CCCCC-----222222----0000-----0000----1111------------//
//-------------------------------------------------------------------------------//
//----------------------------------------------------- http://hxc2001.free.fr --//
///////////////////////////////////////////////////////////////////////////////////
HxCMOD player
The HxCMOD player is a tiny music module player.
It currently supports the Noisetracker/Soundtracker/Protracker Module Format (*.mod)
The core (hxcmod.c/hxcmod.h) is designed to have the least external dependency.
So it should be usable on almost all OS and systems.
You can use the hxcmod.c / hxcmod.h files to add a mod replay support
to a demo/game/software.
You are free to do what you want with this code.
(A credit is always appreciated if you include it into your prod ;) )
The test program is into the win32 folder. Just drag and drop a mod on the main
window to load it. Linux & Mac OS X version it planned.
Please note that this core was "Emscriptened" successfully and is now working in
JavaScript with Android, Chrome, Firefox, Edge, Safari browsers and probably
with others browsers supporting the Web Audio API support.
You can test it at this address : http://hxc2001.free.fr/hxcmod/
A video demo of the native Mod player can be seen on youtube :
https://www.youtube.com/watch?v=MEU9FGZzjac
--------------------------------------------------------------------------------------
HxCMOD Core API
--------------------------------------------------------------------------------------
int hxcmod_init( modcontext * modctx )
- Initialize the modcontext buffer. Must be called before doing anything else.
Return 1 if success. 0 in case of error.
int hxcmod_setcfg( modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
- Configure the player :
samplerate specify the sample rate. (44100 by default).
bits specify the number of bits (16 bits only for the moment).
stereo - if non null, the stereo mode is selected (default)
stereo_separation - Left/Right channel separation.
filter - if non null, the filter is applied (default)
int hxcmod_load( modcontext * modctx, void * mod_data, int mod_data_size )
- "Load" a MOD from memory (from "mod_data" with size "mod_data_size").
Return 1 if success. 0 in case of error.
void hxcmod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, unsigned long nbsample, tracker_buffer_state * trkbuf )
- Generate and return the next samples chunk to outbuffer.
nbsample specify the number of stereo 16bits samples you want.
The output format is signed 44100Hz 16-bit Stereo PCM samples.
The output buffer size in byte must be equal to ( nbsample * 2 * 2 ).
The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 if unused.
void hxcmod_unload( modcontext * modctx )
- "Unload" / clear the player status.
--------------------------------------------------------------------------------------
Files on the repository
--------------------------------------------------------------------------------------
- hxcmod.c / hxcmod.h
The HxC core mod replay routines. These files don't have any dependency with others files
and can be used into other project.
- framegenerator.c / framegenerator.h
Generate a 640*480 framebuffer from the player status to be displayed in real-time.
(not needed by the core)
- win32/
The Windows test software.
(linux & Mac version planned)
- js_emscripten/
The Web browser/JavaScript version. (Build with Emscripten)
- packer/
Data compression utility. Used to embed one mod and some graphical stuff into the executable.
Not directly used by the core.
- data/
Some packed data files.
--------------------------------------------------------------------------------------
Jean-François DEL NERO (Jeff) / HxC2001
Email : jeanfrancoisdelnero <> free.fr
http://hxc2001.free.fr
11 July 2015

View File

@ -962,6 +962,7 @@ typedef uint8_t sm_key_t[16];
#define HCI_EVENT_GOEP_META 0xED
#define HCI_EVENT_PBAP_META 0xEE
#define HCI_EVENT_HID_META 0xEF
#define HCI_EVENT_A2DP_META 0xF0
// Potential other meta groups
// #define HCI_EVENT_BNEP_META 0xxx
@ -1258,26 +1259,29 @@ typedef uint8_t sm_key_t[16];
/** AVDTP Subevent */
/**
* @format 1H11
* @format 1H111
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param signal_identifier
* @param status 0 == OK
*/
#define AVDTP_SUBEVENT_SIGNALING_ACCEPT 0x01
/**
* @format 1H1
* @format 1H11
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param signal_identifier
*/
#define AVDTP_SUBEVENT_SIGNALING_REJECT 0x02
/**
* @format 1H1
* @format 1H11
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param signal_identifier
*/
#define AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT 0x03
@ -1285,7 +1289,7 @@ typedef uint8_t sm_key_t[16];
/**
* @format 1HB1
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param bd_addr
* @param status 0 == OK
*/
@ -1294,14 +1298,14 @@ typedef uint8_t sm_key_t[16];
/**
* @format 1H
* @param subevent_code
* @param con_handle
* @param avdtp_cid
*/
#define AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED 0x05
/**
* @format 1H1111
* @param subevent_code
* @param handle
* @param avdtp_cid
* @param seid 0x01 0x3E
* @param in_use 0-not in use, 1-in use
* @param media_type 0-audio, 1-video, 2-multimedia
@ -1310,9 +1314,11 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_SUBEVENT_SIGNALING_SEP_FOUND 0x06
/**
* @format 1H11111111
* @format 1H1111111111
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param acp_seid
* @param media_type
* @param sampling_frequency_bitmap
* @param channel_mode_bitmap
@ -1325,9 +1331,11 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY 0x07
/**
* @format 1H12LV
* @format 1H1112LV
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param acp_seid
* @param media_type
* @param media_codec_type
* @param media_codec_information_len
@ -1336,9 +1344,11 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY 0x08
/**
* @format 1H1121111111
* @format 1H111121111111
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param acp_seid
* @param reconfigure
* @param media_type
* @param sampling_frequency
@ -1353,9 +1363,11 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION 0x09
/**
* @format 1H112LV
* @format 1H11112LV
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param acp_seid
* @param reconfigure
* @param media_type
* @param media_codec_type
@ -1365,9 +1377,11 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION 0x0A
/**
* @format 1H1
* @format 1H111
* @param subevent_code
* @param con_handle
* @param avdtp_cid
* @param int_seid
* @param acp_seid
* @param status 0 == OK
*/
#define AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED 0x0B
@ -1375,12 +1389,64 @@ typedef uint8_t sm_key_t[16];
/**
* @format 1H
* @param subevent_code
* @param con_handle
* @param avdtp_cid
*/
#define AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED 0x0C
/**
* @format 1H12
* @param subevent_code
* @param avdtp_cid
* @param int_seid
* @param sequence_number
*/
#define AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 0x0D
/** A2DP Subevent */
/**
* @format 1H111
* @param subevent_code
* @param a2dp_cid
* @param local_seid
* @param remote_seid
* @param status
*/
#define A2DP_SUBEVENT_STREAM_ESTABLISHED 0x01
/**
* @format 1H1
* @param subevent_code
* @param a2dp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAM_START_ACCEPTED 0x02
/**
* @format 1H1
* @param subevent_code
* @param a2dp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAM_SUSPENDED 0x03
/**
* @format 1H1
* @param subevent_code
* @param avdtp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 0x04
/**
* @format 1H1
* @param subevent_code
* @param avdtp_cid
* @param local_seid
*/
#define A2DP_SUBEVENT_STREAM_RELEASED 0x05
/** AVRCP Subevent */
/**

View File

@ -85,6 +85,14 @@ static inline uint8_t hci_event_ancs_meta_get_subevent_code(const uint8_t * even
static inline uint8_t hci_event_avdtp_meta_get_subevent_code(const uint8_t * event){
return event[2];
}
/***
* @brief Get subevent code for a2dp event
* @param event packet
* @return subevent_code
*/
static inline uint8_t hci_event_a2dp_meta_get_subevent_code(const uint8_t * event){
return event[2];
}
/***
* @brief Get subevent code for avrcp event
* @param event packet
@ -3972,14 +3980,23 @@ static inline hci_con_handle_t ancs_subevent_client_disconnected_get_handle(cons
#endif
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_ACCEPT
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_accept_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_accept_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_ACCEPT
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_accept_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_ACCEPT
* @param event packet
@ -3987,7 +4004,7 @@ static inline hci_con_handle_t avdtp_subevent_signaling_accept_get_con_handle(co
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_accept_get_signal_identifier(const uint8_t * event){
return event[5];
return event[6];
}
/**
* @brief Get field status from event AVDTP_SUBEVENT_SIGNALING_ACCEPT
@ -3996,18 +4013,27 @@ static inline uint8_t avdtp_subevent_signaling_accept_get_signal_identifier(cons
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_accept_get_status(const uint8_t * event){
return event[6];
return event[7];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_REJECT
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_REJECT
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_reject_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_reject_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_REJECT
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_reject_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_REJECT
* @param event packet
@ -4015,18 +4041,27 @@ static inline hci_con_handle_t avdtp_subevent_signaling_reject_get_con_handle(co
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_reject_get_signal_identifier(const uint8_t * event){
return event[5];
return event[6];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_general_reject_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_general_reject_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_general_reject_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field signal_identifier from event AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT
* @param event packet
@ -4034,16 +4069,16 @@ static inline hci_con_handle_t avdtp_subevent_signaling_general_reject_get_con_h
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_general_reject_get_signal_identifier(const uint8_t * event){
return event[5];
return event[6];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_connection_established_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_connection_established_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
@ -4066,22 +4101,22 @@ static inline uint8_t avdtp_subevent_signaling_connection_established_get_status
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_connection_released_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_connection_released_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field handle from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_SEP_FOUND
* @param event packet
* @return handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_sep_found_get_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_sep_found_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
@ -4122,14 +4157,32 @@ static inline uint8_t avdtp_subevent_signaling_sep_found_get_sep_type(const uint
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_capability_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_capability_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field acp_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
* @param event packet
* @return acp_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_acp_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
* @param event packet
@ -4137,7 +4190,7 @@ static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_capabili
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_media_type(const uint8_t * event){
return event[5];
return event[7];
}
/**
* @brief Get field sampling_frequency_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4146,7 +4199,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_me
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(const uint8_t * event){
return event[6];
return event[8];
}
/**
* @brief Get field channel_mode_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4155,7 +4208,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_sa
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(const uint8_t * event){
return event[7];
return event[9];
}
/**
* @brief Get field block_length_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4164,7 +4217,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_ch
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(const uint8_t * event){
return event[8];
return event[10];
}
/**
* @brief Get field subbands_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4173,7 +4226,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_bl
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(const uint8_t * event){
return event[9];
return event[11];
}
/**
* @brief Get field allocation_method_bitmap from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4182,7 +4235,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_su
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(const uint8_t * event){
return event[10];
return event[12];
}
/**
* @brief Get field min_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4191,7 +4244,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_al
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(const uint8_t * event){
return event[11];
return event[13];
}
/**
* @brief Get field max_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
@ -4200,18 +4253,36 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_mi
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(const uint8_t * event){
return event[12];
return event[14];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_capability_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_capability_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field acp_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
* @param event packet
* @return acp_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_acp_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
* @param event packet
@ -4219,7 +4290,7 @@ static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_capabi
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_media_type(const uint8_t * event){
return event[5];
return event[7];
}
/**
* @brief Get field media_codec_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
@ -4228,7 +4299,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_other_capability_get_
* @note: btstack_type 2
*/
static inline uint16_t avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_type(const uint8_t * event){
return little_endian_read_16(event, 6);
return little_endian_read_16(event, 8);
}
/**
* @brief Get field media_codec_information_len from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
@ -4237,7 +4308,7 @@ static inline uint16_t avdtp_subevent_signaling_media_codec_other_capability_get
* @note: btstack_type L
*/
static inline int avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_information_len(const uint8_t * event){
return little_endian_read_16(event, 8);
return little_endian_read_16(event, 10);
}
/**
* @brief Get field media_codec_information from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
@ -4246,18 +4317,36 @@ static inline int avdtp_subevent_signaling_media_codec_other_capability_get_medi
* @note: btstack_type V
*/
static inline const uint8_t * avdtp_subevent_signaling_media_codec_other_capability_get_media_codec_information(const uint8_t * event){
return &event[10];
return &event[12];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field acp_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
* @param event packet
* @return acp_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_acp_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field reconfigure from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
* @param event packet
@ -4265,7 +4354,7 @@ static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_sbc_configur
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(const uint8_t * event){
return event[5];
return event[7];
}
/**
* @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4274,7 +4363,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_media_type(const uint8_t * event){
return event[6];
return event[8];
}
/**
* @brief Get field sampling_frequency from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4283,7 +4372,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 2
*/
static inline uint16_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(const uint8_t * event){
return little_endian_read_16(event, 7);
return little_endian_read_16(event, 9);
}
/**
* @brief Get field channel_mode from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4292,7 +4381,7 @@ static inline uint16_t avdtp_subevent_signaling_media_codec_sbc_configuration_ge
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(const uint8_t * event){
return event[9];
return event[11];
}
/**
* @brief Get field num_channels from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4301,7 +4390,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(const uint8_t * event){
return event[10];
return event[12];
}
/**
* @brief Get field block_length from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4310,7 +4399,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(const uint8_t * event){
return event[11];
return event[13];
}
/**
* @brief Get field subbands from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4319,7 +4408,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(const uint8_t * event){
return event[12];
return event[14];
}
/**
* @brief Get field allocation_method from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4328,7 +4417,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(const uint8_t * event){
return event[13];
return event[15];
}
/**
* @brief Get field min_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4337,7 +4426,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(const uint8_t * event){
return event[14];
return event[16];
}
/**
* @brief Get field max_bitpool_value from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
@ -4346,18 +4435,36 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(const uint8_t * event){
return event[15];
return event[17];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_configuration_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_configuration_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field acp_seid from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
* @param event packet
* @return acp_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_acp_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field reconfigure from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
* @param event packet
@ -4365,7 +4472,7 @@ static inline hci_con_handle_t avdtp_subevent_signaling_media_codec_other_config
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_reconfigure(const uint8_t * event){
return event[5];
return event[7];
}
/**
* @brief Get field media_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
@ -4374,7 +4481,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_g
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_get_media_type(const uint8_t * event){
return event[6];
return event[8];
}
/**
* @brief Get field media_codec_type from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
@ -4383,7 +4490,7 @@ static inline uint8_t avdtp_subevent_signaling_media_codec_other_configuration_g
* @note: btstack_type 2
*/
static inline uint16_t avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_type(const uint8_t * event){
return little_endian_read_16(event, 7);
return little_endian_read_16(event, 9);
}
/**
* @brief Get field media_codec_information_len from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
@ -4392,7 +4499,7 @@ static inline uint16_t avdtp_subevent_signaling_media_codec_other_configuration_
* @note: btstack_type L
*/
static inline int avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_information_len(const uint8_t * event){
return little_endian_read_16(event, 9);
return little_endian_read_16(event, 11);
}
/**
* @brief Get field media_codec_information from event AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
@ -4401,18 +4508,36 @@ static inline int avdtp_subevent_signaling_media_codec_other_configuration_get_m
* @note: btstack_type V
*/
static inline const uint8_t * avdtp_subevent_signaling_media_codec_other_configuration_get_media_codec_information(const uint8_t * event){
return &event[11];
return &event[13];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
* @param event packet
* @return con_handle
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_streaming_connection_established_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t avdtp_subevent_streaming_connection_established_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_streaming_connection_established_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field acp_seid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
* @param event packet
* @return acp_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_streaming_connection_established_get_acp_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field status from event AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
* @param event packet
@ -4420,18 +4545,159 @@ static inline hci_con_handle_t avdtp_subevent_streaming_connection_established_g
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_streaming_connection_established_get_status(const uint8_t * event){
return event[7];
}
/**
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_streaming_connection_released_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field avdtp_cid from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field int_seid from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return int_seid
* @note: btstack_type 1
*/
static inline uint8_t avdtp_subevent_streaming_can_send_media_packet_now_get_int_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field sequence_number from event AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return sequence_number
* @note: btstack_type 2
*/
static inline uint16_t avdtp_subevent_streaming_can_send_media_packet_now_get_sequence_number(const uint8_t * event){
return little_endian_read_16(event, 6);
}
/**
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_established_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_established_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field remote_seid from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return remote_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_established_get_remote_seid(const uint8_t * event){
return event[6];
}
/**
* @brief Get field status from event A2DP_SUBEVENT_STREAM_ESTABLISHED
* @param event packet
* @return status
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_established_get_status(const uint8_t * event){
return event[7];
}
/**
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_START_ACCEPTED
* @param event packet
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_start_accepted_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_START_ACCEPTED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_start_accepted_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field con_handle from event AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED
* @brief Get field a2dp_cid from event A2DP_SUBEVENT_STREAM_SUSPENDED
* @param event packet
* @return con_handle
* @return a2dp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t avdtp_subevent_streaming_connection_released_get_con_handle(const uint8_t * event){
static inline hci_con_handle_t a2dp_subevent_stream_suspended_get_a2dp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_SUSPENDED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_suspended_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_streaming_can_send_media_packet_now_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_streaming_can_send_media_packet_now_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field avdtp_cid from event A2DP_SUBEVENT_STREAM_RELEASED
* @param event packet
* @return avdtp_cid
* @note: btstack_type H
*/
static inline hci_con_handle_t a2dp_subevent_stream_released_get_avdtp_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field local_seid from event A2DP_SUBEVENT_STREAM_RELEASED
* @param event packet
* @return local_seid
* @note: btstack_type 1
*/
static inline uint8_t a2dp_subevent_stream_released_get_local_seid(const uint8_t * event){
return event[5];
}
/**
* @brief Get field con_handle from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED

134
src/classic/a2dp_sink.c Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2016 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define __BTSTACK_FILE__ "a2dp_sink.c"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "btstack.h"
#include "avdtp.h"
#include "avdtp_util.h"
#include "avdtp_sink.h"
#include "a2dp_sink.h"
static const char * default_a2dp_sink_service_name = "BTstack A2DP Sink Service";
static const char * default_a2dp_sink_service_provider_name = "BTstack A2DP Sink Service Provider";
// static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name){
uint8_t* attribute;
de_create_sequence(service);
// 0x0000 "Service Record Handle"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
// 0x0001 "Service Class ID List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AUDIO_SINK);
}
de_pop_sequence(service, attribute);
// 0x0004 "Protocol Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t* l2cpProtocol = de_push_sequence(attribute);
{
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP);
}
de_pop_sequence(attribute, l2cpProtocol);
uint8_t* avProtocol = de_push_sequence(attribute);
{
de_add_number(avProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP); // avProtocol_service
de_add_number(avProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version
}
de_pop_sequence(attribute, avProtocol);
}
de_pop_sequence(service, attribute);
// 0x0005 "Public Browse Group"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
}
de_pop_sequence(service, attribute);
// 0x0009 "Bluetooth Profile Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t *a2dProfile = de_push_sequence(attribute);
{
de_add_number(a2dProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION);
de_add_number(a2dProfile, DE_UINT, DE_SIZE_16, 0x0103);
}
de_pop_sequence(attribute, a2dProfile);
}
de_pop_sequence(service, attribute);
// 0x0100 "Service Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
if (service_name){
de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name);
} else {
de_add_data(service, DE_STRING, strlen(default_a2dp_sink_service_name), (uint8_t *) default_a2dp_sink_service_name);
}
// 0x0100 "Provider Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102);
if (service_provider_name){
de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
} else {
de_add_data(service, DE_STRING, strlen(default_a2dp_sink_service_provider_name), (uint8_t *) default_a2dp_sink_service_provider_name);
}
// 0x0311 "Supported Features"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}

73
src/classic/a2dp_sink.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2016 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
/*
* a2dp_sink.h
*
* Advanced Audio Distribution Transport Profile (A2DP) Sink
*
* A2DP Sink is a device that accepts streamed media data.
*/
#ifndef __A2DP_SINK_H
#define __A2DP_SINK_H
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
/* API_START */
/**
* @brief A2DP Sink service record.
* @param service
* @param service_record_handle
* @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h
* @param service_name
* @param service_provider_name
*/
void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);
/* API_END */
#if defined __cplusplus
}
#endif
#endif // __A2DP_SINK_H

570
src/classic/a2dp_source.c Normal file
View File

@ -0,0 +1,570 @@
/*
* Copyright (C) 2016 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define __BTSTACK_FILE__ "a2dp_source.c"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "btstack.h"
#include "avdtp.h"
#include "avdtp_util.h"
#include "avdtp_source.h"
#include "a2dp_source.h"
static const char * default_a2dp_source_service_name = "BTstack A2DP Source Service";
static const char * default_a2dp_source_service_provider_name = "BTstack A2DP Source Service Provider";
static avdtp_context_t a2dp_source_context;
#define AVDTP_MEDIA_PAYLOAD_HEADER_SIZE 12
typedef struct {
// to app
uint32_t fill_audio_ring_buffer_timeout_ms;
uint32_t time_audio_data_sent; // ms
uint32_t acc_num_missed_samples;
uint32_t samples_ready;
btstack_timer_source_t fill_audio_ring_buffer_timer;
btstack_ring_buffer_t sbc_ring_buffer;
btstack_sbc_encoder_state_t sbc_encoder_state;
int reconfigure;
int num_channels;
int sampling_frequency;
int channel_mode;
int block_length;
int subbands;
int allocation_method;
int min_bitpool_value;
int max_bitpool_value;
avdtp_stream_endpoint_t * local_stream_endpoint;
avdtp_sep_t * active_remote_sep;
} avdtp_stream_endpoint_context_t;
static a2dp_state_t app_state = A2DP_IDLE;
static avdtp_stream_endpoint_context_t sc;
static uint16_t avdtp_cid = 0;
static int next_remote_sep_index_to_query = 0;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name){
uint8_t* attribute;
de_create_sequence(service);
// 0x0000 "Service Record Handle"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
// 0x0001 "Service Class ID List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE);
}
de_pop_sequence(service, attribute);
// 0x0004 "Protocol Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t* l2cpProtocol = de_push_sequence(attribute);
{
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP);
}
de_pop_sequence(attribute, l2cpProtocol);
uint8_t* avProtocol = de_push_sequence(attribute);
{
de_add_number(avProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP); // avProtocol_service
de_add_number(avProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version
}
de_pop_sequence(attribute, avProtocol);
}
de_pop_sequence(service, attribute);
// 0x0005 "Public Browse Group"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
}
de_pop_sequence(service, attribute);
// 0x0009 "Bluetooth Profile Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t *a2dProfile = de_push_sequence(attribute);
{
de_add_number(a2dProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION);
de_add_number(a2dProfile, DE_UINT, DE_SIZE_16, 0x0103);
}
de_pop_sequence(attribute, a2dProfile);
}
de_pop_sequence(service, attribute);
// 0x0100 "Service Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
if (service_name){
de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name);
} else {
de_add_data(service, DE_STRING, strlen(default_a2dp_source_service_name), (uint8_t *) default_a2dp_source_service_name);
}
// 0x0100 "Provider Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102);
if (service_provider_name){
de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
} else {
de_add_data(service, DE_STRING, strlen(default_a2dp_source_service_provider_name), (uint8_t *) default_a2dp_source_service_provider_name);
}
// 0x0311 "Supported Features"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}
static void a2dp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t cid, uint8_t local_seid, uint8_t remote_seid, uint8_t status){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_ESTABLISHED;
little_endian_store_16(event, pos, cid);
pos += 2;
event[pos++] = local_seid;
event[pos++] = remote_seid;
event[pos++] = status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void a2dp_streaming_emit_can_send_media_packet_now(btstack_packet_handler_t callback, uint16_t cid, uint8_t seid){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW;
little_endian_store_16(event, pos, cid);
pos += 2;
event[pos++] = seid;
(*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);
bd_addr_t event_addr;
uint8_t signal_identifier;
uint8_t status;
avdtp_sep_t sep;
uint8_t int_seid;
uint8_t acp_seid;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_PIN_CODE_REQUEST:
// inform about pin code request
log_info("Pin code request - using '0000'");
hci_event_pin_code_request_get_bd_addr(packet, event_addr);
hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
// connection closed -> quit test app
log_info("\n --- a2dp source --- HCI_EVENT_DISCONNECTION_COMPLETE ---");
break;
case HCI_EVENT_AVDTP_META:
switch (packet[2]){
case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
avdtp_cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet);
status = avdtp_subevent_signaling_connection_established_get_status(packet);
if (status != 0){
log_info(" --- a2dp source --- AVDTP_SUBEVENT_SIGNALING_CONNECTION could not be established, status %d ---", status);
break;
}
sc.active_remote_sep = NULL;
next_remote_sep_index_to_query = 0;
app_state = A2DP_W2_DISCOVER_SEPS;
log_info(" --- a2dp source --- AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, avdtp cid 0x%02x ---", avdtp_cid);
avdtp_source_discover_stream_endpoints(avdtp_cid);
break;
case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED:
status = avdtp_subevent_streaming_connection_established_get_status(packet);
avdtp_cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet);
int_seid = avdtp_subevent_streaming_connection_established_get_int_seid(packet);
acp_seid = avdtp_subevent_streaming_connection_established_get_acp_seid(packet);
if (status != 0){
log_info(" --- a2dp source --- AVDTP_SUBEVENT_STREAMING_CONNECTION could not be established, status %d ---", status);
break;
}
app_state = A2DP_STREAMING_OPENED;
a2dp_streaming_emit_connection_established(a2dp_source_context.a2dp_callback, avdtp_cid, int_seid, acp_seid, 0);
log_info(" --- a2dp source --- AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED --- avdtp_cid 0x%02x, local seid %d, remote seid %d", avdtp_cid, int_seid, acp_seid);
break;
case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:
if (app_state != A2DP_W2_DISCOVER_SEPS) return;
sep.seid = avdtp_subevent_signaling_sep_found_get_seid(packet);
sep.in_use = avdtp_subevent_signaling_sep_found_get_in_use(packet);
sep.media_type = avdtp_subevent_signaling_sep_found_get_media_type(packet);
sep.type = avdtp_subevent_signaling_sep_found_get_sep_type(packet);
log_info(" --- a2dp source --- Found sep: seid %u, in_use %d, media type %d, sep type %d (1-SNK)", sep.seid, sep.in_use, sep.media_type, sep.type);
break;
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:{
if (!sc.local_stream_endpoint) return;
uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet));
uint8_t channel_mode = avdtp_choose_sbc_channel_mode(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet));
uint8_t block_length = avdtp_choose_sbc_block_length(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet));
uint8_t subbands = avdtp_choose_sbc_subbands(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet));
uint8_t allocation_method = avdtp_choose_sbc_allocation_method(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet));
uint8_t max_bitpool_value = avdtp_choose_sbc_max_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet));
uint8_t min_bitpool_value = avdtp_choose_sbc_min_bitpool_value(sc.local_stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet));
sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[0] = (sampling_frequency << 4) | channel_mode;
sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[1] = (block_length << 4) | (subbands << 2) | allocation_method;
sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[2] = min_bitpool_value;
sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_information[3] = max_bitpool_value;
sc.local_stream_endpoint->remote_configuration_bitmap = store_bit16(sc.local_stream_endpoint->remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1);
sc.local_stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO;
sc.local_stream_endpoint->remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
app_state = A2DP_W2_SET_CONFIGURATION;
break;
}
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY:
log_info(" --- a2dp source --- received non SBC codec. not implemented");
break;
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:{
sc.sampling_frequency = avdtp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
sc.block_length = avdtp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
sc.subbands = avdtp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
sc.allocation_method = avdtp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet) - 1;
sc.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
// TODO: deal with reconfigure: avdtp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
break;
}
case AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:
a2dp_streaming_emit_can_send_media_packet_now(a2dp_source_context.a2dp_callback, avdtp_cid, 0);
break;
case AVDTP_SUBEVENT_SIGNALING_ACCEPT:
signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet);
status = avdtp_subevent_signaling_accept_get_status(packet);
log_info(" --- a2dp source --- Accepted %d", signal_identifier);
switch (app_state){
case A2DP_W2_DISCOVER_SEPS:
app_state = A2DP_W2_GET_ALL_CAPABILITIES;
sc.active_remote_sep = avdtp_source_remote_sep(avdtp_cid, next_remote_sep_index_to_query++);
log_info(" --- a2dp source --- Query get caps for seid %d", sc.active_remote_sep->seid);
avdtp_source_get_capabilities(avdtp_cid, sc.active_remote_sep->seid);
break;
case A2DP_W2_GET_CAPABILITIES:
case A2DP_W2_GET_ALL_CAPABILITIES:
if (next_remote_sep_index_to_query < avdtp_source_remote_seps_num(avdtp_cid)){
sc.active_remote_sep = avdtp_source_remote_sep(avdtp_cid, next_remote_sep_index_to_query++);
log_info(" --- a2dp source --- Query get caps for seid %d", sc.active_remote_sep->seid);
avdtp_source_get_capabilities(avdtp_cid, sc.active_remote_sep->seid);
} else {
log_info(" --- a2dp source --- No more remote seps found");
app_state = A2DP_IDLE;
}
break;
case A2DP_W2_SET_CONFIGURATION:{
if (!sc.local_stream_endpoint) return;
app_state = A2DP_W2_GET_CONFIGURATION;
avdtp_source_set_configuration(avdtp_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_GET_CONFIGURATION:
app_state = A2DP_W2_OPEN_STREAM_WITH_SEID;
avdtp_source_get_configuration(avdtp_cid, sc.active_remote_sep->seid);
break;
case A2DP_W2_OPEN_STREAM_WITH_SEID:{
app_state = A2DP_W4_OPEN_STREAM_WITH_SEID;
btstack_sbc_encoder_init(&sc.sbc_encoder_state, SBC_MODE_STANDARD,
sc.block_length, sc.subbands,
sc.allocation_method, sc.sampling_frequency,
sc.max_bitpool_value);
avdtp_source_open_stream(avdtp_cid, avdtp_stream_endpoint_seid(sc.local_stream_endpoint), sc.active_remote_sep->seid);
break;
}
case A2DP_STREAMING_OPENED:
if (!a2dp_source_context.a2dp_callback) return;
switch (signal_identifier){
case AVDTP_SI_START:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_START_ACCEPTED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
case AVDTP_SI_CLOSE:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_RELEASED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
log_info("send A2DP_SUBEVENT_STREAM_RELEASED to app");
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
case AVDTP_SI_SUSPEND:{
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_A2DP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = A2DP_SUBEVENT_STREAM_SUSPENDED;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = avdtp_stream_endpoint_seid(sc.local_stream_endpoint);
(*a2dp_source_context.a2dp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
default:
break;
}
break;
default:
app_state = A2DP_IDLE;
break;
}
break;
case AVDTP_SUBEVENT_SIGNALING_REJECT:
app_state = A2DP_IDLE;
signal_identifier = avdtp_subevent_signaling_reject_get_signal_identifier(packet);
log_info(" --- a2dp source --- Rejected %d", signal_identifier);
break;
case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT:
app_state = A2DP_IDLE;
signal_identifier = avdtp_subevent_signaling_general_reject_get_signal_identifier(packet);
log_info(" --- a2dp source --- Rejected %d", signal_identifier);
break;
default:
app_state = A2DP_IDLE;
log_info(" --- a2dp source --- not implemented");
break;
}
break;
default:
break;
}
break;
default:
// other packet type
break;
}
}
void a2dp_source_register_packet_handler(btstack_packet_handler_t callback){
if (callback == NULL){
log_error("a2dp_source_register_packet_handler called with NULL callback");
return;
}
avdtp_source_register_packet_handler(&packet_handler);
a2dp_source_context.a2dp_callback = callback;
}
void a2dp_source_init(void){
avdtp_source_init(&a2dp_source_context);
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
}
uint8_t a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
uint8_t * codec_capabilities, uint16_t codec_capabilities_len,
uint8_t * media_codec_info, uint16_t media_codec_info_len){
avdtp_stream_endpoint_t * local_stream_endpoint = avdtp_source_create_stream_endpoint(AVDTP_SOURCE, media_type);
avdtp_source_register_media_transport_category(avdtp_stream_endpoint_seid(local_stream_endpoint));
avdtp_source_register_media_codec_category(avdtp_stream_endpoint_seid(local_stream_endpoint), media_type, media_codec_type,
codec_capabilities, codec_capabilities_len);
local_stream_endpoint->remote_configuration.media_codec.media_codec_information = media_codec_info;
local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = media_codec_info_len;
return local_stream_endpoint->sep.seid;
}
void a2dp_source_establish_stream(bd_addr_t bd_addr, uint8_t local_seid){
sc.local_stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!sc.local_stream_endpoint){
log_error(" no local_stream_endpoint for seid %d", local_seid);
return;
}
avdtp_source_connect(bd_addr);
}
void a2dp_source_disconnect(uint16_t con_handle){
avdtp_disconnect(con_handle, &a2dp_source_context);
}
void a2dp_source_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, &a2dp_source_context);
}
void a2dp_source_release_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, &a2dp_source_context);
}
void a2dp_source_pause_stream(uint8_t int_seid){
avdtp_suspend_stream(int_seid, &a2dp_source_context);
}
uint8_t a2dp_source_stream_endpoint_ready(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!stream_endpoint) {
log_error("No stream_endpoint with seid %d", local_seid);
return 0;
}
return (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING);
}
static void a2dp_source_setup_media_header(uint8_t * media_packet, int size, int *offset, uint8_t marker, uint16_t sequence_number){
if (size < AVDTP_MEDIA_PAYLOAD_HEADER_SIZE){
log_error("small outgoing buffer");
return;
}
uint8_t rtp_version = 2;
uint8_t padding = 0;
uint8_t extension = 0;
uint8_t csrc_count = 0;
uint8_t payload_type = 0x60;
// uint16_t sequence_number = stream_endpoint->sequence_number;
uint32_t timestamp = btstack_run_loop_get_time_ms();
uint32_t ssrc = 0x11223344;
// rtp header (min size 12B)
int pos = 0;
// int mtu = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
media_packet[pos++] = (rtp_version << 6) | (padding << 5) | (extension << 4) | csrc_count;
media_packet[pos++] = (marker << 1) | payload_type;
big_endian_store_16(media_packet, pos, sequence_number);
pos += 2;
big_endian_store_32(media_packet, pos, timestamp);
pos += 4;
big_endian_store_32(media_packet, pos, ssrc); // only used for multicast
pos += 4;
*offset = pos;
}
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(local_seid, &a2dp_source_context);
if (!stream_endpoint) {
log_error("no stream_endpoint for seid %d", local_seid);
return;
}
stream_endpoint->send_stream = 1;
avdtp_request_can_send_now_initiator(stream_endpoint->connection, stream_endpoint->l2cap_media_cid);
}
int a2dp_max_media_payload_size(uint8_t int_seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, &a2dp_source_context);
if (!stream_endpoint) {
log_error("no stream_endpoint found for seid %d", int_seid);
return 0;
}
if (stream_endpoint->l2cap_media_cid == 0){
log_error("no media cid found for seid %d", int_seid);
return 0;
}
return l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid) - AVDTP_MEDIA_PAYLOAD_HEADER_SIZE;
}
static void a2dp_source_copy_media_payload(uint8_t * media_packet, int size, int * offset, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames){
if (size < num_bytes_to_copy + 1){
log_error("small outgoing buffer");
return;
}
int pos = *offset;
media_packet[pos++] = num_frames; // (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames;
memcpy(media_packet + pos, storage, num_bytes_to_copy);
pos += num_bytes_to_copy;
*offset = pos;
}
int a2dp_source_stream_send_media_payload(uint8_t int_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, &a2dp_source_context);
if (!stream_endpoint) {
log_error("no stream_endpoint found for seid %d", int_seid);
return 0;
}
if (stream_endpoint->l2cap_media_cid == 0){
log_error("no media cid found for seid %d", int_seid);
return 0;
}
int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
int offset = 0;
l2cap_reserve_packet_buffer();
uint8_t * media_packet = l2cap_get_outgoing_buffer();
//int size = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
a2dp_source_setup_media_header(media_packet, size, &offset, marker, stream_endpoint->sequence_number);
a2dp_source_copy_media_payload(media_packet, size, &offset, storage, num_bytes_to_copy, num_frames);
stream_endpoint->sequence_number++;
l2cap_send_prepared(stream_endpoint->l2cap_media_cid, offset);
return size;
}

125
src/classic/a2dp_source.h Normal file
View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2016 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
/*
* a2dp_source.h
*
* Advanced Audio Distribution Transport Profile (A2DP) Source
*
* A2DP Source is a device that streames media data.
*/
#ifndef __A2DP_SOURCE_H
#define __A2DP_SOURCE_H
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
/* API_START */
/**
* @brief A2DP Source service record.
* @param service
* @param service_record_handle
* @param supported_features 16-bit bitmap, see AVDTP_SOURCE_SF_* values in avdtp.h
* @param service_name
* @param service_provider_name
*/
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);
void a2dp_source_init(void);
void a2dp_source_register_packet_handler(btstack_packet_handler_t callback);
uint8_t a2dp_source_create_stream_endpoint(avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type,
uint8_t * codec_capabilities, uint16_t codec_capabilities_len,
uint8_t * codec_configuration, uint16_t codec_configuration_len);
/**
* @brief Open stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_establish_stream(bd_addr_t bd_addr, uint8_t local_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_start_stream(uint8_t int_seid);
/**
* @brief Start stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_pause_stream(uint8_t int_seid);
/**
* @brief Close stream
* @param avdtp_cid
* @param seid
*/
void a2dp_source_release_stream(uint8_t int_seid);
/**
* @brief Disconnect from device with connection handle.
* @param avdtp_cid
*/
void a2dp_source_disconnect(uint16_t avdtp_cid);
// size for media (does not include media header)
int a2dp_max_media_payload_size(uint8_t int_seid);
uint8_t a2dp_source_stream_endpoint_ready(uint8_t local_seid);
void a2dp_source_stream_endpoint_request_can_send_now(uint8_t local_seid);
int a2dp_source_stream_send_media_payload(uint8_t int_seid, uint8_t * storage, int num_bytes_to_copy, uint8_t num_frames, uint8_t marker);
/* API_END */
#if defined __cplusplus
}
#endif
#endif // __A2DP_SOURCE_H

View File

@ -50,13 +50,37 @@
#include "avdtp_acceptor.h"
#include "avdtp_initiator.h"
static uint8_t audio_samples_storage[44100*4]; // 1s buffer
// static btstack_ring_buffer_t audio_ring_buffer;
static int record_id = -1;
static uint8_t attribute_value[1000];
static const unsigned int attribute_value_buffer_size = sizeof(attribute_value);
static uint8_t sbc_samples_storage[44100*4];
// static btstack_ring_buffer_t sbc_ring_buffer;
typedef struct {
avdtp_connection_t * connection;
btstack_packet_handler_t avdtp_callback;
avdtp_sep_type_t query_role;
btstack_packet_handler_t packet_handler;
} avdtp_sdp_query_context_t;
static avdtp_sdp_query_context_t sdp_query_context;
static void (*handle_media_data)(avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size);
static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void avdtp_connect(bd_addr_t remote, avdtp_sep_type_t query_role, avdtp_context_t * avdtp_context){
sdp_query_context.connection = NULL;
avdtp_connection_t * connection = avdtp_connection_for_bd_addr(remote, avdtp_context);
if (!connection){
connection = avdtp_create_connection(remote, avdtp_context);
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_IDLE) return;
connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE;
sdp_query_context.connection = connection;
sdp_query_context.query_role = query_role;
sdp_query_context.avdtp_callback = avdtp_context->avdtp_callback;
sdp_query_context.packet_handler = avdtp_context->packet_handler;
sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, remote, BLUETOOTH_PROTOCOL_AVDTP);
}
void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){
if (!stream_endpoint){
@ -65,7 +89,6 @@ void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_en
}
uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1);
stream_endpoint->sep.registered_service_categories = bitmap;
printf("registered services AVDTP_MEDIA_TRANSPORT(%d) %02x\n", AVDTP_MEDIA_TRANSPORT, stream_endpoint->sep.registered_service_categories);
}
void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
@ -122,14 +145,13 @@ void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream
stream_endpoint->sep.capabilities.header_compression.recovery = recovery;
}
void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len){
void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){
if (!stream_endpoint){
log_error("avdtp_register_media_transport_category: stream endpoint with given seid is not registered");
return;
}
uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1);
stream_endpoint->sep.registered_service_categories = bitmap;
printf("registered services AVDTP_MEDIA_CODEC(%d) %02x\n", AVDTP_MEDIA_CODEC, stream_endpoint->sep.registered_service_categories);
stream_endpoint->sep.capabilities.media_codec.media_type = media_type;
stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type;
stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info;
@ -203,14 +225,6 @@ avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type
stream_endpoint->sep.seid = context->stream_endpoints_id_counter;
stream_endpoint->sep.media_type = media_type;
stream_endpoint->sep.type = sep_type;
memset(audio_samples_storage, 0, sizeof(audio_samples_storage));
btstack_ring_buffer_init(&stream_endpoint->audio_ring_buffer, audio_samples_storage, sizeof(audio_samples_storage));
memset(sbc_samples_storage, 0, sizeof(sbc_samples_storage));
btstack_ring_buffer_init(&stream_endpoint->sbc_ring_buffer, sbc_samples_storage, sizeof(sbc_samples_storage));
btstack_linked_list_add(&context->stream_endpoints, (btstack_linked_item_t *) stream_endpoint);
return stream_endpoint;
}
@ -248,8 +262,9 @@ static void stream_endpoint_state_machine(avdtp_connection_t * connection, avdtp
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
stream_endpoint->connection = connection;
stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
printf(" -> AVDTP_STREAM_ENDPOINT_OPENED, stream endpoint %p, connection %p\n", stream_endpoint, connection);
avdtp_streaming_emit_connection_established(context->avdtp_callback, stream_endpoint->l2cap_media_cid, 0);
stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
log_info(" -> AVDTP_STREAM_ENDPOINT_OPENED, media con handle 0x%02x, l2cap_media_cid 0x%02x", stream_endpoint->media_con_handle, stream_endpoint->l2cap_media_cid);
avdtp_streaming_emit_connection_established(context->avdtp_callback, connection->l2cap_signaling_cid, stream_endpoint->sep.seid, connection->remote_seps[stream_endpoint->remote_sep_index].seid, 0);
break;
}
break;
@ -257,13 +272,11 @@ static void stream_endpoint_state_machine(avdtp_connection_t * connection, avdtp
local_cid = l2cap_event_channel_closed_get_local_cid(packet);
if (stream_endpoint->l2cap_media_cid == local_cid){
stream_endpoint->l2cap_media_cid = 0;
printf(" -> L2CAP_EVENT_CHANNEL_CLOSED: AVDTP_STREAM_ENDPOINT_IDLE\n");
log_info(" -> L2CAP_EVENT_CHANNEL_CLOSED: AVDTP_STREAM_ENDPOINT_IDLE");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
stream_endpoint->remote_seps_num = 0;
memset(stream_endpoint->remote_seps, 0, sizeof(avdtp_sep_t)*MAX_NUM_SEPS);
stream_endpoint->remote_sep_index = AVDTP_INVALID_SEP_INDEX;
stream_endpoint->remote_sep_index = 0;
break;
}
if (stream_endpoint->l2cap_recovery_cid == local_cid){
@ -287,6 +300,121 @@ static void stream_endpoint_state_machine(avdtp_connection_t * connection, avdtp
}
}
static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(packet_type);
UNUSED(channel);
UNUSED(size);
des_iterator_t des_list_it;
des_iterator_t prot_it;
uint32_t avdtp_remote_uuid = 0;
uint16_t avdtp_l2cap_psm = 0;
uint16_t avdtp_version = 0;
if (!sdp_query_context.connection) return;
switch (hci_event_packet_get_type(packet)){
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
// Handle new SDP record
if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) {
record_id = sdp_event_query_attribute_byte_get_record_id(packet);
// log_info("SDP Record: Nr: %d", record_id);
}
if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) {
attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
if (de_get_element_type(attribute_value) != DE_DES) break;
for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
uint8_t * element = des_iterator_get_element(&des_list_it);
if (de_get_element_type(element) != DE_UUID) continue;
uint32_t uuid = de_get_uuid32(element);
switch (uuid){
case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE:
if (sdp_query_context.query_role != AVDTP_SOURCE) {
sdp_query_context.connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
avdtp_signaling_emit_connection_established(sdp_query_context.avdtp_callback, sdp_query_context.connection->l2cap_signaling_cid, sdp_query_context.connection->remote_addr, 0);
break;
}
// log_info("SDP Attribute 0x%04x: AVDTP SOURCE protocol UUID: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid);
avdtp_remote_uuid = uuid;
break;
case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
if (sdp_query_context.query_role != AVDTP_SINK) {
sdp_query_context.connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
avdtp_signaling_emit_connection_established(sdp_query_context.avdtp_callback, sdp_query_context.connection->l2cap_signaling_cid, sdp_query_context.connection->remote_addr, 0);
break;
}
// log_info("SDP Attribute 0x%04x: AVDTP SINK protocol UUID: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet), uuid);
avdtp_remote_uuid = uuid;
break;
default:
break;
}
}
break;
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: {
// log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
uint8_t *des_element;
uint8_t *element;
uint32_t uuid;
if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
des_element = des_iterator_get_element(&des_list_it);
des_iterator_init(&prot_it, des_element);
element = des_iterator_get_element(&prot_it);
if (de_get_element_type(element) != DE_UUID) continue;
uuid = de_get_uuid32(element);
switch (uuid){
case BLUETOOTH_PROTOCOL_L2CAP:
if (!des_iterator_has_more(&prot_it)) continue;
des_iterator_next(&prot_it);
de_element_get_uint16(des_iterator_get_element(&prot_it), &avdtp_l2cap_psm);
break;
case BLUETOOTH_PROTOCOL_AVDTP:
if (!des_iterator_has_more(&prot_it)) continue;
des_iterator_next(&prot_it);
de_element_get_uint16(des_iterator_get_element(&prot_it), &avdtp_version);
break;
default:
break;
}
}
if (!avdtp_l2cap_psm) {
sdp_query_context.connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
avdtp_signaling_emit_connection_established(sdp_query_context.avdtp_callback, sdp_query_context.connection->l2cap_signaling_cid, sdp_query_context.connection->remote_addr, L2CAP_SERVICE_DOES_NOT_EXIST);
break;
}
sdp_query_context.connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
l2cap_create_channel(sdp_query_context.packet_handler, sdp_query_context.connection->remote_addr, avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
}
break;
default:
break;
}
}
} else {
log_error("SDP attribute value buffer size exceeded: available %d, required %d", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet));
}
break;
case SDP_EVENT_QUERY_COMPLETE:
log_info("General query done with status %d.", sdp_event_query_complete_get_status(packet));
break;
}
}
void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avdtp_context_t * context){
bd_addr_t event_addr;
hci_con_handle_t con_handle;
@ -297,7 +425,7 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
btstack_linked_list_t * avdtp_connections = &context->connections;
btstack_linked_list_t * stream_endpoints = &context->stream_endpoints;
handle_media_data = context->handle_media_data;
// printf("avdtp_packet_handler packet type %02x, event %02x \n", packet_type, hci_event_packet_get_type(packet));
// log_info("avdtp_packet_handler packet type %02x, event %02x ", packet_type, hci_event_packet_get_type(packet));
switch (packet_type) {
case L2CAP_DATA_PACKET:
connection = avdtp_connection_for_l2cap_signaling_cid(channel, context);
@ -325,10 +453,10 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
if (channel == stream_endpoint->l2cap_reporting_cid){
// TODO
printf("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED\n");
log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED");
} else if (channel == stream_endpoint->l2cap_recovery_cid){
// TODO
printf("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED\n");
log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED");
} else {
log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel);
}
@ -341,16 +469,18 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
connection = avdtp_connection_for_bd_addr(event_addr, context);
if (!connection){
if (!connection || connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED){
connection = avdtp_create_connection(event_addr, context);
connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
log_info("L2CAP_EVENT_INCOMING_CONNECTION, connection %p, state connection %d", connection, connection->state);
l2cap_accept_connection(local_cid);
break;
}
stream_endpoint = avdtp_stream_endpoint_for_seid(connection->query_seid, context);
if (!stream_endpoint) {
printf("L2CAP_EVENT_INCOMING_CONNECTION no streamendpoint found for seid %d\n", connection->query_seid);
log_info("L2CAP_EVENT_INCOMING_CONNECTION no streamendpoint found for seid %d", connection->query_seid);
break;
}
@ -378,8 +508,8 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
con_handle = l2cap_event_channel_opened_get_handle(packet);
local_cid = l2cap_event_channel_opened_get_local_cid(packet);
// printf("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
// bd_addr_to_str(event_addr), con_handle, psm, local_cid, l2cap_event_channel_opened_get_remote_cid(packet));
log_info("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x",
bd_addr_to_str(event_addr), con_handle, psm, local_cid, l2cap_event_channel_opened_get_remote_cid(packet));
if (psm != BLUETOOTH_PROTOCOL_AVDTP) break;
@ -392,14 +522,14 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
connection->con_handle = con_handle;
connection->query_seid = 0;
connection->state = AVDTP_SIGNALING_CONNECTION_OPENED;
printf(" -> AVDTP_SIGNALING_CONNECTION_OPENED, connection %p\n", connection);
avdtp_signaling_emit_connection_established(context->avdtp_callback, con_handle, event_addr, 0);
log_info(" -> AVDTP_SIGNALING_CONNECTION_OPENED, connection %p", connection);
avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->l2cap_signaling_cid, event_addr, 0);
break;
}
stream_endpoint = avdtp_stream_endpoint_for_seid(connection->query_seid, context);
if (!stream_endpoint){
printf("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found");
log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found");
return;
}
stream_endpoint_state_machine(connection, stream_endpoint, HCI_EVENT_PACKET, L2CAP_EVENT_CHANNEL_OPENED, packet, size, context);
@ -409,10 +539,10 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
// data: event (8), len(8), channel (16)
local_cid = l2cap_event_channel_closed_get_local_cid(packet);
connection = avdtp_connection_for_l2cap_signaling_cid(local_cid, context);
printf(" -> L2CAP_EVENT_CHANNEL_CLOSED signaling cid 0x%0x\n", local_cid);
log_info(" -> L2CAP_EVENT_CHANNEL_CLOSED signaling cid 0x%0x", local_cid);
if (connection){
printf(" -> AVDTP_STREAM_ENDPOINT_IDLE, connection closed\n");
log_info(" -> AVDTP_STREAM_ENDPOINT_IDLE, connection closed");
btstack_linked_list_remove(avdtp_connections, (btstack_linked_item_t*) connection);
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, stream_endpoints);
@ -437,68 +567,12 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
if (!connection) {
stream_endpoint = avdtp_stream_endpoint_for_l2cap_cid(channel, context);
if (!stream_endpoint->connection) break;
if (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND){
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
//send sbc
uint8_t rtp_version = 2;
uint8_t padding = 0;
uint8_t extension = 0;
uint8_t csrc_count = 0;
uint8_t marker = 0;
uint8_t payload_type = 0x60;
uint16_t sequence_number = stream_endpoint->sequence_number;
uint32_t timestamp = btstack_run_loop_get_time_ms();
uint32_t ssrc = 0x11223344;
// rtp header (min size 12B)
int pos = 0;
int mtu = l2cap_get_remote_mtu_for_local_cid(stream_endpoint->l2cap_media_cid);
uint8_t media_packet[mtu];
media_packet[pos++] = (rtp_version << 6) | (padding << 5) | (extension << 4) | csrc_count;
media_packet[pos++] = (marker << 1) | payload_type;
big_endian_store_16(media_packet, pos, sequence_number);
pos += 2;
big_endian_store_32(media_packet, pos, timestamp);
pos += 4;
big_endian_store_32(media_packet, pos, ssrc); // only used for multicast
pos += 4;
// media payload
// sbc_header (size 1B)
uint8_t sbc_header_index = pos;
pos++;
uint8_t fragmentation = 0;
uint8_t starting_packet = 0; // set to 1 for the first packet of a fragmented SBC frame
uint8_t last_packet = 0; // set to 1 for the last packet of a fragmented SBC frame
uint8_t num_frames = 0;
uint32_t total_sbc_bytes_read = 0;
uint8_t sbc_frame_size = 0;
// payload
while (mtu - 13 - total_sbc_bytes_read >= 120 && btstack_ring_buffer_bytes_available(&stream_endpoint->sbc_ring_buffer)){
uint32_t number_of_bytes_read = 0;
btstack_ring_buffer_read(&stream_endpoint->sbc_ring_buffer, &sbc_frame_size, 1, &number_of_bytes_read);
btstack_ring_buffer_read(&stream_endpoint->sbc_ring_buffer, media_packet + pos, sbc_frame_size, &number_of_bytes_read);
pos += sbc_frame_size;
total_sbc_bytes_read += sbc_frame_size;
num_frames++;
// printf("send sbc frame: timestamp %d, seq. nr %d\n", timestamp, stream_endpoint->sequence_number);
}
media_packet[sbc_header_index] = (fragmentation << 7) | (starting_packet << 6) | (last_packet << 5) | num_frames;
stream_endpoint->sequence_number++;
l2cap_send(stream_endpoint->l2cap_media_cid, media_packet, pos);
if (btstack_ring_buffer_bytes_available(&stream_endpoint->sbc_ring_buffer)){
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND;
l2cap_request_can_send_now_event(stream_endpoint->l2cap_media_cid);
}
}
connection = stream_endpoint->connection;
}
avdtp_handle_can_send_now(connection, channel, context);
break;
default:
printf("unknown HCI event type %02x\n", hci_event_packet_get_type(packet));
log_info("unknown HCI event type %02x", hci_event_packet_get_type(packet));
break;
}
break;
@ -509,8 +583,8 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
}
}
void avdtp_disconnect(uint16_t con_handle, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_disconnect(uint16_t avdtp_cid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection) return;
if (connection->state == AVDTP_SIGNALING_CONNECTION_IDLE) return;
if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return;
@ -519,21 +593,25 @@ void avdtp_disconnect(uint16_t con_handle, avdtp_context_t * context){
avdtp_request_can_send_now_self(connection, connection->l2cap_signaling_cid);
}
void avdtp_open_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_media_connect: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_media_connect: wrong connection state %d\n", connection->state);
if (avdtp_find_remote_sep(connection, acp_seid) == 0xFF){
log_error("avdtp_media_connect: no remote sep for seid %d found", acp_seid);
return;
}
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
log_error("avdtp_media_connect: wrong connection state %d", connection->state);
return;
}
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
printf("avdtp_media_connect: no stream_endpoint with acp seid %d found\n", acp_seid);
log_error("avdtp_media_connect: no stream_endpoint with seid %d found", int_seid);
return;
}
@ -548,103 +626,79 @@ void avdtp_open_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t *
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_start_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
if (!connection){
printf("avdtp_media_connect: no connection for handle 0x%02x found\n", con_handle);
void avdtp_start_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
log_error("avdtp_start_stream: no stream_endpoint with seid %d found", int_seid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_media_connect: wrong connection state %d\n", connection->state);
avdtp_connection_t * connection = stream_endpoint->connection;
if (!connection){
log_error("avdtp_start_stream: no connection for seid %d found",stream_endpoint->sep.seid);
return;
}
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
if (!stream_endpoint) {
printf("avdtp_media_connect: no stream_endpoint with acp_seid %d found\n", acp_seid);
return;
}
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return;
if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_OPENED) return;
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_STREAMING_START;
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX || stream_endpoint->start_stream) return;
stream_endpoint->start_stream = 1;
connection->int_seid = int_seid;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_stop_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
if (!connection){
printf("avdtp_stop_stream: no connection for handle 0x%02x found\n", con_handle);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_stop_stream: wrong connection state %d\n", connection->state);
return;
}
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
void avdtp_stop_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
printf("avdtp_stop_stream: no stream_endpoint with acp seid %d found\n", acp_seid);
log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", int_seid);
return;
}
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return;
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
printf(" AVDTP_INITIATOR_W2_STREAMING_STOP \n");
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_STREAMING_STOP;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
break;
default:
break;
avdtp_connection_t * connection = stream_endpoint->connection;
if (!connection){
log_error("avdtp_stop_stream: no connection for seid %d found",stream_endpoint->sep.seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->stop_stream) return;
stream_endpoint->stop_stream = 1;
connection->int_seid = int_seid;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_abort_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
if (!connection){
printf("avdtp_abort_stream: no connection for handle 0x%02x found\n", con_handle);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
printf("avdtp_abort_stream: wrong connection state %d\n", connection->state);
return;
}
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
void avdtp_abort_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
printf("avdtp_abort_stream: no stream_endpoint for seid %d found\n", acp_seid);
log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", int_seid);
return;
}
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return;
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_CONFIGURED:
case AVDTP_STREAM_ENDPOINT_CLOSING:
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
printf(" AVDTP_INITIATOR_W2_STREAMING_ABORT \n");
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_STREAMING_ABORT;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
break;
default:
break;
avdtp_connection_t * connection = stream_endpoint->connection;
if (!connection){
log_error("avdtp_abort_stream: no connection for seid %d found",stream_endpoint->sep.seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->abort_stream) return;
stream_endpoint->abort_stream = 1;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_discover_stream_endpoints(uint16_t con_handle, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_suspend_stream(uint8_t int_seid, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_with_seid(int_seid, context);
if (!stream_endpoint) {
log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", int_seid);
return;
}
avdtp_connection_t * connection = stream_endpoint->connection;
if (!connection){
printf("avdtp_discover_stream_endpoints: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_abort_stream: no connection for seid %d found",stream_endpoint->sep.seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF || stream_endpoint->suspend_stream) return;
stream_endpoint->suspend_stream = 1;
connection->int_seid = int_seid;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_discover_stream_endpoints(uint16_t avdtp_cid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
@ -656,16 +710,16 @@ void avdtp_discover_stream_endpoints(uint16_t con_handle, avdtp_context_t * cont
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
break;
default:
printf("avdtp_discover_stream_endpoints: wrong state\n");
log_error("avdtp_discover_stream_endpoints: wrong state");
break;
}
}
void avdtp_get_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_get_capabilities: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_get_capabilities: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
@ -677,10 +731,10 @@ void avdtp_get_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_context
}
void avdtp_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_get_all_capabilities: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_get_all_capabilities: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
@ -691,10 +745,10 @@ void avdtp_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_con
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_get_configuration(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_get_configuration: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_get_configuration: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
@ -705,10 +759,10 @@ void avdtp_get_configuration(uint16_t con_handle, uint8_t acp_seid, avdtp_contex
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
log_error("avdtp_set_configuration: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_set_configuration: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
@ -716,55 +770,181 @@ void avdtp_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, context);
if (!stream_endpoint) {
log_error("avdtp_set_configuration: no initiator stream endpoint for seid %d\n", int_seid);
log_error("avdtp_set_configuration: no initiator stream endpoint for seid %d", int_seid);
return;
}
// printf("avdtp_set_configuration int seid %d, acp seid %d\n", int_seid, acp_seid);
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = int_seid;
connection->remote_capabilities_bitmap = configured_services_bitmap;
connection->remote_capabilities = configuration;
stream_endpoint->remote_capabilities_bitmap = configured_services_bitmap;
stream_endpoint->remote_capabilities = configuration;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
void avdtp_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_reconfigure: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_reconfigure: no connection for signaling cid 0x%02x found", avdtp_cid);
return;
}
//TODO: if opened only app capabilities, enable reconfigure for not opened
if (connection->state < AVDTP_SIGNALING_CONNECTION_OPENED) return;
if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) return;
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
if (!stream_endpoint) return;
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return;
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(int_seid, context);
if (!stream_endpoint) {
log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", int_seid);
return;
}
if (stream_endpoint->remote_sep_index == 0xFF){
log_error("avdtp_reconfigure: no associated remote sep");
return;
}
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
connection->remote_capabilities_bitmap = configured_services_bitmap;
connection->remote_capabilities = configuration;
stream_endpoint->remote_capabilities_bitmap = configured_services_bitmap;
stream_endpoint->remote_capabilities = configuration;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
}
void avdtp_suspend(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_con_handle(con_handle, context);
uint8_t avdtp_remote_seps_num(uint16_t avdtp_cid, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
printf("avdtp_suspend: no connection for handle 0x%02x found\n", con_handle);
log_error("avdtp_suspend: no connection for signaling cid 0x%02x found", avdtp_cid);
return 0;
}
return connection->remote_seps_num;
}
avdtp_sep_t * avdtp_remote_sep(uint16_t avdtp_cid, uint8_t index, avdtp_context_t * context){
avdtp_connection_t * connection = avdtp_connection_for_l2cap_signaling_cid(avdtp_cid, context);
if (!connection){
log_error("avdtp_suspend: no connection for signaling cid 0x%02x found", avdtp_cid);
return NULL;
}
return &connection->remote_seps[index];
}
void avdtp_initialize_sbc_configuration_storage(avdtp_stream_endpoint_t * stream_endpoint, uint8_t * config_storage, uint16_t storage_size, uint8_t * packet, uint16_t packet_size){
UNUSED(packet_size);
if (storage_size < 4) {
log_error("storage must have 4 bytes");
return;
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE) return;
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(acp_seid, context);
if (!stream_endpoint) return;
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX) return;
connection->initiator_transaction_label++;
connection->acp_seid = acp_seid;
connection->int_seid = stream_endpoint->sep.seid;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SUSPEND_STREAM_WITH_SEID;
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);
uint8_t sampling_frequency = avdtp_choose_sbc_sampling_frequency(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet));
uint8_t channel_mode = avdtp_choose_sbc_channel_mode(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet));
uint8_t block_length = avdtp_choose_sbc_block_length(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet));
uint8_t subbands = avdtp_choose_sbc_subbands(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet));
uint8_t allocation_method = avdtp_choose_sbc_allocation_method(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet));
uint8_t max_bitpool_value = avdtp_choose_sbc_max_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet));
uint8_t min_bitpool_value = avdtp_choose_sbc_min_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet));
config_storage[0] = (sampling_frequency << 4) | channel_mode;
config_storage[1] = (block_length << 4) | (subbands << 2) | allocation_method;
config_storage[2] = min_bitpool_value;
config_storage[3] = max_bitpool_value;
stream_endpoint->remote_configuration_bitmap = store_bit16(stream_endpoint->remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1);
stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO;
stream_endpoint->remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
stream_endpoint->remote_configuration.media_codec.media_codec_information_len = storage_size;
stream_endpoint->remote_configuration.media_codec.media_codec_information = config_storage;
}
uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap;
uint8_t channel_mode = AVDTP_SBC_STEREO;
if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
channel_mode = AVDTP_SBC_JOINT_STEREO;
} else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
channel_mode = AVDTP_SBC_STEREO;
} else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
channel_mode = AVDTP_SBC_DUAL_CHANNEL;
} else if (channel_mode_bitmap & AVDTP_SBC_MONO){
channel_mode = AVDTP_SBC_MONO;
}
return channel_mode;
}
uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap;
uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){
allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
} else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){
allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR;
}
return allocation_method;
}
uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){
if (!stream_endpoint) return 0;
return stream_endpoint->sep.seid;
}
uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap;
uint8_t subbands = AVDTP_SBC_SUBBANDS_8;
if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
subbands = AVDTP_SBC_SUBBANDS_8;
} else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
subbands = AVDTP_SBC_SUBBANDS_4;
}
return subbands;
}
uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap;
uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16;
if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
block_length = AVDTP_SBC_BLOCK_LENGTH_16;
} else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
block_length = AVDTP_SBC_BLOCK_LENGTH_12;
} else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
block_length = AVDTP_SBC_BLOCK_LENGTH_8;
} else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
block_length = AVDTP_SBC_BLOCK_LENGTH_4;
}
return block_length;
}
uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
uint8_t sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap;
uint8_t sampling_frequency = AVDTP_SBC_44100;
if (sampling_frequency_bitmap & AVDTP_SBC_48000){
sampling_frequency = AVDTP_SBC_48000;
} else if (sampling_frequency_bitmap & AVDTP_SBC_44100){
sampling_frequency = AVDTP_SBC_44100;
} else if (sampling_frequency_bitmap & AVDTP_SBC_32000){
sampling_frequency = AVDTP_SBC_32000;
} else if (sampling_frequency_bitmap & AVDTP_SBC_16000){
sampling_frequency = AVDTP_SBC_16000;
}
return sampling_frequency;
}
uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
return btstack_min(media_codec[3], remote_max_bitpool_value);
}
uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){
uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
return btstack_max(media_codec[2], remote_min_bitpool_value);
}

View File

@ -60,16 +60,6 @@ extern "C" {
#endif
#define MAX_NUM_SEPS 10
// protocols
#define PSM_AVCTP BLUETOOTH_PROTOCOL_AVCTP
#define PSM_AVDTP BLUETOOTH_PROTOCOL_AVDTP
// service classes
#define AUDIO_SOURCE_GROUP 0x110A
#define AUDIO_SINK_GROUP 0x110B
#define ADVANCED_AUDIO_DISTRIBUTION 0X110D
#define MAX_CSRC_NUM 15
// Supported Features
@ -185,9 +175,10 @@ typedef struct {
avdtp_media_type_t media_type;
avdtp_media_codec_type_t media_codec_type;
uint16_t media_codec_information_len;
const uint8_t * media_codec_information;
uint8_t * media_codec_information;
} adtvp_media_codec_capabilities_t;
typedef struct {
uint16_t cp_type;
uint16_t cp_type_value_len;
@ -292,7 +283,6 @@ typedef enum {
AVDTP_STREAM_ENDPOINT_OPENED,
AVDTP_STREAM_ENDPOINT_STREAMING,
AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND,
AVDTP_STREAM_ENDPOINT_CLOSING,
AVDTP_STREAM_ENDPOINT_ABORTING,
@ -307,8 +297,6 @@ typedef enum {
AVDTP_INITIATOR_W2_OPEN_STREAM,
AVDTP_INITIATOR_W2_STREAMING_START,
AVDTP_INITIATOR_W2_STREAMING_STOP,
AVDTP_INITIATOR_W2_STREAMING_ABORT,
AVDTP_INITIATOR_FRAGMENTATED_COMMAND,
AVDTP_INITIATOR_W4_ANSWER
@ -349,6 +337,7 @@ typedef struct {
typedef enum {
AVDTP_SIGNALING_CONNECTION_IDLE,
AVDTP_SIGNALING_W4_SDP_QUERY_COMPLETE,
AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED,
AVDTP_SIGNALING_CONNECTION_OPENED,
AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED
@ -389,6 +378,7 @@ typedef struct {
bd_addr_t remote_addr;
hci_con_handle_t con_handle;
uint16_t l2cap_signaling_cid;
avdtp_service_mode_t service_mode;
@ -408,9 +398,6 @@ typedef struct {
uint8_t int_seid;
uint8_t acp_seid;
avdtp_capabilities_t remote_capabilities;
uint16_t remote_capabilities_bitmap;
uint8_t wait_to_send_acceptor;
uint8_t wait_to_send_initiator;
uint8_t wait_to_send_self;
@ -421,14 +408,38 @@ typedef struct {
uint8_t reject_service_category;
avdtp_signal_identifier_t reject_signal_identifier;
uint8_t error_code;
// store configurations with remote seps
avdtp_sep_t remote_seps[MAX_NUM_SEPS];
uint8_t remote_seps_num;
} avdtp_connection_t;
typedef enum {
A2DP_IDLE,
A2DP_CONNECTED,
A2DP_W2_DISCOVER_SEPS,
A2DP_W2_GET_CAPABILITIES,
A2DP_W2_GET_ALL_CAPABILITIES,
A2DP_W2_SET_CONFIGURATION,
A2DP_W4_GET_CONFIGURATION,
A2DP_W4_SET_CONFIGURATION,
A2DP_W2_SUSPEND_STREAM_WITH_SEID,
A2DP_W2_RECONFIGURE_WITH_SEID,
A2DP_W2_OPEN_STREAM_WITH_SEID,
A2DP_W4_OPEN_STREAM_WITH_SEID,
A2DP_W2_START_STREAM_WITH_SEID,
A2DP_W2_ABORT_STREAM_WITH_SEID,
A2DP_W2_STOP_STREAM_WITH_SEID,
A2DP_W2_GET_CONFIGURATION,
A2DP_STREAMING_OPENED
} a2dp_state_t;
typedef struct avdtp_stream_endpoint {
btstack_linked_item_t item;
// original capabilities
avdtp_sep_t sep;
hci_con_handle_t media_con_handle;
uint16_t l2cap_media_cid;
uint16_t l2cap_reporting_cid;
uint16_t l2cap_recovery_cid;
@ -436,27 +447,26 @@ typedef struct avdtp_stream_endpoint {
avdtp_stream_endpoint_state_t state;
avdtp_acceptor_stream_endpoint_state_t acceptor_config_state;
avdtp_initiator_stream_endpoint_state_t initiator_config_state;
a2dp_state_t a2dp_state;
// active connection
avdtp_connection_t * connection;
// store configurations with remote seps
avdtp_sep_t remote_seps[MAX_NUM_SEPS];
uint8_t remote_seps_num;
// currently active remote seid
uint8_t remote_sep_index;
avdtp_capabilities_t remote_capabilities;
uint16_t remote_capabilities_bitmap;
uint16_t remote_configuration_bitmap;
avdtp_capabilities_t remote_configuration;
// register request for media L2cap connection release
uint8_t media_disconnect;
uint8_t media_connect;
btstack_timer_source_t fill_audio_ring_buffer_timer;
uint32_t time_audio_data_sent; // ms
uint32_t acc_num_missed_samples;
btstack_sbc_encoder_state_t sbc_encoder_state;
uint16_t sequence_number;
uint8_t start_stream;
uint8_t stop_stream;
uint8_t send_stream;
uint8_t abort_stream;
uint8_t suspend_stream;
btstack_ring_buffer_t audio_ring_buffer;
btstack_ring_buffer_t sbc_ring_buffer;
uint16_t sequence_number;
} avdtp_stream_endpoint_t;
typedef struct {
@ -464,6 +474,7 @@ typedef struct {
btstack_linked_list_t stream_endpoints;
uint16_t stream_endpoints_id_counter;
btstack_packet_handler_t avdtp_callback;
btstack_packet_handler_t a2dp_callback;
void (*handle_media_data)(avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size);
btstack_packet_handler_t packet_handler;
} avdtp_context_t;
@ -474,7 +485,7 @@ void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_en
void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets);
void avdtp_register_content_protection_category(avdtp_stream_endpoint_t * stream_endpoint, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len);
void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery);
void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation);
void avdtp_handle_can_send_now(avdtp_connection_t * connection, uint16_t l2cap_cid, avdtp_context_t * context);
@ -482,21 +493,34 @@ void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet
avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, avdtp_context_t * context);
avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type, avdtp_context_t * context);
void avdtp_disconnect(uint16_t con_handle, avdtp_context_t * context);
void avdtp_open_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_start_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_stop_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_abort_stream(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_discover_stream_endpoints(uint16_t con_handle, avdtp_context_t * context);
void avdtp_get_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_get_configuration(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context);
void avdtp_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context);
void avdtp_suspend(uint16_t con_handle, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_connect(bd_addr_t remote, avdtp_sep_type_t query_role, avdtp_context_t * context);
void avdtp_disconnect(uint16_t avdtp_cid, avdtp_context_t * context);
void avdtp_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_start_stream(uint8_t int_seid, avdtp_context_t * context);
void avdtp_stop_stream (uint8_t int_seid, avdtp_context_t * context);
void avdtp_abort_stream(uint8_t int_seid, avdtp_context_t * context);
void avdtp_suspend_stream(uint8_t int_seid, avdtp_context_t * context);
void avdtp_source_stream_data_start(uint16_t con_handle);
void avdtp_source_stream_data_stop(uint16_t con_handle);
void avdtp_discover_stream_endpoints(uint16_t avdtp_cid, avdtp_context_t * context);
void avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid, avdtp_context_t * context);
void avdtp_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context);
void avdtp_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration, avdtp_context_t * context);
uint8_t avdtp_remote_seps_num(uint16_t avdtp_cid, avdtp_context_t * context);
avdtp_sep_t * avdtp_remote_sep(uint16_t avdtp_cid, uint8_t index, avdtp_context_t * context);
void avdtp_initialize_sbc_configuration_storage(avdtp_stream_endpoint_t * stream_endpoint, uint8_t * config_storage, uint16_t storage_size, uint8_t * packet, uint16_t packet_size);
uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap);
uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap);
uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap);
uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap);
uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap);
uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value);
uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value);
uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint);
#if defined __cplusplus
}

View File

@ -86,7 +86,7 @@ static int avdtp_acceptor_validate_msg_length(avdtp_signal_identifier_t signal_i
void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t * packet, uint16_t size, int offset, avdtp_context_t * context){
avdtp_stream_endpoint_t * stream_endpoint;
connection->acceptor_transaction_label = connection->signaling_packet.transaction_label;
if (!avdtp_acceptor_validate_msg_length(connection->signaling_packet.signal_identifier, size)) {
connection->error_code = BAD_LENGTH;
connection->acceptor_connection_state = AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_REJECT_WITH_ERROR_CODE;
@ -98,7 +98,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
switch (connection->signaling_packet.signal_identifier){
case AVDTP_SI_DISCOVER:
if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) return;
printf(" ACP: AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS\n");
log_info(" ACP: AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS");
connection->acceptor_connection_state = AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_ANSWER_DISCOVER_SEPS;
avdtp_request_can_send_now_acceptor(connection, connection->l2cap_signaling_cid);
return;
@ -114,7 +114,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
connection->query_seid = packet[offset++] >> 2;
stream_endpoint = avdtp_stream_endpoint_with_seid(connection->query_seid, context);
if (!stream_endpoint){
printf(" ACP: cmd %d - RESPONSE REJECT\n", connection->signaling_packet.signal_identifier);
log_info(" ACP: cmd %d - RESPONSE REJECT", connection->signaling_packet.signal_identifier);
connection->error_code = BAD_ACP_SEID;
if (connection->signaling_packet.signal_identifier == AVDTP_SI_OPEN){
connection->error_code = BAD_STATE;
@ -133,18 +133,18 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
case AVDTP_SI_SUSPEND:{
int i;
printf(" ACP: AVDTP_SI_SUSPEND seids: ");
log_info(" ACP: AVDTP_SI_SUSPEND seids: ");
connection->num_suspended_seids = 0;
for (i = offset; i < size; i++){
connection->suspended_seids[connection->num_suspended_seids] = packet[i] >> 2;
offset++;
printf("%d, \n", connection->suspended_seids[connection->num_suspended_seids]);
log_info("%d, ", connection->suspended_seids[connection->num_suspended_seids]);
connection->num_suspended_seids++;
}
if (connection->num_suspended_seids == 0) {
printf(" ACP: CATEGORY RESPONSE REJECT BAD_ACP_SEID\n");
log_info(" ACP: CATEGORY RESPONSE REJECT BAD_ACP_SEID");
connection->error_code = BAD_ACP_SEID;
connection->reject_service_category = connection->query_seid;
connection->acceptor_connection_state = AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
@ -156,7 +156,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
connection->query_seid = connection->suspended_seids[0];
stream_endpoint = avdtp_stream_endpoint_with_seid(connection->query_seid, context);
if (!stream_endpoint){
printf(" ACP: stream_endpoint not found, CATEGORY RESPONSE REJECT BAD_ACP_SEID\n");
log_info(" ACP: stream_endpoint not found, CATEGORY RESPONSE REJECT BAD_ACP_SEID");
connection->error_code = BAD_ACP_SEID;
connection->reject_service_category = connection->query_seid;
connection->acceptor_connection_state = AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
@ -170,7 +170,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
default:
connection->acceptor_connection_state = AVDTP_SIGNALING_CONNECTION_ACCEPTOR_W2_GENERAL_REJECT_WITH_ERROR_CODE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
printf("AVDTP_CMD_MSG signal %d not implemented, general reject\n", connection->signaling_packet.signal_identifier);
log_info("AVDTP_CMD_MSG signal %d not implemented, general reject", connection->signaling_packet.signal_identifier);
avdtp_request_can_send_now_acceptor(connection, connection->l2cap_signaling_cid);
return;
}
@ -189,45 +189,41 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
case AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE:
switch (connection->signaling_packet.signal_identifier){
case AVDTP_SI_GET_ALL_CAPABILITIES:
printf(" ACP: AVDTP_SI_GET_ALL_CAPABILITIES\n");
log_info(" ACP: AVDTP_SI_GET_ALL_CAPABILITIES");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_GET_ALL_CAPABILITIES;
break;
case AVDTP_SI_GET_CAPABILITIES:
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_GET_CAPABILITIES;
break;
case AVDTP_SI_SET_CONFIGURATION:{
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION \n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION ");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION;
connection->reject_service_category = 0;
stream_endpoint->connection = connection;
avdtp_sep_t sep;
sep.seid = connection->signaling_packet.command[offset++] >> 2;
sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+offset, packet_size-offset);
sep.in_use = 1;
if (connection->error_code){
printf("fire configuration parsing errors \n");
log_info("fire configuration parsing errors ");
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
break;
}
// find or add sep
int i;
stream_endpoint->remote_sep_index = AVDTP_INVALID_SEP_INDEX;
for (i=0; i < stream_endpoint->remote_seps_num; i++){
if (stream_endpoint->remote_seps[i].seid == sep.seid){
stream_endpoint->remote_sep_index = i;
}
}
printf(" ACP .. seid %d, index %d\n", sep.seid, stream_endpoint->remote_sep_index);
stream_endpoint->remote_sep_index = avdtp_find_remote_sep(stream_endpoint->connection, sep.seid);
log_info(" ACP .. seid %d, index %d", sep.seid, stream_endpoint->remote_sep_index);
if (stream_endpoint->remote_sep_index != AVDTP_INVALID_SEP_INDEX){
if (stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].in_use){
if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].in_use){
// reject if already configured
connection->error_code = SEP_IN_USE;
// find first registered category and fire the error
connection->reject_service_category = 0;
int i;
for (i = 1; i < 9; i++){
if (get_bit16(sep.configured_service_categories, i)){
connection->reject_service_category = i;
@ -237,29 +233,28 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
} else {
stream_endpoint->remote_seps[stream_endpoint->remote_sep_index] = sep;
printf(" ACP: update seid %d, to %p\n", stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
log_info(" ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
}
} else {
// add new
printf(" ACP: seid %d not found in %p\n", sep.seid, stream_endpoint);
stream_endpoint->remote_sep_index = stream_endpoint->remote_seps_num;
stream_endpoint->remote_seps_num++;
stream_endpoint->remote_seps[stream_endpoint->remote_sep_index] = sep;
printf(" ACP: add seid %d, to %p\n", stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
log_info(" ACP: seid %d not found in %p", sep.seid, stream_endpoint);
stream_endpoint->remote_sep_index = connection->remote_seps_num;
connection->remote_seps_num++;
connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
log_info(" ACP: add seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
}
if (get_bit16(sep.configured_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.configuration.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->con_handle, sep.configuration.media_codec);
avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->acp_seid, sep.configuration.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->con_handle, sep.configuration.media_codec);
avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->acp_seid, sep.configuration.media_codec);
break;
}
}
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier, 0);
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->signaling_packet.signal_identifier, 0);
break;
}
case AVDTP_SI_RECONFIGURE:{
@ -268,8 +263,8 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
avdtp_sep_t sep;
sep.seid = connection->query_seid;
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_RECONFIGURE seid %d\n", sep.seid);
// printf_hexdump(connection->signaling_packet.command, packet_size);
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_RECONFIGURE seid %d", sep.seid);
// log_info_hexdump(connection->signaling_packet.command, packet_size);
sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+offset, packet_size-offset);
@ -281,76 +276,70 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
}
// find sep or raise error
int i;
stream_endpoint->remote_sep_index = AVDTP_INVALID_SEP_INDEX;
for (i = 0; i < stream_endpoint->remote_seps_num; i++){
if (stream_endpoint->remote_seps[i].seid == sep.seid){
stream_endpoint->remote_sep_index = i;
}
}
stream_endpoint->remote_sep_index = avdtp_find_remote_sep(stream_endpoint->connection, sep.seid);
if (stream_endpoint->remote_sep_index == AVDTP_INVALID_SEP_INDEX){
printf(" ACP: REJECT AVDTP_SI_RECONFIGURE, BAD_ACP_SEID\n");
log_info(" ACP: REJECT AVDTP_SI_RECONFIGURE, BAD_ACP_SEID");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
connection->error_code = BAD_ACP_SEID;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
break;
}
stream_endpoint->remote_seps[stream_endpoint->remote_sep_index] = sep;
printf(" ACP: update seid %d, to %p\n", stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
log_info(" ACP: update seid %d, to %p", stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
if (get_bit16(sep.configured_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.capabilities.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_reconfiguration(context->avdtp_callback, connection->con_handle, sep.capabilities.media_codec);
avdtp_signaling_emit_media_codec_sbc_reconfiguration(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->acp_seid, sep.capabilities.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_reconfiguration(context->avdtp_callback, connection->con_handle, sep.capabilities.media_codec);
avdtp_signaling_emit_media_codec_other_reconfiguration(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->acp_seid, sep.capabilities.media_codec);
break;
}
}
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier, 0);
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->signaling_packet.signal_identifier, 0);
break;
}
case AVDTP_SI_GET_CONFIGURATION:
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_GET_CONFIGURATION\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_GET_CONFIGURATION");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_GET_CONFIGURATION;
break;
case AVDTP_SI_OPEN:
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_CONFIGURED){
printf(" ACP: REJECT AVDTP_SI_OPEN, BAD_STATE\n");
log_info(" ACP: REJECT AVDTP_SI_OPEN, BAD_STATE");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_WITH_ERROR_CODE;
connection->error_code = BAD_STATE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
break;
}
printf(" ACP: AVDTP_STREAM_ENDPOINT_W2_ANSWER_OPEN_STREAM\n");
log_info(" ACP: AVDTP_STREAM_ENDPOINT_W2_ANSWER_OPEN_STREAM");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_OPEN_STREAM;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED;
connection->query_seid = stream_endpoint->sep.seid;
break;
case AVDTP_SI_START:
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_OPENED){
printf(" ACP: REJECT AVDTP_SI_START, BAD_STATE\n");
log_info(" ACP: REJECT AVDTP_SI_START, BAD_STATE");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
connection->error_code = BAD_STATE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
break;
}
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_START_STREAM\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_START_STREAM");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_START_STREAM;
break;
case AVDTP_SI_CLOSE:
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_CLOSE_STREAM\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_CLOSE_STREAM");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CLOSING;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_CLOSE_STREAM;
break;
default:
printf(" ACP: AVDTP_SI_CLOSE, bad state %d \n", stream_endpoint->state);
log_info(" ACP: AVDTP_SI_CLOSE, bad state %d ", stream_endpoint->state);
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_WITH_ERROR_CODE;
connection->error_code = BAD_STATE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
@ -363,12 +352,12 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
case AVDTP_STREAM_ENDPOINT_CLOSING:
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_ABORT_STREAM\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_ABORT_STREAM");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_ABORT_STREAM;
break;
default:
printf(" ACP: AVDTP_SI_ABORT, bad state %d \n", stream_endpoint->state);
log_info(" ACP: AVDTP_SI_ABORT, bad state %d ", stream_endpoint->state);
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_WITH_ERROR_CODE;
connection->error_code = BAD_STATE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
@ -376,19 +365,19 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
}
break;
case AVDTP_SI_SUSPEND:
printf(" entering AVDTP_SI_SUSPEND\n");
log_info(" entering AVDTP_SI_SUSPEND");
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
connection->num_suspended_seids--;
if (connection->num_suspended_seids <= 0){
printf(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_SUSPEND_STREAM\n");
log_info(" ACP: AVDTP_ACCEPTOR_W2_ANSWER_SUSPEND_STREAM");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ANSWER_SUSPEND_STREAM;
}
break;
default:
printf(" ACP: AVDTP_SI_SUSPEND, bad state \n");
log_info(" ACP: AVDTP_SI_SUSPEND, bad state ");
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE;
connection->error_code = BAD_STATE;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
@ -399,7 +388,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
//stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_SUSPEND_STREAM;
break;
default:
printf(" ACP: NOT IMPLEMENTED, Reject signal_identifier %02x\n", connection->signaling_packet.signal_identifier);
log_info(" ACP: NOT IMPLEMENTED, Reject signal_identifier %02x", connection->signaling_packet.signal_identifier);
stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_UNKNOWN_CMD;
connection->reject_signal_identifier = connection->signaling_packet.signal_identifier;
break;
@ -410,7 +399,7 @@ void avdtp_acceptor_stream_config_subsm(avdtp_connection_t * connection, uint8_t
}
if (!request_to_send){
printf(" ACP: NOT IMPLEMENTED\n");
log_info(" ACP: NOT IMPLEMENTED");
}
avdtp_request_can_send_now_acceptor(connection, connection->l2cap_signaling_cid);
}
@ -488,7 +477,7 @@ void avdtp_acceptor_stream_config_subsm_run(avdtp_connection_t * connection, avd
break;
}
if (sent){
printf(" ACP: DONE\n");
log_info(" ACP: DONE");
return;
}
@ -517,9 +506,9 @@ void avdtp_acceptor_stream_config_subsm_run(avdtp_connection_t * connection, avd
pos = avdtp_signaling_create_fragment(cid, &connection->signaling_packet, out_buffer);
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
stream_endpoint->acceptor_config_state = acceptor_config_state;
printf(" ACP: fragmented\n");
log_info(" ACP: fragmented");
} else {
printf(" ACP:DONE\n");
log_info(" ACP:DONE");
}
l2cap_send_prepared(cid, pos);
break;
@ -530,92 +519,89 @@ void avdtp_acceptor_stream_config_subsm_run(avdtp_connection_t * connection, avd
pos = avdtp_signaling_create_fragment(cid, &connection->signaling_packet, out_buffer);
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
stream_endpoint->acceptor_config_state = acceptor_config_state;
printf(" ACP: fragmented\n");
log_info(" ACP: fragmented");
} else {
printf(" ACP:DONE\n");
log_info(" ACP:DONE");
}
l2cap_send_prepared(cid, pos);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_SET_CONFIGURATION:
printf(" ACP: DONE\n");
printf(" -> AVDTP_STREAM_ENDPOINT_CONFIGURED\n");
log_info(" ACP: DONE");
log_info(" -> AVDTP_STREAM_ENDPOINT_CONFIGURED");
stream_endpoint->connection = connection;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
// TODO: use actual config
// TODO: consider reconfiguration
btstack_sbc_encoder_init(&stream_endpoint->sbc_encoder_state, SBC_MODE_STANDARD, 16, 8, 2, 44100, 53);
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_SET_CONFIGURATION);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_RECONFIGURE:
printf(" ACP: DONE \n");
log_info(" ACP: DONE ");
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_RECONFIGURE);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_GET_CONFIGURATION:{
avdtp_sep_t sep = stream_endpoint->remote_seps[stream_endpoint->remote_sep_index];
avdtp_sep_t sep = stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index];
avdtp_prepare_capabilities(&connection->signaling_packet, trid, sep.configured_service_categories, sep.configuration, AVDTP_SI_GET_CONFIGURATION);
l2cap_reserve_packet_buffer();
out_buffer = l2cap_get_outgoing_buffer();
pos = avdtp_signaling_create_fragment(cid, &connection->signaling_packet, out_buffer);
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
stream_endpoint->acceptor_config_state = acceptor_config_state;
printf(" ACP: fragmented\n");
log_info(" ACP: fragmented");
} else {
printf(" ACP:DONE\n");
log_info(" ACP:DONE");
}
l2cap_send_prepared(cid, pos);
break;
}
case AVDTP_ACCEPTOR_W2_ANSWER_OPEN_STREAM:
printf(" ACP: DONE\n");
log_info(" ACP: DONE");
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_OPEN);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_START_STREAM:
printf(" ACP: DONE \n");
printf(" -> AVDTP_STREAM_ENDPOINT_STREAMING \n");
log_info(" ACP: DONE ");
log_info(" -> AVDTP_STREAM_ENDPOINT_STREAMING ");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_START);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_CLOSE_STREAM:
printf(" ACP: DONE\n");
log_info(" ACP: DONE");
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_CLOSE);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_ABORT_STREAM:
printf(" ACP: DONE\n");
log_info(" ACP: DONE");
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_ABORT);
break;
case AVDTP_ACCEPTOR_W2_ANSWER_SUSPEND_STREAM:
printf(" ACP: DONE\n");
log_info(" ACP: DONE");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
avdtp_acceptor_send_accept_response(cid, trid, AVDTP_SI_SUSPEND);
break;
case AVDTP_ACCEPTOR_W2_REJECT_UNKNOWN_CMD:
status = 1;
printf(" ACP: DONE REJECT\n");
log_info(" ACP: DONE REJECT");
connection->reject_signal_identifier = 0;
avdtp_acceptor_send_response_reject(cid, reject_signal_identifier, trid);
break;
case AVDTP_ACCEPTOR_W2_REJECT_CATEGORY_WITH_ERROR_CODE:
status = 1;
printf(" ACP: DONE REJECT CATEGORY\n");
log_info(" ACP: DONE REJECT CATEGORY");
connection->reject_service_category = 0;
avdtp_acceptor_send_response_reject_service_category(cid, reject_signal_identifier, reject_service_category, error_code, trid);
break;
case AVDTP_ACCEPTOR_W2_REJECT_WITH_ERROR_CODE:
status = 1;
printf(" ACP: DONE REJECT\n");
log_info(" ACP: DONE REJECT");
connection->reject_signal_identifier = 0;
connection->error_code = 0;
avdtp_acceptor_send_response_reject_with_error_code(cid, reject_signal_identifier, error_code, trid);
break;
default:
status = 0;
printf(" ACP: NOT IMPLEMENTED\n");
log_info(" ACP: NOT IMPLEMENTED");
sent = 0;
}
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier, status);
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->int_seid, connection->signaling_packet.signal_identifier, status);
// check fragmentation
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){

View File

@ -65,32 +65,6 @@ static int avdtp_initiator_send_signaling_cmd_with_seid(uint16_t cid, avdtp_sign
return l2cap_send(cid, command, sizeof(command));
}
static void avdtp_signaling_emit_media_codec_capability(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_sep_t sep){
if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.capabilities.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_capability(callback, con_handle, sep.capabilities.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_capability(callback, con_handle, sep.capabilities.media_codec);
break;
}
}
}
static void avdtp_signaling_emit_media_codec_configuration(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_sep_t sep){
if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.capabilities.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_configuration(callback, con_handle, sep.capabilities.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_configuration(callback, con_handle, sep.capabilities.media_codec);
break;
}
}
}
void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_t *packet, uint16_t size, int offset, avdtp_context_t * context){
int status = 0;
avdtp_stream_endpoint_t * stream_endpoint = NULL;
@ -107,25 +81,23 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_
if (!stream_endpoint) return;
sep.seid = connection->acp_seid;
printf(" INT: local seid %d, remote seid %d, ident %d \n", connection->int_seid, connection->acp_seid, connection->signaling_packet.signal_identifier);
if (stream_endpoint->initiator_config_state != AVDTP_INITIATOR_W4_ANSWER) return;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
}
switch (connection->signaling_packet.message_type){
case AVDTP_RESPONSE_ACCEPT_MSG:
printf(" INT: AVDTP_RESPONSE_ACCEPT_MSG: ");
switch (connection->signaling_packet.signal_identifier){
case AVDTP_SI_DISCOVER:{
printf("AVDTP_SI_DISCOVER\n");
log_info("AVDTP_SI_DISCOVER");
if (connection->signaling_packet.transaction_label != connection->initiator_transaction_label){
printf(" unexpected transaction label, got %d, expected %d\n", connection->signaling_packet.transaction_label, connection->initiator_transaction_label);
log_info(" unexpected transaction label, got %d, expected %d", connection->signaling_packet.transaction_label, connection->initiator_transaction_label);
status = BAD_HEADER_FORMAT;
break;
}
if (size == 3){
printf(" ERROR code %02x\n", packet[offset]);
log_info(" ERROR code %02x", packet[offset]);
status = packet[offset];
break;
}
@ -135,73 +107,90 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_
sep.seid = packet[i] >> 2;
offset++;
if (sep.seid < 0x01 || sep.seid > 0x3E){
printf(" invalid sep id\n");
log_info(" invalid sep id");
status = BAD_ACP_SEID;
break;
}
sep.in_use = (packet[i] >> 1) & 0x01;
sep.media_type = (avdtp_media_type_t)(packet[i+1] >> 4);
sep.type = (avdtp_sep_type_t)((packet[i+1] >> 3) & 0x01);
avdtp_signaling_emit_sep(context->avdtp_callback, connection->con_handle, sep);
if (avdtp_find_remote_sep(connection, sep.seid) == 0xFF){
connection->remote_seps[connection->remote_seps_num++] = sep;
}
avdtp_signaling_emit_sep(context->avdtp_callback, connection->l2cap_signaling_cid, sep);
}
break;
}
case AVDTP_SI_GET_CAPABILITIES:
case AVDTP_SI_GET_ALL_CAPABILITIES:
printf("AVDTP_SI_GET(_ALL)_CAPABILITIES\n");
log_info("AVDTP_SI_GET(_ALL)_CAPABILITIES int %d, acp %d", connection->int_seid, connection->acp_seid);
sep.registered_service_categories = avdtp_unpack_service_capabilities(connection, &sep.capabilities, packet+offset, size-offset);
avdtp_signaling_emit_media_codec_capability(context->avdtp_callback, connection->con_handle, sep);
if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.capabilities.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_capability(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->acp_seid, sep.capabilities.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_capability(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->acp_seid, sep.capabilities.media_codec);
break;
}
}
break;
case AVDTP_SI_GET_CONFIGURATION:
printf("AVDTP_SI_GET_CONFIGURATION\n");
log_info("AVDTP_SI_GET_CONFIGURATION");
sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, packet+offset, size-offset);
avdtp_signaling_emit_media_codec_configuration(context->avdtp_callback, connection->con_handle, sep);
if (get_bit16(sep.configured_service_categories, AVDTP_MEDIA_CODEC)){
switch (sep.configuration.media_codec.media_codec_type){
case AVDTP_CODEC_SBC:
avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->acp_seid, sep.configuration.media_codec);
break;
default:
avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->acp_seid, sep.configuration.media_codec);
break;
}
}
break;
case AVDTP_SI_RECONFIGURE:
printf("AVDTP_SI_RECONFIGURE\n");
log_info("AVDTP_SI_RECONFIGURE");
sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+4, connection->signaling_packet.size-4);
// TODO check if configuration is supported
remote_sep_index = avdtp_get_index_of_remote_stream_endpoint_with_seid(stream_endpoint, sep.seid);
remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
if (remote_sep_index != 0xFF){
stream_endpoint->remote_sep_index = remote_sep_index;
stream_endpoint->remote_seps[stream_endpoint->remote_sep_index] = sep;
connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
printf(" INT: update seid %d, to %p\n", stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
log_info(" INT: update seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
}
break;
case AVDTP_SI_SET_CONFIGURATION:{
printf("AVDTP_SI_SET_CONFIGURATION\n");
sep.configured_service_categories = connection->remote_capabilities_bitmap;
sep.configuration = connection->remote_capabilities;
log_info("AVDTP_SI_SET_CONFIGURATION");
sep.configured_service_categories = stream_endpoint->remote_capabilities_bitmap;
sep.configuration = stream_endpoint->remote_capabilities;
sep.in_use = 1;
// TODO check if configuration is supported
// find or add sep
remote_sep_index = avdtp_get_index_of_remote_stream_endpoint_with_seid(stream_endpoint, sep.seid);
remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
if (remote_sep_index != 0xFF){
stream_endpoint->remote_sep_index = remote_sep_index;
} else {
stream_endpoint->remote_sep_index = stream_endpoint->remote_seps_num;
stream_endpoint->remote_seps_num++;
stream_endpoint->remote_sep_index = connection->remote_seps_num;
stream_endpoint->connection->remote_seps_num++;
}
stream_endpoint->remote_seps[stream_endpoint->remote_sep_index] = sep;
printf(" INT: configured remote seid %d, to %p\n", stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
log_info(" INT: configured remote seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
// TODO: use actual config
// TODO: consider reconfiguration
btstack_sbc_encoder_init(&stream_endpoint->sbc_encoder_state, SBC_MODE_STANDARD, 16, 8, 2, 44100, 53);
break;
}
case AVDTP_SI_OPEN:
printf("AVDTP_SI_OPEN\n");
log_info("AVDTP_SI_OPEN");
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM) {
log_error("AVDTP_SI_OPEN in wrong stream endpoint state");
return;
@ -211,15 +200,16 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_
l2cap_create_channel(context->packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL);
return;
case AVDTP_SI_START:
printf("AVDTP_SI_START\n");
log_info("AVDTP_SI_START");
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_OPENED) {
log_error("AVDTP_SI_START in wrong stream endpoint state");
return;
}
log_info("AVDTP_STREAM_ENDPOINT_STREAMING");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
break;
case AVDTP_SI_SUSPEND:
printf("AVDTP_SI_SUSPEND\n");
log_info("AVDTP_SI_SUSPEND");
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING) {
log_error("AVDTP_SI_SUSPEND in wrong stream endpoint state");
return;
@ -227,58 +217,54 @@ void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
break;
case AVDTP_SI_CLOSE:
printf("AVDTP_SI_CLOSE\n");
log_info("AVDTP_SI_CLOSE");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CLOSING;
break;
case AVDTP_SI_ABORT:
printf("AVDTP_SI_ABORT\n");
log_info("AVDTP_SI_ABORT");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
break;
default:
status = 1;
printf(" AVDTP_RESPONSE_ACCEPT_MSG, signal %d not implemented\n", connection->signaling_packet.signal_identifier);
log_info(" AVDTP_RESPONSE_ACCEPT_MSG, signal %d not implemented", connection->signaling_packet.signal_identifier);
break;
}
}
avdtp_signaling_emit_accept(context->avdtp_callback, connection->l2cap_signaling_cid, 0, connection->signaling_packet.signal_identifier, status);
connection->initiator_transaction_label++;
break;
case AVDTP_RESPONSE_REJECT_MSG:
printf(" AVDTP_RESPONSE_REJECT_MSG signal %d\n", connection->signaling_packet.signal_identifier);
avdtp_signaling_emit_reject(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier);
log_info(" AVDTP_RESPONSE_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
avdtp_signaling_emit_reject(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->signaling_packet.signal_identifier);
return;
case AVDTP_GENERAL_REJECT_MSG:
printf(" AVDTP_GENERAL_REJECT_MSG signal %d\n", connection->signaling_packet.signal_identifier);
avdtp_signaling_emit_general_reject(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier);
log_info(" AVDTP_GENERAL_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
avdtp_signaling_emit_general_reject(context->avdtp_callback, connection->l2cap_signaling_cid, connection->int_seid, connection->signaling_packet.signal_identifier);
return;
default:
break;
}
connection->initiator_transaction_label++;
connection->int_seid = 0;
connection->acp_seid = 0;
avdtp_signaling_emit_accept(context->avdtp_callback, connection->con_handle, connection->signaling_packet.signal_identifier, status);
}
void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, avdtp_context_t * context){
int sent = 1;
switch (connection->initiator_connection_state){
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS:
printf(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS\n");
log_info(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd(connection->l2cap_signaling_cid, AVDTP_SI_DISCOVER, connection->initiator_transaction_label);
break;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES:
printf(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES\n");
log_info(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_CAPABILITIES, connection->initiator_transaction_label, connection->acp_seid);
break;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES:
printf(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES\n");
log_info(" INT: AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_ALL_CAPABILITIES, connection->initiator_transaction_label, connection->acp_seid);
break;
case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION:
printf(" INT: AVDTP_INITIATOR_W4_GET_CONFIGURATION\n");
log_info(" INT: AVDTP_INITIATOR_W4_GET_CONFIGURATION");
connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_GET_CONFIGURATION, connection->initiator_transaction_label, connection->acp_seid);
break;
@ -289,9 +275,8 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av
if (sent) return;
sent = 1;
avdtp_stream_endpoint_t * stream_endpoint = NULL;
// printf(" run int seid %d, acp seid %d\n", connection->int_seid, connection->acp_seid);
avdtp_stream_endpoint_t * stream_endpoint = NULL;
stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(connection->acp_seid, context);
if (!stream_endpoint){
@ -301,12 +286,69 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av
avdtp_initiator_stream_endpoint_state_t stream_endpoint_state = stream_endpoint->initiator_config_state;
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W4_ANSWER;
if (stream_endpoint->start_stream){
stream_endpoint->start_stream = 0;
if (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_OPENED){
connection->int_seid = stream_endpoint->sep.seid;
connection->acp_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_START, connection->initiator_transaction_label++, connection->acp_seid);
return;
}
return;
}
if (stream_endpoint->stop_stream){
stream_endpoint->stop_stream = 0;
if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_OPENED){
connection->int_seid = stream_endpoint->sep.seid;
connection->acp_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_CLOSE, connection->initiator_transaction_label++, connection->acp_seid);
return;
}
}
if (stream_endpoint->abort_stream){
stream_endpoint->abort_stream = 0;
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_CONFIGURED:
case AVDTP_STREAM_ENDPOINT_CLOSING:
case AVDTP_STREAM_ENDPOINT_OPENED:
case AVDTP_STREAM_ENDPOINT_STREAMING:
connection->int_seid = stream_endpoint->sep.seid;
connection->acp_seid = connection->remote_seps[stream_endpoint->remote_sep_index].seid;
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_ABORT, connection->initiator_transaction_label++, connection->acp_seid);
return;
default:
break;
}
}
if (stream_endpoint->suspend_stream){
stream_endpoint->suspend_stream = 0;
if (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING){
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_SUSPEND, connection->initiator_transaction_label, connection->acp_seid);
return;
}
}
if (stream_endpoint->send_stream){
stream_endpoint->send_stream = 0;
if (stream_endpoint->state == AVDTP_STREAM_ENDPOINT_STREAMING){
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
avdtp_streaming_emit_can_send_media_packet_now(context->avdtp_callback, stream_endpoint->l2cap_media_cid, stream_endpoint->sep.seid, stream_endpoint->sequence_number);
return;
}
}
switch (stream_endpoint_state){
case AVDTP_INITIATOR_W2_SET_CONFIGURATION:
case AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID:{
printf(" INT: AVDTP_INITIATOR_W2_(RE)CONFIGURATION bitmap, int seid %d, acp seid %d\n", connection->int_seid, connection->acp_seid);
// printf_hexdump( connection->remote_capabilities.media_codec.media_codec_information, connection->remote_capabilities.media_codec.media_codec_information_len);
log_info(" INT: AVDTP_INITIATOR_W2_(RE)CONFIGURATION bitmap, int seid %d, acp seid %d", connection->int_seid, connection->acp_seid);
// log_info_hexdump( connection->remote_capabilities.media_codec.media_codec_information, connection->remote_capabilities.media_codec.media_codec_information_len);
connection->signaling_packet.acp_seid = connection->acp_seid;
connection->signaling_packet.int_seid = connection->int_seid;
@ -316,13 +358,13 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av
connection->signaling_packet.signal_identifier = AVDTP_SI_RECONFIGURE;
}
avdtp_prepare_capabilities(&connection->signaling_packet, connection->initiator_transaction_label, connection->remote_capabilities_bitmap, connection->remote_capabilities, connection->signaling_packet.signal_identifier);
avdtp_prepare_capabilities(&connection->signaling_packet, connection->initiator_transaction_label, stream_endpoint->remote_capabilities_bitmap, stream_endpoint->remote_capabilities, connection->signaling_packet.signal_identifier);
l2cap_reserve_packet_buffer();
uint8_t * out_buffer = l2cap_get_outgoing_buffer();
uint16_t pos = avdtp_signaling_create_fragment(connection->l2cap_signaling_cid, &connection->signaling_packet, out_buffer);
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_FRAGMENTATED_COMMAND;
printf(" INT: fragmented\n");
log_info(" INT: fragmented");
}
l2cap_send_prepared(connection->l2cap_signaling_cid, pos);
break;
@ -333,7 +375,7 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av
uint16_t pos = avdtp_signaling_create_fragment(connection->l2cap_signaling_cid, &connection->signaling_packet, out_buffer);
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_FRAGMENTATED_COMMAND;
printf(" INT: fragmented\n");
log_info(" INT: fragmented");
}
l2cap_send_prepared(connection->l2cap_signaling_cid, pos);
break;
@ -341,35 +383,19 @@ void avdtp_initiator_stream_config_subsm_run(avdtp_connection_t * connection, av
case AVDTP_INITIATOR_W2_OPEN_STREAM:
switch (stream_endpoint->state){
case AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM:
printf(" INT: AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM\n");
log_info(" INT: AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM");
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_OPEN, connection->initiator_transaction_label, connection->acp_seid);
break;
default:
sent = 0;
break;
}
break;
case AVDTP_INITIATOR_W2_SUSPEND_STREAM_WITH_SEID:
printf(" INT: AVDTP_INITIATOR_W4_SUSPEND_STREAM_WITH_SEID\n");
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_SUSPEND, connection->initiator_transaction_label, connection->acp_seid);
break;
case AVDTP_INITIATOR_W2_STREAMING_START:
printf(" INT: AVDTP_INITIATOR_W4_STREAMING_START\n");
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_START, connection->initiator_transaction_label, connection->acp_seid);
break;
case AVDTP_INITIATOR_W2_STREAMING_STOP:
printf(" INT: AVDTP_INITIATOR_W4_STREAMING_STOP\n");
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_CLOSE, connection->initiator_transaction_label, connection->acp_seid);
break;
case AVDTP_INITIATOR_W2_STREAMING_ABORT:
printf(" INT: AVDTP_INITIATOR_W4_STREAMING_ABORT\n");
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
avdtp_initiator_send_signaling_cmd_with_seid(connection->l2cap_signaling_cid, AVDTP_SI_ABORT, connection->initiator_transaction_label, connection->acp_seid);
break;
default:
sent = 0;
break;
}
// check fragmentation
if (connection->signaling_packet.packet_type != AVDTP_SINGLE_PACKET && connection->signaling_packet.packet_type != AVDTP_END_PACKET){
avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid);

View File

@ -37,7 +37,6 @@
#define __BTSTACK_FILE__ "avdtp_sink.c"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@ -51,95 +50,10 @@
#include "avdtp_initiator.h"
#include "avdtp_acceptor.h"
static const char * default_avdtp_sink_service_name = "BTstack AVDTP Sink Service";
static const char * default_avdtp_sink_service_provider_name = "BTstack AVDTP Sink Service Provider";
static avdtp_context_t avdtp_sink_context;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
//static void (*handle_media_data)(avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size);
void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name){
uint8_t* attribute;
de_create_sequence(service);
// 0x0000 "Service Record Handle"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
// 0x0001 "Service Class ID List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, AUDIO_SINK_GROUP);
}
de_pop_sequence(service, attribute);
// 0x0004 "Protocol Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t* l2cpProtocol = de_push_sequence(attribute);
{
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP);
}
de_pop_sequence(attribute, l2cpProtocol);
uint8_t* avProtocol = de_push_sequence(attribute);
{
de_add_number(avProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP); // avProtocol_service
de_add_number(avProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version
}
de_pop_sequence(attribute, avProtocol);
}
de_pop_sequence(service, attribute);
// 0x0005 "Public Browse Group"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
}
de_pop_sequence(service, attribute);
// 0x0009 "Bluetooth Profile Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t *a2dProfile = de_push_sequence(attribute);
{
de_add_number(a2dProfile, DE_UUID, DE_SIZE_16, ADVANCED_AUDIO_DISTRIBUTION);
de_add_number(a2dProfile, DE_UINT, DE_SIZE_16, 0x0103);
}
de_pop_sequence(attribute, a2dProfile);
}
de_pop_sequence(service, attribute);
// 0x0100 "Service Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
if (service_name){
de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name);
} else {
de_add_data(service, DE_STRING, strlen(default_avdtp_sink_service_name), (uint8_t *) default_avdtp_sink_service_name);
}
// 0x0100 "Provider Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102);
if (service_provider_name){
de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
} else {
de_add_data(service, DE_STRING, strlen(default_avdtp_sink_service_provider_name), (uint8_t *) default_avdtp_sink_service_provider_name);
}
// 0x0311 "Supported Features"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}
void avdtp_sink_register_media_transport_category(uint8_t seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_sink_context);
avdtp_register_media_transport_category(stream_endpoint);
@ -170,7 +84,7 @@ void avdtp_sink_register_header_compression_category(uint8_t seid, uint8_t back_
avdtp_register_header_compression_category(stream_endpoint, back_ch, media, recovery);
}
void avdtp_sink_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len){
void avdtp_sink_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_sink_context);
avdtp_register_media_codec_category(stream_endpoint, media_type, media_codec_type, media_codec_info, media_codec_info_len);
}
@ -198,7 +112,7 @@ void avdtp_sink_init(void){
avdtp_sink_context.stream_endpoints = NULL;
avdtp_sink_context.connections = NULL;
avdtp_sink_context.stream_endpoints_id_counter = 0;
// TODO: assign dummy handlers;
avdtp_sink_context.packet_handler = packet_handler;
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
}
@ -223,60 +137,55 @@ void avdtp_sink_register_packet_handler(btstack_packet_handler_t callback){
avdtp_sink_context.avdtp_callback = callback;
}
void avdtp_sink_connect(bd_addr_t bd_addr){
avdtp_connection_t * connection = avdtp_connection_for_bd_addr(bd_addr, &avdtp_sink_context);
if (!connection){
connection = avdtp_create_connection(bd_addr, &avdtp_sink_context);
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_IDLE) return;
connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
l2cap_create_channel(packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL);
void avdtp_sink_connect(bd_addr_t remote){
avdtp_connect(remote, AVDTP_SOURCE, &avdtp_sink_context);
}
void avdtp_sink_disconnect(uint16_t con_handle){
avdtp_disconnect(con_handle, &avdtp_sink_context);
void avdtp_sink_disconnect(uint16_t avdtp_cid){
avdtp_disconnect(avdtp_cid, &avdtp_sink_context);
}
void avdtp_sink_open_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_open_stream(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid){
avdtp_open_stream(avdtp_cid, int_seid, acp_seid, &avdtp_sink_context);
}
void avdtp_sink_start_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_start_stream(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_stop_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_stop_stream(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_stop_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_abort_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_abort_stream(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_abort_stream(uint8_t int_seid){
avdtp_abort_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_discover_stream_endpoints(uint16_t con_handle){
avdtp_discover_stream_endpoints(con_handle, &avdtp_sink_context);
void avdtp_sink_suspend(uint8_t int_seid){
avdtp_suspend_stream(int_seid, &avdtp_sink_context);
}
void avdtp_sink_get_capabilities(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_capabilities(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_discover_stream_endpoints(uint16_t avdtp_cid){
avdtp_discover_stream_endpoints(avdtp_cid, &avdtp_sink_context);
}
void avdtp_sink_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_all_capabilities(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid){
avdtp_get_capabilities(avdtp_cid, acp_seid, &avdtp_sink_context);
}
void avdtp_sink_get_configuration(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_configuration(con_handle, acp_seid, &avdtp_sink_context);
void avdtp_sink_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid){
avdtp_get_all_capabilities(avdtp_cid, acp_seid, &avdtp_sink_context);
}
void avdtp_sink_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_set_configuration(con_handle, int_seid, acp_seid, configured_services_bitmap, configuration, &avdtp_sink_context);
void avdtp_sink_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid){
avdtp_get_configuration(avdtp_cid, acp_seid, &avdtp_sink_context);
}
void avdtp_sink_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_reconfigure(con_handle, acp_seid, configured_services_bitmap, configuration, &avdtp_sink_context);
void avdtp_sink_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_set_configuration(avdtp_cid, int_seid, acp_seid, configured_services_bitmap, configuration, &avdtp_sink_context);
}
void avdtp_sink_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_reconfigure(avdtp_cid, int_seid, acp_seid, configured_services_bitmap, configuration, &avdtp_sink_context);
}
void avdtp_sink_suspend(uint16_t con_handle, uint8_t acp_seid){
avdtp_suspend(con_handle, acp_seid, &avdtp_sink_context);
}

View File

@ -55,15 +55,6 @@ extern "C" {
#endif
/* API_START */
/**
* @brief AVDTP Sink service record.
* @param service
* @param service_record_handle
* @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h
* @param service_name
* @param service_provider_name
*/
void a2dp_sink_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);
/**
* @brief Set up AVDTP Sink device.
@ -80,7 +71,7 @@ void avdtp_sink_register_recovery_category(uint8_t seid, uint8_t maximum_recover
void avdtp_sink_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery);
void avdtp_sink_register_multiplexing_category(uint8_t seid, uint8_t fragmentation);
void avdtp_sink_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_sink_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_sink_register_content_protection_category(uint8_t seid, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len);
/**
@ -98,82 +89,79 @@ void avdtp_sink_connect(bd_addr_t bd_addr);
void avdtp_sink_register_media_handler(void (*callback)(avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size));
/**
* @brief Disconnect from device with connection handle.
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_disconnect(uint16_t con_handle);
void avdtp_sink_disconnect(uint16_t avdtp_cid);
/**
* @brief Discover stream endpoints
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_discover_stream_endpoints(uint16_t con_handle);
void avdtp_sink_discover_stream_endpoints(uint16_t avdtp_cid);
/**
* @brief Get capabilities
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_get_capabilities(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Get all capabilities
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Set configuration
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
void avdtp_sink_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
/**
* @brief Reconfigure stream
* @param con_handle
* @param avdtp_cid
* @param seid
*/
void avdtp_sink_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
void avdtp_sink_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
/**
* @brief Get configuration
* @param con_handle
* @param avdtp_cid
*/
void avdtp_sink_get_configuration(uint16_t con_handle, uint8_t acp_seid);
/**
* @brief Suspend stream
* @param con_handle
* @param seid
*/
void avdtp_sink_suspend(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Open stream
* @param con_handle
* @param avdtp_cid
* @param seid
*/
void avdtp_sink_open_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_open_stream(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @param local_seid
*/
void avdtp_sink_start_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_start_stream(uint8_t local_seid);
/**
* @brief Abort stream
* @param local_seid
*/
void avdtp_sink_abort_stream(uint8_t local_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @param local_seid
*/
void avdtp_sink_abort_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_stop_stream(uint8_t local_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @brief Suspend stream
* @param local_seid
*/
void avdtp_sink_stop_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_sink_suspend(uint8_t local_seid);
/* API_END */

View File

@ -51,137 +51,52 @@
#include "avdtp_util.h"
#include "avdtp_source.h"
#include "btstack_ring_buffer.h"
static const char * default_avdtp_source_service_name = "BTstack AVDTP Source Service";
static const char * default_avdtp_source_service_provider_name = "BTstack AVDTP Source Service Provider";
static avdtp_context_t avdtp_source_context;
static avdtp_context_t * avdtp_source_context;
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name){
uint8_t* attribute;
de_create_sequence(service);
// 0x0000 "Service Record Handle"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
// 0x0001 "Service Class ID List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, AUDIO_SOURCE_GROUP);
}
de_pop_sequence(service, attribute);
// 0x0004 "Protocol Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t* l2cpProtocol = de_push_sequence(attribute);
{
de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP);
}
de_pop_sequence(attribute, l2cpProtocol);
uint8_t* avProtocol = de_push_sequence(attribute);
{
de_add_number(avProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP); // avProtocol_service
de_add_number(avProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version
}
de_pop_sequence(attribute, avProtocol);
}
de_pop_sequence(service, attribute);
// 0x0005 "Public Browse Group"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
attribute = de_push_sequence(service);
{
de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
}
de_pop_sequence(service, attribute);
// 0x0009 "Bluetooth Profile Descriptor List"
de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
attribute = de_push_sequence(service);
{
uint8_t *a2dProfile = de_push_sequence(attribute);
{
de_add_number(a2dProfile, DE_UUID, DE_SIZE_16, ADVANCED_AUDIO_DISTRIBUTION);
de_add_number(a2dProfile, DE_UINT, DE_SIZE_16, 0x0103);
}
de_pop_sequence(attribute, a2dProfile);
}
de_pop_sequence(service, attribute);
// 0x0100 "Service Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100);
if (service_name){
de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name);
} else {
de_add_data(service, DE_STRING, strlen(default_avdtp_source_service_name), (uint8_t *) default_avdtp_source_service_name);
}
// 0x0100 "Provider Name"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102);
if (service_provider_name){
de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
} else {
de_add_data(service, DE_STRING, strlen(default_avdtp_source_service_provider_name), (uint8_t *) default_avdtp_source_service_provider_name);
}
// 0x0311 "Supported Features"
de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
}
void avdtp_source_register_media_transport_category(uint8_t seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_media_transport_category(stream_endpoint);
}
void avdtp_source_register_reporting_category(uint8_t seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_reporting_category(stream_endpoint);
}
void avdtp_source_register_delay_reporting_category(uint8_t seid){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_delay_reporting_category(stream_endpoint);
}
void avdtp_source_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_recovery_category(stream_endpoint, maximum_recovery_window_size, maximum_number_media_packets);
}
void avdtp_source_register_content_protection_category(uint8_t seid, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_content_protection_category(stream_endpoint, cp_type, cp_type_value, cp_type_value_len);
}
void avdtp_source_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_header_compression_category(stream_endpoint, back_ch, media, recovery);
}
void avdtp_source_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
void avdtp_source_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_media_codec_category(stream_endpoint, media_type, media_codec_type, media_codec_info, media_codec_info_len);
}
void avdtp_source_register_multiplexing_category(uint8_t seid, uint8_t fragmentation){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, &avdtp_source_context);
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_seid(seid, avdtp_source_context);
avdtp_register_multiplexing_category(stream_endpoint, fragmentation);
}
avdtp_stream_endpoint_t * avdtp_source_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
return avdtp_create_stream_endpoint(sep_type, media_type, &avdtp_source_context);
return avdtp_create_stream_endpoint(sep_type, media_type, avdtp_source_context);
}
void avdtp_source_register_packet_handler(btstack_packet_handler_t callback){
@ -189,232 +104,83 @@ void avdtp_source_register_packet_handler(btstack_packet_handler_t callback){
log_error("avdtp_source_register_packet_handler called with NULL callback");
return;
}
avdtp_source_context.avdtp_callback = callback;
avdtp_source_context->avdtp_callback = callback;
}
void avdtp_source_connect(bd_addr_t bd_addr){
avdtp_connection_t * connection = avdtp_connection_for_bd_addr(bd_addr, &avdtp_source_context);
if (!connection){
connection = avdtp_create_connection(bd_addr, &avdtp_source_context);
}
if (connection->state != AVDTP_SIGNALING_CONNECTION_IDLE) return;
connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
l2cap_create_channel(packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL);
void avdtp_source_connect(bd_addr_t remote){
avdtp_connect(remote, AVDTP_SINK, avdtp_source_context);
}
void avdtp_source_disconnect(uint16_t con_handle){
avdtp_disconnect(con_handle, &avdtp_source_context);
avdtp_disconnect(con_handle, avdtp_source_context);
}
void avdtp_source_open_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_open_stream(con_handle, acp_seid, &avdtp_source_context);
void avdtp_source_open_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid){
avdtp_open_stream(con_handle, int_seid, acp_seid, avdtp_source_context);
}
void avdtp_source_start_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_start_stream(con_handle, acp_seid, &avdtp_source_context);
void avdtp_source_start_stream(uint8_t int_seid){
avdtp_start_stream(int_seid, avdtp_source_context);
}
void avdtp_source_stop_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_stop_stream(con_handle, acp_seid, &avdtp_source_context);
void avdtp_source_stop_stream(uint8_t int_seid){
avdtp_stop_stream(int_seid, avdtp_source_context);
}
void avdtp_source_abort_stream(uint16_t con_handle, uint8_t acp_seid){
avdtp_abort_stream(con_handle, acp_seid, &avdtp_source_context);
void avdtp_source_abort_stream(uint8_t int_seid){
avdtp_abort_stream(int_seid, avdtp_source_context);
}
void avdtp_source_suspend(uint8_t int_seid){
avdtp_suspend_stream(int_seid, avdtp_source_context);
}
void avdtp_source_discover_stream_endpoints(uint16_t con_handle){
avdtp_discover_stream_endpoints(con_handle, &avdtp_source_context);
avdtp_discover_stream_endpoints(con_handle, avdtp_source_context);
}
void avdtp_source_get_capabilities(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_capabilities(con_handle, acp_seid, &avdtp_source_context);
avdtp_get_capabilities(con_handle, acp_seid, avdtp_source_context);
}
void avdtp_source_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_all_capabilities(con_handle, acp_seid, &avdtp_source_context);
avdtp_get_all_capabilities(con_handle, acp_seid, avdtp_source_context);
}
void avdtp_source_get_configuration(uint16_t con_handle, uint8_t acp_seid){
avdtp_get_configuration(con_handle, acp_seid, &avdtp_source_context);
avdtp_get_configuration(con_handle, acp_seid, avdtp_source_context);
}
void avdtp_source_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_set_configuration(con_handle, int_seid, acp_seid, configured_services_bitmap, configuration, &avdtp_source_context);
avdtp_set_configuration(con_handle, int_seid, acp_seid, configured_services_bitmap, configuration, avdtp_source_context);
}
void avdtp_source_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_reconfigure(con_handle, acp_seid, configured_services_bitmap, configuration, &avdtp_source_context);
}
void avdtp_source_suspend(uint16_t con_handle, uint8_t acp_seid){
avdtp_suspend(con_handle, acp_seid, &avdtp_source_context);
void avdtp_source_reconfigure(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
avdtp_reconfigure(con_handle, int_seid, acp_seid, configured_services_bitmap, configuration, avdtp_source_context);
}
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
avdtp_packet_handler(packet_type, channel, packet, size, &avdtp_source_context);
avdtp_packet_handler(packet_type, channel, packet, size, avdtp_source_context);
}
/* streaming part */
#define NUM_CHANNELS 2
#define SAMPLE_RATE 44100
#define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS)
#define LATENCY 300 // ms
#ifndef M_PI
#define M_PI 3.14159265
#endif
#define TABLE_SIZE_441HZ 100
typedef struct {
int16_t source[TABLE_SIZE_441HZ];
int left_phase;
int right_phase;
} paTestData;
static uint32_t fill_audio_ring_buffer_timeout = 50; //ms
static paTestData sin_data;
static void fill_audio_ring_buffer(void *userData, int num_samples_to_write, avdtp_stream_endpoint_t * stream_endpoint){
paTestData *data = (paTestData*)userData;
int count = 0;
while (btstack_ring_buffer_bytes_free(&stream_endpoint->audio_ring_buffer) >= BYTES_PER_AUDIO_SAMPLE && count < num_samples_to_write){
uint8_t write_data[BYTES_PER_AUDIO_SAMPLE];
*(int16_t*)&write_data[0] = data->source[data->left_phase];
*(int16_t*)&write_data[2] = data->source[data->right_phase];
btstack_ring_buffer_write(&stream_endpoint->audio_ring_buffer, write_data, BYTES_PER_AUDIO_SAMPLE);
count++;
data->left_phase += 1;
if (data->left_phase >= TABLE_SIZE_441HZ){
data->left_phase -= TABLE_SIZE_441HZ;
}
data->right_phase += 1;
if (data->right_phase >= TABLE_SIZE_441HZ){
data->right_phase -= TABLE_SIZE_441HZ;
}
}
}
static void fill_sbc_ring_buffer(uint8_t * sbc_frame, int sbc_frame_size, avdtp_stream_endpoint_t * stream_endpoint){
if (btstack_ring_buffer_bytes_free(&stream_endpoint->sbc_ring_buffer) >= sbc_frame_size ){
// printf(" fill_sbc_ring_buffer\n");
uint8_t size_buffer = sbc_frame_size;
btstack_ring_buffer_write(&stream_endpoint->sbc_ring_buffer, &size_buffer, 1);
btstack_ring_buffer_write(&stream_endpoint->sbc_ring_buffer, sbc_frame, sbc_frame_size);
} else {
printf("No space in sbc buffer\n");
}
}
static void avdtp_source_stream_endpoint_run(avdtp_stream_endpoint_t * stream_endpoint){
// performe sbc encoding
int total_num_bytes_read = 0;
int num_audio_samples_to_read = btstack_sbc_encoder_num_audio_frames();
int audio_bytes_to_read = num_audio_samples_to_read * BYTES_PER_AUDIO_SAMPLE;
// printf("run: audio_bytes_to_read: %d\n", audio_bytes_to_read);
// printf(" audio buf, bytes available: %d\n", btstack_ring_buffer_bytes_available(&stream_endpoint->audio_ring_buffer));
// printf(" sbc buf, bytes free: %d\n", btstack_ring_buffer_bytes_free(&stream_endpoint->sbc_ring_buffer));
while (btstack_ring_buffer_bytes_available(&stream_endpoint->audio_ring_buffer) >= audio_bytes_to_read
&& btstack_ring_buffer_bytes_free(&stream_endpoint->sbc_ring_buffer) >= 120){ // TODO use real value
uint32_t number_of_bytes_read = 0;
uint8_t pcm_frame[256*BYTES_PER_AUDIO_SAMPLE];
btstack_ring_buffer_read(&stream_endpoint->audio_ring_buffer, pcm_frame, audio_bytes_to_read, &number_of_bytes_read);
// printf(" num audio bytes read %d\n", number_of_bytes_read);
btstack_sbc_encoder_process_data((int16_t *) pcm_frame);
uint16_t sbc_frame_bytes = 119; //btstack_sbc_encoder_sbc_buffer_length();
total_num_bytes_read += number_of_bytes_read;
fill_sbc_ring_buffer(btstack_sbc_encoder_sbc_buffer(), sbc_frame_bytes, stream_endpoint);
}
// schedule sending
if (total_num_bytes_read != 0){
stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING_W2_SEND;
avdtp_request_can_send_now_self(stream_endpoint->connection, stream_endpoint->l2cap_media_cid);
}
}
static void test_fill_audio_ring_buffer_timeout_handler(btstack_timer_source_t * timer){
avdtp_stream_endpoint_t * stream_endpoint = btstack_run_loop_get_timer_context(timer);
btstack_run_loop_set_timer(&stream_endpoint->fill_audio_ring_buffer_timer, fill_audio_ring_buffer_timeout); // 2 seconds timeout
btstack_run_loop_add_timer(&stream_endpoint->fill_audio_ring_buffer_timer);
uint32_t now = btstack_run_loop_get_time_ms();
uint32_t update_period_ms = fill_audio_ring_buffer_timeout;
if (stream_endpoint->time_audio_data_sent > 0){
update_period_ms = now - stream_endpoint->time_audio_data_sent;
}
uint32_t num_samples = (update_period_ms * 44100) / 1000;
stream_endpoint->acc_num_missed_samples += (update_period_ms * 44100) % 1000;
if (stream_endpoint->acc_num_missed_samples >= 1000){
num_samples++;
stream_endpoint->acc_num_missed_samples -= 1000;
}
fill_audio_ring_buffer(&sin_data, num_samples, stream_endpoint);
stream_endpoint->time_audio_data_sent = now;
avdtp_source_stream_endpoint_run(stream_endpoint);
//
}
static void test_fill_audio_ring_buffer_timer_start(avdtp_stream_endpoint_t * stream_endpoint){
btstack_run_loop_remove_timer(&stream_endpoint->fill_audio_ring_buffer_timer);
btstack_run_loop_set_timer_handler(&stream_endpoint->fill_audio_ring_buffer_timer, test_fill_audio_ring_buffer_timeout_handler);
btstack_run_loop_set_timer_context(&stream_endpoint->fill_audio_ring_buffer_timer, stream_endpoint);
btstack_run_loop_set_timer(&stream_endpoint->fill_audio_ring_buffer_timer, fill_audio_ring_buffer_timeout); // 50 ms timeout
btstack_run_loop_add_timer(&stream_endpoint->fill_audio_ring_buffer_timer);
}
static void test_fill_audio_ring_buffer_timer_stop(avdtp_stream_endpoint_t * stream_endpoint){
btstack_run_loop_remove_timer(&stream_endpoint->fill_audio_ring_buffer_timer);
}
void avdtp_source_stream_data_start(uint16_t con_handle){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_l2cap_cid(con_handle, &avdtp_source_context);
if (!stream_endpoint) {
printf("no stream_endpoint found for 0x%02x", con_handle);
void avdtp_source_init(avdtp_context_t * avdtp_context){
if (!avdtp_context){
log_error("avdtp_source_context is NULL");
return;
}
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING){
printf("stream_endpoint in wrong state %d\n", stream_endpoint->state);
return;
}
test_fill_audio_ring_buffer_timer_start(stream_endpoint);
}
void avdtp_source_stream_data_stop(uint16_t con_handle){
avdtp_stream_endpoint_t * stream_endpoint = avdtp_stream_endpoint_for_l2cap_cid(con_handle, &avdtp_source_context);
if (!stream_endpoint) {
log_error("no stream_endpoint found");
return;
}
if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING) return;
// TODO: initialize randomly sequence number
stream_endpoint->sequence_number = 0;
test_fill_audio_ring_buffer_timer_stop(stream_endpoint);
}
void avdtp_source_init(void){
avdtp_source_context.stream_endpoints = NULL;
avdtp_source_context.connections = NULL;
avdtp_source_context.stream_endpoints_id_counter = 0;
avdtp_source_context.packet_handler = packet_handler;
/* initialise sinusoidal wavetable */
int i;
for (i=0; i<TABLE_SIZE_441HZ; i++){
sin_data.source[i] = sin(((double)i/(double)TABLE_SIZE_441HZ) * M_PI * 2.)*32767;
}
sin_data.left_phase = sin_data.right_phase = 0;
avdtp_source_context = avdtp_context;
avdtp_source_context->stream_endpoints = NULL;
avdtp_source_context->connections = NULL;
avdtp_source_context->stream_endpoints_id_counter = 0;
avdtp_source_context->packet_handler = packet_handler;
l2cap_register_service(&packet_handler, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, LEVEL_0);
}
uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid){
return avdtp_remote_seps_num(avdtp_cid, avdtp_source_context);
}
avdtp_sep_t * avdtp_source_remote_sep(uint16_t avdtp_cid, uint8_t index){
return avdtp_remote_sep(avdtp_cid, index, avdtp_source_context);
}

View File

@ -54,27 +54,17 @@ extern "C" {
/* API_START */
/**
* @brief AVDTP Source service record.
* @param service
* @param service_record_handle
* @param supported_features 16-bit bitmap, see AVDTP_SOURCE_SF_* values in avdtp.h
* @param service_name
* @param service_provider_name
*/
void a2dp_source_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name);
void avdtp_source_register_media_transport_category(uint8_t seid);
void avdtp_source_register_reporting_category(uint8_t seid);
void avdtp_source_register_delay_reporting_category(uint8_t seid);
void avdtp_source_register_recovery_category(uint8_t seid, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets);
void avdtp_source_register_content_protection_category(uint8_t seid, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len);
void avdtp_source_register_header_compression_category(uint8_t seid, uint8_t back_ch, uint8_t media, uint8_t recovery);
void avdtp_source_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_source_register_media_codec_category(uint8_t seid, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len);
void avdtp_source_register_multiplexing_category(uint8_t seid, uint8_t fragmentation);
void avdtp_source_init(void);
void avdtp_source_init(avdtp_context_t * avdtp_context);
void avdtp_source_register_packet_handler(btstack_packet_handler_t callback);
/**
@ -83,90 +73,86 @@ void avdtp_source_register_packet_handler(btstack_packet_handler_t callback);
*/
void avdtp_source_connect(bd_addr_t bd_addr);
void avdtp_source_register_media_handler(void (*callback)(avdtp_stream_endpoint_t * stream_endpoint, uint8_t *packet, uint16_t size));
/**
* @brief Disconnect from device with connection handle.
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_disconnect(uint16_t con_handle);
void avdtp_source_disconnect(uint16_t avdtp_cid);
/**
* @brief Discover stream endpoints
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_discover_stream_endpoints(uint16_t con_handle);
void avdtp_source_discover_stream_endpoints(uint16_t avdtp_cid);
/**
* @brief Get capabilities
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_get_capabilities(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_get_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Get all capabilities
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_get_all_capabilities(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_get_all_capabilities(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Set configuration
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_set_configuration(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
void avdtp_source_set_configuration(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
/**
* @brief Reconfigure stream
* @param con_handle
* @param avdtp_cid
* @param seid
*/
void avdtp_source_reconfigure(uint16_t con_handle, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
void avdtp_source_reconfigure(uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration);
/**
* @brief Get configuration
* @param con_handle
* @param avdtp_cid
*/
void avdtp_source_get_configuration(uint16_t con_handle, uint8_t acp_seid);
/**
* @brief Suspend stream
* @param con_handle
* @param seid
*/
void avdtp_source_suspend(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_get_configuration(uint16_t avdtp_cid, uint8_t acp_seid);
/**
* @brief Open stream
* @param con_handle
* @param avdtp_cid
* @param seid
*/
void avdtp_source_open_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_open_stream(uint16_t con_handle, uint8_t int_seid, uint8_t acp_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @param local_seid
*/
void avdtp_source_start_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_start_stream(uint8_t local_seid);
/**
* @brief Abort stream
* @param local_seid
*/
void avdtp_source_abort_stream(uint8_t local_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @param local_seid
*/
void avdtp_source_abort_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_stop_stream(uint8_t local_seid);
/**
* @brief Start stream
* @param con_handle
* @param seid
* @brief Suspend stream
* @param local_seid
*/
void avdtp_source_stop_stream(uint16_t con_handle, uint8_t acp_seid);
void avdtp_source_suspend(uint8_t local_seid);
avdtp_stream_endpoint_t * avdtp_source_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type);
void avdtp_source_stream_data_start(uint16_t con_handle);
void avdtp_source_stream_data_stop(uint16_t con_handle);
uint8_t avdtp_source_remote_seps_num(uint16_t avdtp_cid);
avdtp_sep_t * avdtp_source_remote_sep(uint16_t avdtp_cid, uint8_t index);
/* API_END */
#if defined __cplusplus

View File

@ -59,9 +59,8 @@ void avdtp_initialize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint)
stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
stream_endpoint->remote_sep_index = AVDTP_INVALID_SEP_INDEX;
stream_endpoint->media_disconnect = 0;
stream_endpoint->remote_seps_num = 0;
stream_endpoint->sep.in_use = 0;
memset(stream_endpoint->remote_seps, 0, sizeof(stream_endpoint->remote_seps));
stream_endpoint->remote_sep_index = 0;
}
avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_seid(uint16_t seid, avdtp_context_t * context){
@ -87,17 +86,6 @@ avdtp_connection_t * avdtp_connection_for_bd_addr(bd_addr_t addr, avdtp_context_
return NULL;
}
avdtp_connection_t * avdtp_connection_for_con_handle(hci_con_handle_t con_handle, avdtp_context_t * context){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &context->connections);
while (btstack_linked_list_iterator_has_next(&it)){
avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
if (connection->con_handle != con_handle) continue;
return connection;
}
return NULL;
}
avdtp_connection_t * avdtp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avdtp_context_t * context){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &context->connections);
@ -144,8 +132,10 @@ avdtp_stream_endpoint_t * avdtp_stream_endpoint_associated_with_acp_seid(uint16_
btstack_linked_list_iterator_init(&it, &context->stream_endpoints);
while (btstack_linked_list_iterator_has_next(&it)){
avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
if (stream_endpoint->remote_sep_index != AVDTP_INVALID_SEP_INDEX){
if (stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid == acp_seid){
if (!stream_endpoint->connection) continue;
if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid == acp_seid){
return stream_endpoint;
}
}
@ -190,7 +180,7 @@ int avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, uin
break;
case AVDTP_CONTINUE_PACKET:
if (signaling_header->num_packets <= 0) {
printf(" ERROR: wrong num fragmented packets\n");
log_info(" ERROR: wrong num fragmented packets\n");
break;
}
signaling_header->num_packets--;
@ -254,7 +244,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
if (category == AVDTP_SERVICE_CATEGORY_INVALID_0 ||
(category == AVDTP_SERVICE_CATEGORY_INVALID_FF && connection->signaling_packet.signal_identifier == AVDTP_SI_RECONFIGURE)){
printf(" ERROR: BAD SERVICE CATEGORY %d\n", category);
log_info(" ERROR: BAD SERVICE CATEGORY %d\n", category);
connection->reject_service_category = category;
connection->error_code = BAD_SERV_CATEGORY;
return 1;
@ -262,7 +252,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
if (connection->signaling_packet.signal_identifier == AVDTP_SI_RECONFIGURE){
if (category != AVDTP_CONTENT_PROTECTION && category != AVDTP_MEDIA_CODEC){
printf(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n");
log_info(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n");
connection->reject_service_category = category;
connection->error_code = INVALID_CAPABILITIES;
return 1;
@ -272,7 +262,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
switch(category){
case AVDTP_MEDIA_TRANSPORT:
if (cap_len != 0){
printf(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
connection->reject_service_category = category;
connection->error_code = BAD_MEDIA_TRANSPORT_FORMAT;
return 1;
@ -281,7 +271,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
case AVDTP_REPORTING:
case AVDTP_DELAY_REPORTING:
if (cap_len != 0){
printf(" ERROR: REJECT CATEGORY, BAD_LENGTH\n");
log_info(" ERROR: REJECT CATEGORY, BAD_LENGTH\n");
connection->reject_service_category = category;
connection->error_code = BAD_LENGTH;
return 1;
@ -289,7 +279,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
break;
case AVDTP_RECOVERY:
if (cap_len < 3){
printf(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
connection->reject_service_category = category;
connection->error_code = BAD_RECOVERY_FORMAT;
return 1;
@ -297,7 +287,7 @@ static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * con
break;
case AVDTP_CONTENT_PROTECTION:
if (cap_len < 2){
printf(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n");
log_info(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n");
connection->reject_service_category = category;
connection->error_code = BAD_CP_FORMAT;
return 1;
@ -327,8 +317,7 @@ uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdt
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
int processed_cap_len = 0;
int rfa = 0;
//printf(" size %d, cat size %d\n", size, cap_len);
while (pos < size){
if (cap_len > size - pos){
connection->reject_service_category = category;
@ -398,8 +387,6 @@ uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdt
category = (avdtp_service_category_t)packet[pos++];
cap_len = packet[pos++];
if (avdtp_unpack_service_capabilities_has_errors(connection, category, cap_len)) return 0;
//printf("category %d, pos %d + 2 + %d -> %d\n", category, old_pos, cap_len, pos + cap_len);
//printf_hexdump(packet+old_pos, size-old_pos);
}
}
}
@ -437,10 +424,6 @@ void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uin
break;
}
// printf("registered_service_categories: 0x%02x\n", registered_service_categories);
// printf("command before packing:\n");
// printf_hexdump(signaling_packet->command, signaling_packet->size);
for (i = 1; i < 9; i++){
int registered_category = get_bit16(registered_service_categories, i);
if (!registered_category && (identifier == AVDTP_SI_SET_CONFIGURATION || identifier == AVDTP_SI_RECONFIGURE)){
@ -451,13 +434,10 @@ void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uin
}
if (registered_category){
// service category
// printf("pack service category: %d\n", i);
signaling_packet->command[signaling_packet->size++] = i;
signaling_packet->size += avdtp_pack_service_capabilities(signaling_packet->command+signaling_packet->size, sizeof(signaling_packet->command)-signaling_packet->size, capabilities, (avdtp_service_category_t)i, pack_all_capabilities);
}
}
// printf("command after packing:\n");
// printf_hexdump(signaling_packet->command, signaling_packet->size);
signaling_packet->signal_identifier = identifier;
signaling_packet->transaction_label = transaction_label;
@ -465,17 +445,13 @@ void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uin
int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer) {
int mtu = l2cap_get_remote_mtu_for_local_cid(cid);
// hack for test
// int mtu = 6;
int data_len = 0;
uint16_t offset = signaling_packet->offset;
uint16_t pos = 1;
// printf(" avdtp_signaling_create_fragment offset %d, packet type %d\n", signaling_packet->offset, signaling_packet->packet_type);
if (offset == 0){
if (signaling_packet->size <= mtu - 2){
// printf(" AVDTP_SINGLE_PACKET\n");
signaling_packet->packet_type = AVDTP_SINGLE_PACKET;
out_buffer[pos++] = signaling_packet->signal_identifier;
data_len = signaling_packet->size;
@ -485,21 +461,17 @@ int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * sig
out_buffer[pos++] = signaling_packet->signal_identifier;
data_len = mtu - 3;
signaling_packet->offset = data_len;
// printf(" AVDTP_START_PACKET len %d, offset %d\n", signaling_packet->size, signaling_packet->offset);
}
} else {
int remaining_bytes = signaling_packet->size - offset;
if (remaining_bytes <= mtu - 1){
//signaling_packet->fragmentation = 1;
signaling_packet->packet_type = AVDTP_END_PACKET;
data_len = remaining_bytes;
signaling_packet->offset = 0;
// printf(" AVDTP_END_PACKET len %d, offset %d\n", signaling_packet->size, signaling_packet->offset);
} else{
signaling_packet->packet_type = AVDTP_CONTINUE_PACKET;
data_len = mtu - 1;
signaling_packet->offset += data_len;
// printf(" AVDTP_CONTINUE_PACKET len %d, offset %d\n", signaling_packet->size, signaling_packet->offset);
}
}
out_buffer[0] = avdtp_header(signaling_packet->transaction_label, signaling_packet->packet_type, signaling_packet->message_type);
@ -509,14 +481,14 @@ int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * sig
}
void avdtp_signaling_emit_connection_established(btstack_packet_handler_t callback, uint16_t con_handle, bd_addr_t addr, uint8_t status){
void avdtp_signaling_emit_connection_established(btstack_packet_handler_t callback, uint16_t avdtp_cid, bd_addr_t addr, uint8_t status){
if (!callback) return;
uint8_t event[12];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
reverse_bd_addr(addr,&event[pos]);
pos += 6;
@ -524,27 +496,44 @@ void avdtp_signaling_emit_connection_established(btstack_packet_handler_t callba
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t con_handle, uint8_t status){
void avdtp_streaming_emit_can_send_media_packet_now(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t seid, uint16_t sequence_number){
if (!callback) return;
uint8_t event[6];
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW;
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = seid;
little_endian_store_16(event, pos, sequence_number);
pos += 2;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint8_t status){
if (!callback) return;
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = acp_seid;
event[pos++] = status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_sep_t sep){
void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t avdtp_cid, avdtp_sep_t sep){
if (!callback) return;
uint8_t event[9];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_FOUND;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = sep.seid;
event[pos++] = sep.in_use;
@ -553,55 +542,60 @@ void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t con_ha
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier, uint8_t status){
void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier, uint8_t status){
if (!callback) return;
uint8_t event[7];
uint8_t event[8];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = identifier;
event[pos++] = status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_reject(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier){
void avdtp_signaling_emit_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier){
if (!callback) return;
uint8_t event[6];
uint8_t event[7];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_REJECT;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = identifier;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_general_reject(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier){
void avdtp_signaling_emit_general_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier){
if (!callback) return;
uint8_t event[6];
uint8_t event[7];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = identifier;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_media_codec_sbc_capability(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_sbc_capability(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
uint8_t event[13];
uint8_t event[15];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = acp_seid;
event[pos++] = media_codec.media_type;
event[pos++] = media_codec.media_codec_information[0] >> 4;
event[pos++] = media_codec.media_codec_information[0] & 0x0F;
@ -613,15 +607,17 @@ void avdtp_signaling_emit_media_codec_sbc_capability(btstack_packet_handler_t ca
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_media_codec_other_capability(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_other_capability(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
uint8_t event[109];
uint8_t event[111];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = acp_seid;
event[pos++] = media_codec.media_type;
little_endian_store_16(event, pos, media_codec.media_codec_type);
pos += 2;
@ -635,16 +631,18 @@ void avdtp_signaling_emit_media_codec_other_capability(btstack_packet_handler_t
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static inline void avdtp_signaling_emit_media_codec_sbc(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec, uint8_t reconfigure){
static inline void avdtp_signaling_emit_media_codec_sbc(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec, uint8_t reconfigure){
if (!callback) return;
uint8_t event[14+2];
uint8_t event[16+2];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = acp_seid;
event[pos++] = reconfigure;
uint8_t num_channels = 0;
@ -713,25 +711,26 @@ static inline void avdtp_signaling_emit_media_codec_sbc(btstack_packet_handler_t
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_media_codec_sbc_configuration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_sbc_configuration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
avdtp_signaling_emit_media_codec_sbc(callback, con_handle, media_codec, 0);
avdtp_signaling_emit_media_codec_sbc(callback, avdtp_cid, int_seid, acp_seid, media_codec, 0);
}
void avdtp_signaling_emit_media_codec_sbc_reconfiguration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_sbc_reconfiguration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
avdtp_signaling_emit_media_codec_sbc(callback, con_handle, media_codec, 1);
avdtp_signaling_emit_media_codec_sbc(callback, avdtp_cid, int_seid, acp_seid, media_codec, 1);
}
static inline void avdtp_signaling_emit_media_codec_other(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec, uint8_t reconfigure){
uint8_t event[110];
static inline void avdtp_signaling_emit_media_codec_other(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec, uint8_t reconfigure){
uint8_t event[112];
int pos = 0;
event[pos++] = HCI_EVENT_AVDTP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION;
little_endian_store_16(event, pos, con_handle);
little_endian_store_16(event, pos, avdtp_cid);
pos += 2;
event[pos++] = int_seid;
event[pos++] = acp_seid;
event[pos++] = reconfigure;
event[pos++] = media_codec.media_type;
@ -748,14 +747,14 @@ static inline void avdtp_signaling_emit_media_codec_other(btstack_packet_handler
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
void avdtp_signaling_emit_media_codec_other_configuration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_other_configuration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
avdtp_signaling_emit_media_codec_other(callback, con_handle, media_codec, 0);
avdtp_signaling_emit_media_codec_other(callback, avdtp_cid, int_seid, acp_seid, media_codec, 0);
}
void avdtp_signaling_emit_media_codec_other_reconfiguration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec){
void avdtp_signaling_emit_media_codec_other_reconfiguration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec){
if (!callback) return;
avdtp_signaling_emit_media_codec_other(callback, con_handle, media_codec, 1);
avdtp_signaling_emit_media_codec_other(callback, avdtp_cid, int_seid, acp_seid, media_codec, 1);
}
@ -773,14 +772,27 @@ void avdtp_request_can_send_now_self(avdtp_connection_t * connection, uint16_t l
}
uint8_t avdtp_get_index_of_remote_stream_endpoint_with_seid(avdtp_stream_endpoint_t * stream_endpoint, uint16_t seid){
if (stream_endpoint->remote_seps[stream_endpoint->remote_sep_index].seid == seid){
if (!stream_endpoint->connection) return 0xFF;
if (stream_endpoint->connection->remote_seps[stream_endpoint->remote_sep_index].seid == seid){
return stream_endpoint->remote_sep_index;
}
int i;
for (i=0; i < stream_endpoint->remote_seps_num; i++){
if (stream_endpoint->remote_seps[i].seid == seid){
for (i=0; i < stream_endpoint->connection->remote_seps_num; i++){
if (stream_endpoint->connection->remote_seps[i].seid == seid){
return i;
}
}
return 0xFF;
}
uint8_t avdtp_find_remote_sep(avdtp_connection_t * connection, uint8_t remote_seid){
if (!connection) return 0xFF;
int i;
for (i = 0; i < connection->remote_seps_num; i++){
if (connection->remote_seps[i].seid == remote_seid){
return i;
}
}
return 0xFF;
}

View File

@ -55,7 +55,6 @@ extern "C" {
#define AVDTP_INVALID_SEP_INDEX 0xff
avdtp_connection_t * avdtp_connection_for_bd_addr(bd_addr_t addr, avdtp_context_t * context);
avdtp_connection_t * avdtp_connection_for_con_handle(hci_con_handle_t con_handle, avdtp_context_t * context);
avdtp_connection_t * avdtp_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid, avdtp_context_t * context);
avdtp_stream_endpoint_t * avdtp_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid, avdtp_context_t * context);
avdtp_stream_endpoint_t * avdtp_stream_endpoint_with_seid(uint8_t seid, avdtp_context_t * context);
@ -74,20 +73,20 @@ uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdt
void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uint8_t transaction_label, uint16_t registered_service_categories, avdtp_capabilities_t configuration, uint8_t identifier);
int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer);
void avdtp_signaling_emit_connection_established(btstack_packet_handler_t callback, uint16_t con_handle, bd_addr_t addr, uint8_t status);
void avdtp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t con_handle, uint8_t status);
void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_sep_t sep);
void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier, uint8_t status);
void avdtp_signaling_emit_general_reject(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier);
void avdtp_signaling_emit_reject(btstack_packet_handler_t callback, uint16_t con_handle, avdtp_signal_identifier_t identifier);
void avdtp_signaling_emit_connection_established(btstack_packet_handler_t callback, uint16_t avdtp_cid, bd_addr_t addr, uint8_t status);
void avdtp_streaming_emit_connection_established(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, uint8_t status);
void avdtp_signaling_emit_sep(btstack_packet_handler_t callback, uint16_t avdtp_cid, avdtp_sep_t sep);
void avdtp_signaling_emit_accept(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t seid, avdtp_signal_identifier_t identifier, uint8_t status);
void avdtp_signaling_emit_general_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier);
void avdtp_signaling_emit_reject(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, avdtp_signal_identifier_t identifier);
void avdtp_streaming_emit_can_send_media_packet_now(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint16_t sequence_number);
void avdtp_signaling_emit_media_codec_sbc_capability(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_capability(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_sbc_configuration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_configuration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_sbc_reconfiguration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_reconfiguration(btstack_packet_handler_t callback, uint16_t con_handle, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_sbc_capability(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_capability(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_sbc_configuration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_configuration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_sbc_reconfiguration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_signaling_emit_media_codec_other_reconfiguration(btstack_packet_handler_t callback, uint16_t avdtp_cid, uint8_t int_seid, uint8_t acp_seid, adtvp_media_codec_capabilities_t media_codec);
void avdtp_request_can_send_now_acceptor(avdtp_connection_t * connection, uint16_t l2cap_cid);
void avdtp_request_can_send_now_initiator(avdtp_connection_t * connection, uint16_t l2cap_cid);
@ -96,6 +95,7 @@ void avdtp_request_can_send_now_self(avdtp_connection_t * connection, uint16_t l
uint8_t avdtp_get_index_of_remote_stream_endpoint_with_seid(avdtp_stream_endpoint_t * stream_endpoint, uint16_t acp_seid);
void avdtp_initialize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint);
uint8_t avdtp_find_remote_sep(avdtp_connection_t * connection, uint8_t remote_seid);
#if defined __cplusplus
}

View File

@ -1,4 +1,4 @@
avdtp_source_test
avdtp_source_demo
avdtp_sink_test
portaudio_test
sine_encode_decode_test

View File

@ -28,6 +28,8 @@ COMMON += \
sdp_server.c \
sdp_util.c \
wav_util.c \
sdp_server.c \
sdp_client.c \
CFLAGS += -g -Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wunused-variable -Wunused-parameter -Werror
CFLAGS += -I.
@ -35,6 +37,8 @@ CFLAGS += -I${BTSTACK_ROOT}/src
CFLAGS += -I${BTSTACK_ROOT}/src/classic
CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/include -D OI_DEBUG
CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/include
CFLAGS += -I${BTSTACK_ROOT}/3rd-party/hxcmod-player
CFLAGS += -I${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods
CFLAGS += -I${BTSTACK_ROOT}/platform/posix
CFLAGS += -I${BTSTACK_ROOT}/platform/embedded
CFLAGS += -I${BTSTACK_ROOT}/port/libusb
@ -46,6 +50,8 @@ VPATH += ${BTSTACK_ROOT}/platform/libusb
VPATH += ${BTSTACK_ROOT}/port/libusb
VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce
VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce
VPATH += ${BTSTACK_ROOT}/3rd-party/hxcmod-player
VPATH += ${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods
# use pkg-config for libusb
CFLAGS += $(shell pkg-config libusb-1.0 --cflags)
@ -63,42 +69,50 @@ SBC_ENCODER += \
${BTSTACK_ROOT}/src/classic/btstack_sbc_bludroid.c \
${BTSTACK_ROOT}/src/classic/hfp_msbc.c \
AVDTP_SINK += \
AVDTP += \
avdtp_util.c \
avdtp.c \
avdtp_initiator.c \
avdtp_acceptor.c \
avdtp_source.c \
avdtp_sink.c \
a2dp_source.c \
a2dp_sink.c \
btstack_ring_buffer.c \
AVDTP_TESTS = avdtp_source_test avdtp_sink_test portaudio_test sine_encode_decode_ring_buffer_test sine_encode_decode_test sine_encode_decode_performance_test
HXCMOD_PLAYER = \
${BTSTACK_ROOT}/3rd-party/hxcmod-player/hxcmod.c \
${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods/nao-deceased_by_disease.c \
AVDTP_TESTS = avdtp_source_demo avdtp_sink_test portaudio_test
#sine_encode_decode_ring_buffer_test sine_encode_decode_test sine_encode_decode_performance_test
CORE_OBJ = $(CORE:.c=.o)
COMMON_OBJ = $(COMMON:.c=.o)
SBC_DECODER_OBJ = $(SBC_DECODER:.c=.o)
SBC_ENCODER_OBJ = $(SBC_ENCODER:.c=.o)
AVDTP_SINK_OBJ = $(AVDTP_SINK:.c=.o)
AVDTP_OBJ = $(AVDTP:.c=.o)
HXCMOD_PLAYER_OBJ = $(HXCMOD_PLAYER:.c=.o)
all: ${AVDTP_TESTS}
avdtp_sink_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_SINK_OBJ} avdtp_sink_test.o
avdtp_sink_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} avdtp_sink_test.o
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
avdtp_source_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_SINK_OBJ} avdtp_source_test.o
avdtp_source_demo: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} ${HXCMOD_PLAYER_OBJ} avdtp_source_demo.o
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
portaudio_test: btstack_util.o hci_dump.o wav_util.o btstack_ring_buffer.o portaudio_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
sine_encode_decode_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_SINK_OBJ} sine_encode_decode_test.c
sine_encode_decode_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} sine_encode_decode_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
sine_encode_decode_ring_buffer_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_SINK_OBJ} sine_encode_decode_ring_buffer_test.c
sine_encode_decode_ring_buffer_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} sine_encode_decode_ring_buffer_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
sine_encode_decode_performance_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_SINK_OBJ} sine_encode_decode_performance_test.c
sine_encode_decode_performance_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} sine_encode_decode_performance_test.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@

View File

@ -54,6 +54,7 @@
#include "l2cap.h"
#include "stdin_support.h"
#include "avdtp_sink.h"
#include "a2dp_sink.h"
#include "btstack_sbc.h"
#include "wav_util.h"
@ -133,13 +134,13 @@ typedef struct {
} avdtp_media_codec_configuration_sbc_t;
// mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
// pts:
static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
// mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15};
// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
// mac 2013:
static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15};
// bt dongle: -u 02-02 static bd_addr_t remote = {0x00, 0x02, 0x72, 0xDC, 0x31, 0xC1};
static uint16_t con_handle = 0;
static uint16_t avdtp_cid = 0;
static uint8_t sdp_avdtp_sink_service_buffer[150];
static avdtp_sep_t sep;
@ -442,8 +443,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case HCI_EVENT_AVDTP_META:
switch (packet[2]){
case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
con_handle = avdtp_subevent_signaling_connection_established_get_con_handle(packet);
printf("\n --- avdtp_test: AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, con handle 0x%02x ---\n", con_handle);
avdtp_cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet);
printf("\n --- avdtp_test: AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED, cid 0x%02x ---\n", avdtp_cid);
break;
case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:
if (app_state != AVDTP_APPLICATION_W2_DISCOVER_SEPS) return;
@ -477,7 +478,9 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
sbc_configuration.max_bitpool_value = avdtp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);
sbc_configuration.frames_per_buffer = sbc_configuration.subbands * sbc_configuration.block_length;
dump_sbc_configuration(sbc_configuration);
// // TODO: use actual config
// btstack_sbc_encoder_init(&local_stream_endpoint->sbc_encoder_state, SBC_MODE_STANDARD, 16, 8, 2, 44100, 53);
if (sbc_configuration.reconfigure){
close_media_processing();
init_media_processing(sbc_configuration);
@ -486,6 +489,8 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
}
break;
}
case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED:
break;
case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY:
printf(" received non SBC codec. not implemented\n");
break;
@ -528,19 +533,19 @@ static void show_usage(void){
printf("---\n");
}
static const uint8_t media_sbc_codec_capabilities[] = {
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 const uint8_t media_sbc_codec_configuration[] = {
static uint8_t media_sbc_codec_configuration[] = {
(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
2, 53
};
static const uint8_t media_sbc_codec_reconfiguration[] = {
static uint8_t media_sbc_codec_reconfiguration[] = {
(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_SNR,
2, 53
@ -560,23 +565,23 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
break;
case 'C':
printf("Disconnect not implemented\n");
avdtp_sink_disconnect(con_handle);
avdtp_sink_disconnect(avdtp_cid);
break;
case 'd':
app_state = AVDTP_APPLICATION_W2_DISCOVER_SEPS;
avdtp_sink_discover_stream_endpoints(con_handle);
avdtp_sink_discover_stream_endpoints(avdtp_cid);
break;
case 'g':
app_state = AVDTP_APPLICATION_W2_GET_CAPABILITIES;
avdtp_sink_get_capabilities(con_handle, sep.seid);
avdtp_sink_get_capabilities(avdtp_cid, sep.seid);
break;
case 'a':
app_state = AVDTP_APPLICATION_W2_GET_ALL_CAPABILITIES;
avdtp_sink_get_all_capabilities(con_handle, sep.seid);
avdtp_sink_get_all_capabilities(avdtp_cid, sep.seid);
break;
case 'f':
app_state = AVDTP_APPLICATION_W2_GET_CONFIGURATION;
avdtp_sink_get_configuration(con_handle, sep.seid);
avdtp_sink_get_configuration(avdtp_cid, sep.seid);
break;
case 's':
app_state = AVDTP_APPLICATION_W2_SET_CONFIGURATION;
@ -585,7 +590,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_configuration);
remote_configuration.media_codec.media_codec_information = media_sbc_codec_configuration;
avdtp_sink_set_configuration(con_handle, local_stream_endpoint->sep.seid, sep.seid, remote_configuration_bitmap, remote_configuration);
avdtp_sink_set_configuration(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid, remote_configuration_bitmap, remote_configuration);
break;
case 'R':
app_state = AVDTP_APPLICATION_W2_RECONFIGURE_WITH_SEID;
@ -594,27 +599,28 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
remote_configuration.media_codec.media_codec_type = AVDTP_CODEC_SBC;
remote_configuration.media_codec.media_codec_information_len = sizeof(media_sbc_codec_reconfiguration);
remote_configuration.media_codec.media_codec_information = media_sbc_codec_reconfiguration;
avdtp_sink_reconfigure(con_handle, sep.seid, remote_configuration_bitmap, remote_configuration);
avdtp_sink_reconfigure(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid, remote_configuration_bitmap, remote_configuration);
break;
case 'o':
app_state = AVDTP_APPLICATION_W2_OPEN_STREAM_WITH_SEID;
avdtp_sink_open_stream(con_handle, sep.seid);
avdtp_sink_open_stream(avdtp_cid, local_stream_endpoint->sep.seid, sep.seid);
break;
case 'm':
printf("AVDTP_APPLICATION_W2_START_STREAM_WITH_SEID \n");
app_state = AVDTP_APPLICATION_W2_START_STREAM_WITH_SEID;
avdtp_sink_start_stream(con_handle, sep.seid);
avdtp_sink_start_stream(local_stream_endpoint->sep.seid);
break;
case 'A':
app_state = AVDTP_APPLICATION_W2_ABORT_STREAM_WITH_SEID;
avdtp_sink_abort_stream(con_handle, sep.seid);
avdtp_sink_abort_stream(local_stream_endpoint->sep.seid);
break;
case 'S':
app_state = AVDTP_APPLICATION_W2_STOP_STREAM_WITH_SEID;
avdtp_sink_stop_stream(con_handle, sep.seid);
avdtp_sink_stop_stream(local_stream_endpoint->sep.seid);
break;
case 'P':
app_state = AVDTP_APPLICATION_W2_SUSPEND_STREAM_WITH_SEID;
avdtp_sink_suspend(con_handle, sep.seid);
avdtp_sink_suspend(local_stream_endpoint->sep.seid);
break;
case '\n':

View File

@ -0,0 +1,425 @@
/*
* Copyright (C) 2016 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "btstack_config.h"
#include "btstack_debug.h"
#include "btstack_event.h"
#include "btstack_memory.h"
#include "btstack_run_loop.h"
#include "gap.h"
#include "hci.h"
#include "hci_cmd.h"
#include "hci_dump.h"
#include "l2cap.h"
#include "stdin_support.h"
#include "avdtp_source.h"
#include "a2dp_source.h"
#include "btstack_sbc.h"
#include "sbc_encoder.h"
#include "avdtp_util.h"
#include "hxcmod.h"
#include "mod.h"
#define NUM_CHANNELS 2
#define A2DP_SAMPLE_RATE 44100
#define BYTES_PER_AUDIO_SAMPLE (2*NUM_CHANNELS)
#define FILL_AUDIO_BUFFER_TIMEOUT_MS 10
#ifndef M_PI
#define M_PI 3.14159265
#endif
#define TABLE_SIZE_441HZ 100
typedef struct {
int left_phase;
int right_phase;
} paTestData;
typedef enum {
STREAM_SINE,
STREAM_MOD
} stream_data_source_t;
static uint8_t media_sbc_codec_capabilities[] = {
(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 const int16_t sine_int16[] = {
0, 2057, 4107, 6140, 8149, 10126, 12062, 13952, 15786, 17557,
19260, 20886, 22431, 23886, 25247, 26509, 27666, 28714, 29648, 30466,
31163, 31738, 32187, 32509, 32702, 32767, 32702, 32509, 32187, 31738,
31163, 30466, 29648, 28714, 27666, 26509, 25247, 23886, 22431, 20886,
19260, 17557, 15786, 13952, 12062, 10126, 8149, 6140, 4107, 2057,
0, -2057, -4107, -6140, -8149, -10126, -12062, -13952, -15786, -17557,
-19260, -20886, -22431, -23886, -25247, -26509, -27666, -28714, -29648, -30466,
-31163, -31738, -32187, -32509, -32702, -32767, -32702, -32509, -32187, -31738,
-31163, -30466, -29648, -28714, -27666, -26509, -25247, -23886, -22431, -20886,
-19260, -17557, -15786, -13952, -12062, -10126, -8149, -6140, -4107, -2057,
};
static char * device_name = "A2DP Source BTstack";
// mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
// mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15};
// phone 2013: static bd_addr_t remote = {0xD8, 0xBB, 0x2C, 0xDF, 0xF0, 0xF2};
// minijambox:
static bd_addr_t remote = {0x00, 0x21, 0x3c, 0xac, 0xf7, 0x38};
// head phones: static bd_addr_t remote = {0x00, 0x18, 0x09, 0x28, 0x50, 0x18};
// bt dongle: -u 02-04-01
// static bd_addr_t remote = {0x00, 0x15, 0x83, 0x5F, 0x9D, 0x46};
static uint8_t sdp_avdtp_source_service_buffer[150];
static uint8_t media_sbc_codec_configuration[4];
typedef struct {
uint16_t a2dp_cid;
uint8_t local_seid;
uint32_t time_audio_data_sent; // ms
uint32_t acc_num_missed_samples;
uint32_t samples_ready;
btstack_timer_source_t fill_audio_buffer_timer;
uint8_t streaming;
int max_media_payload_size;
uint8_t sbc_storage[1030];
uint16_t sbc_storage_count;
uint8_t sbc_ready_to_send;
} a2dp_media_sending_context_t;
static a2dp_media_sending_context_t media_tracker;
static paTestData sin_data;
static int hxcmod_initialized = 0;
static modcontext mod_context;
static tracker_buffer_state trkbuf;
static uint8_t local_seid = 0;
stream_data_source_t data_source = STREAM_SINE;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context);
static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context);
static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context);
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_A2DP_META:
switch (packet[2]){
case A2DP_SUBEVENT_STREAM_ESTABLISHED:
media_tracker.local_seid = a2dp_subevent_stream_established_get_local_seid(packet);
media_tracker.a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
printf(" --- application --- A2DP_SUBEVENT_STREAM_ESTABLISHED, a2dp_cid 0x%02x, local seid %d, remote seid %d\n",
media_tracker.a2dp_cid, media_tracker.local_seid, a2dp_subevent_stream_established_get_remote_seid(packet));
break;
case A2DP_SUBEVENT_STREAM_START_ACCEPTED:
if (local_seid != media_tracker.local_seid) break;
if (!a2dp_source_stream_endpoint_ready(media_tracker.local_seid)) break;
a2dp_fill_audio_buffer_timer_start(&media_tracker);
printf(" --- application --- A2DP_SUBEVENT_STREAM_START_ACCEPTED, local seid %d\n", media_tracker.local_seid);
break;
case A2DP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW:{
if (local_seid != media_tracker.local_seid) break;
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;
a2dp_source_stream_send_media_payload(media_tracker.local_seid, media_tracker.sbc_storage, bytes_in_storage, num_frames, 0);
media_tracker.sbc_storage_count = 0;
media_tracker.sbc_ready_to_send = 0;
break;
}
case A2DP_SUBEVENT_STREAM_SUSPENDED:
printf(" --- application --- A2DP_SUBEVENT_STREAM_SUSPENDED, local seid %d\n", media_tracker.local_seid);
a2dp_fill_audio_buffer_timer_pause(&media_tracker);
break;
case A2DP_SUBEVENT_STREAM_RELEASED:
printf(" --- application --- A2DP_SUBEVENT_STREAM_RELEASED, local seid %d\n", media_tracker.local_seid);
a2dp_fill_audio_buffer_timer_stop(&media_tracker);
break;
default:
printf(" --- application --- not implemented\n");
break;
}
break;
default:
break;
}
break;
default:
// other packet type
break;
}
}
static void show_usage(void){
bd_addr_t iut_address;
gap_local_bd_addr(iut_address);
printf("\n--- Bluetooth AVDTP SOURCE Test Console %s ---\n", bd_addr_to_str(iut_address));
printf("c - create connection to addr %s\n", bd_addr_to_str(remote));
printf("C - disconnect\n");
printf("x - start streaming sine\n");
if (hxcmod_initialized){
printf("z - start streaming '%s'\n", mod_name);
}
printf("p - pause streaming\n");
printf("X - stop streaming\n");
printf("Ctrl-c - exit\n");
printf("---\n");
}
static void produce_sine_audio(int16_t * pcm_buffer, void *user_data, int num_samples_to_write){
paTestData *data = (paTestData*)user_data;
int count;
for (count = 0; count < num_samples_to_write ; count++){
pcm_buffer[count * 2] = sine_int16[data->left_phase];
pcm_buffer[count * 2 + 1] = sine_int16[data->right_phase];
data->left_phase += 1;
if (data->left_phase >= TABLE_SIZE_441HZ){
data->left_phase -= TABLE_SIZE_441HZ;
}
data->right_phase += 1;
if (data->right_phase >= TABLE_SIZE_441HZ){
data->right_phase -= TABLE_SIZE_441HZ;
}
}
}
static void produce_mod_audio(int16_t * pcm_buffer, int num_samples_to_write){
hxcmod_fillbuffer(&mod_context, (unsigned short *) &pcm_buffer[0], num_samples_to_write, &trkbuf);
}
static void produce_audio(int16_t * pcm_buffer, int num_samples){
switch (data_source){
case STREAM_SINE:
produce_sine_audio(pcm_buffer, &sin_data, num_samples);
break;
case STREAM_MOD:
produce_mod_audio(pcm_buffer, num_samples);
break;
}
}
static int fill_sbc_audio_buffer(a2dp_media_sending_context_t * context){
// perform sbc encodin
int total_num_bytes_read = 0;
int num_audio_samples_per_sbc_buffer = btstack_sbc_encoder_num_audio_frames();
while (context->samples_ready >= num_audio_samples_per_sbc_buffer
&& (context->max_media_payload_size - context->sbc_storage_count) >= btstack_sbc_encoder_sbc_buffer_length()){
uint8_t pcm_frame[256*BYTES_PER_AUDIO_SAMPLE];
produce_audio((int16_t *) pcm_frame, num_audio_samples_per_sbc_buffer);
btstack_sbc_encoder_process_data((int16_t *) pcm_frame);
uint16_t sbc_frame_size = btstack_sbc_encoder_sbc_buffer_length();
uint8_t * sbc_frame = btstack_sbc_encoder_sbc_buffer();
total_num_bytes_read += num_audio_samples_per_sbc_buffer;
memcpy(&context->sbc_storage[context->sbc_storage_count], sbc_frame, sbc_frame_size);
context->sbc_storage_count += sbc_frame_size;
context->samples_ready -= num_audio_samples_per_sbc_buffer;
}
return total_num_bytes_read;
}
static void avdtp_fill_audio_buffer_timeout_handler(btstack_timer_source_t * timer){
log_info("timer");
a2dp_media_sending_context_t * context = (a2dp_media_sending_context_t *) btstack_run_loop_get_timer_context(timer);
btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS);
btstack_run_loop_add_timer(&context->fill_audio_buffer_timer);
uint32_t now = btstack_run_loop_get_time_ms();
uint32_t update_period_ms = FILL_AUDIO_BUFFER_TIMEOUT_MS;
if (context->time_audio_data_sent > 0){
update_period_ms = now - context->time_audio_data_sent;
}
uint32_t num_samples = (update_period_ms * A2DP_SAMPLE_RATE) / 1000;
context->acc_num_missed_samples += (update_period_ms * A2DP_SAMPLE_RATE) % 1000;
while (context->acc_num_missed_samples >= 1000){
num_samples++;
context->acc_num_missed_samples -= 1000;
}
context->time_audio_data_sent = now;
context->samples_ready += num_samples;
if (!context->sbc_ready_to_send){
fill_sbc_audio_buffer(context);
}
if ((context->sbc_storage_count + btstack_sbc_encoder_sbc_buffer_length()) > context->max_media_payload_size){
// schedule sending
context->sbc_ready_to_send = 1;
a2dp_source_stream_endpoint_request_can_send_now(context->local_seid);
}
}
static void a2dp_fill_audio_buffer_timer_start(a2dp_media_sending_context_t * context){
context->max_media_payload_size = a2dp_max_media_payload_size(context->local_seid);
context->sbc_storage_count = 0;
context->sbc_ready_to_send = 0;
context->streaming = 1;
btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer);
btstack_run_loop_set_timer_handler(&context->fill_audio_buffer_timer, avdtp_fill_audio_buffer_timeout_handler);
btstack_run_loop_set_timer_context(&context->fill_audio_buffer_timer, context);
btstack_run_loop_set_timer(&context->fill_audio_buffer_timer, FILL_AUDIO_BUFFER_TIMEOUT_MS);
btstack_run_loop_add_timer(&context->fill_audio_buffer_timer);
}
static void a2dp_fill_audio_buffer_timer_stop(a2dp_media_sending_context_t * context){
context->time_audio_data_sent = 0;
context->acc_num_missed_samples = 0;
context->samples_ready = 0;
context->streaming = 1;
context->sbc_storage_count = 0;
context->sbc_ready_to_send = 0;
btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer);
}
static void a2dp_fill_audio_buffer_timer_pause(a2dp_media_sending_context_t * context){
// context->time_audio_data_sent = 0;
btstack_run_loop_remove_timer(&context->fill_audio_buffer_timer);
}
static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
UNUSED(ds);
UNUSED(callback_type);
int cmd = btstack_stdin_read();
switch (cmd){
case 'c':
printf("Creating L2CAP Connection to %s, PSM_AVDTP\n", bd_addr_to_str(remote));
a2dp_source_establish_stream(remote, local_seid);
break;
case 'C':
printf("Disconnect not implemented\n");
a2dp_source_disconnect(media_tracker.a2dp_cid);
break;
case 'x':
printf("Stream sine, local seid %d\n", media_tracker.local_seid);
data_source = STREAM_SINE;
a2dp_source_start_stream(media_tracker.local_seid);
break;
case 'z':
printf("Stream mode, local seid %d\n", media_tracker.local_seid);
data_source = STREAM_MOD;
a2dp_source_start_stream(media_tracker.local_seid);
break;
case 'p':
printf("Pause stream, local seid %d\n", media_tracker.local_seid);
a2dp_source_pause_stream(media_tracker.local_seid);
break;
case 'X':
printf("Close stream, local seid %d\n", media_tracker.local_seid);
a2dp_source_release_stream(media_tracker.local_seid);
break;
default:
show_usage();
break;
}
}
int btstack_main(int argc, const char * argv[]);
int btstack_main(int argc, const char * argv[]){
UNUSED(argc);
(void)argv;
/* Register for HCI events */
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
l2cap_init();
// Initialize AVDTP Sink
a2dp_source_init();
a2dp_source_register_packet_handler(&packet_handler);
//#ifndef SMG_BI
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));
// Initialize SDP
sdp_init();
memset(sdp_avdtp_source_service_buffer, 0, sizeof(sdp_avdtp_source_service_buffer));
a2dp_source_create_sdp_record(sdp_avdtp_source_service_buffer, 0x10002, 1, NULL, NULL);
sdp_register_service(sdp_avdtp_source_service_buffer);
gap_set_local_name(device_name);
gap_discoverable_control(1);
gap_set_class_of_device(0x200408);
hxcmod_initialized = hxcmod_init(&mod_context);
if (hxcmod_initialized){
hxcmod_setcfg(&mod_context, A2DP_SAMPLE_RATE, 16, 1, 1, 1);
hxcmod_load(&mod_context, (void *) &mod_data, mod_len);
printf("loaded mod '%s', size %u\n", mod_name, mod_len);
}
// turn on!
hci_power_control(HCI_POWER_ON);
btstack_stdin_setup(stdin_process);
return 0;
}

1
test/pts/.gitignore vendored
View File

@ -1,3 +1,4 @@
avdtp_source_test
ancs_client
ble_central_test
ble_central_test.h

View File

@ -1,32 +1,49 @@
# Makefile for libusb based PTS tests
BTSTACK_ROOT = ../..
CORE += \
btstack_memory.c \
btstack_linked_list.c \
btstack_memory_pool.c \
btstack_run_loop.c \
btstack_util.c \
main.c \
stdin_support.c \
main.c \
stdin_support.c \
COMMON += \
hci.c \
hci_cmd.c \
hci_dump.c \
l2cap.c \
l2cap_signaling.c \
hci_transport_h2_libusb.c \
btstack_run_loop_posix.c \
btstack_link_key_db_fs.c \
le_device_db_fs.c \
wav_util.c \
hci_transport_h2_libusb.c \
btstack_run_loop_posix.c \
btstack_link_key_db_fs.c \
le_device_db_fs.c \
wav_util.c \
sdp_util.c \
sdp_server.c \
sdp_server.c \
SBC_DECODER += \
${BTSTACK_ROOT}/src/classic/btstack_sbc_plc.c \
${BTSTACK_ROOT}/src/classic/btstack_sbc_bludroid.c \
SBC_ENCODER += \
${BTSTACK_ROOT}/src/classic/btstack_sbc_bludroid.c \
${BTSTACK_ROOT}/src/classic/hfp_msbc.c \
AVDTP += \
avdtp_util.c \
avdtp.c \
avdtp_initiator.c \
avdtp_acceptor.c \
avdtp_source.c \
btstack_ring_buffer.c \
include ${BTSTACK_ROOT}/example/Makefile.inc
include ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/Makefile.inc
include ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/Makefile.inc
CFLAGS += -g -Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wunused-variable -Wunused-parameter -Werror
CFLAGS += -I.
@ -44,31 +61,34 @@ VPATH += ${BTSTACK_ROOT}/src/classic
VPATH += ${BTSTACK_ROOT}/platform/posix
VPATH += ${BTSTACK_ROOT}/platform/libusb
VPATH += ${BTSTACK_ROOT}/port/libusb
# VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce
# VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce
VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce
VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce
# use pkg-config for libusb
CFLAGS += $(shell pkg-config libusb-1.0 --cflags)
LDFLAGS += $(shell pkg-config libusb-1.0 --libs)
# hard coded flags for libusb in /usr/local/lib
# CFLAGS += -I/usr/local/include
# LDFLAGS += -L/usr/local/lib -lusb-1.0
# use pkg-config for portaudio
# CFLAGS += $(shell pkg-config portaudio-2.0 --cflags)
# LDFLAGS += $(shell pkg-config portaudio-2.0 --libs)
# hard coded flags for portaudio in /usr/local/lib
# CFLAGS += -I/usr/local/include
# LDFLAGS += -L/sw/lib -lportaudio -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit -Wl,-framework,Carbon
CFLAGS += $(shell pkg-config portaudio-2.0 --cflags) -DHAVE_PORTAUDIO
LDFLAGS += $(shell pkg-config portaudio-2.0 --libs)
CORE_OBJ = $(CORE:.c=.o)
COMMON_OBJ = $(COMMON:.c=.o)
SBC_DECODER_OBJ = $(SBC_DECODER:.c=.o)
SBC_ENCODER_OBJ = $(SBC_ENCODER:.c=.o)
AVDTP_OBJ = $(AVDTP:.c=.o)
EXAMPLES = iopt ble_peripheral_test ble_central_test l2cap_test classic_test bnep_test hsp_ag_test hsp_hs_test sco_loopback le_data_channel
EXAMPLES = le_data_channel
EXAMPLES = avdtp_source_test le_data_channel
all: ${EXAMPLES}
# compile .gatt descriptions
avdtp_source_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SM_OBJ} ${SBC_ENCODER_OBJ} ${AVDTP_OBJ} avdtp_source_test.o
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
ble_peripheral_test.h: ble_peripheral_test.gatt
python ${BTSTACK_ROOT}/tool/compile_gatt.py $< $@
ble_central_test.h: ble_central_test.gatt
python ${BTSTACK_ROOT}/tool/compile_gatt.py $< $@
@ -101,4 +121,6 @@ sco_loopback: ${CORE_OBJ} ${COMMON_OBJ} sco_loopback.c
iopt: ${CORE_OBJ} ${COMMON_OBJ} pan.o hsp_ag.o hsp_hs.o hfp_ag.o hfp_hf.o hfp_gsm_model.o iopt.c hfp.o ${SDP_CLIENT}
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
clean:
rm -rf *.pyc *.o $(AVDTP_TESTS) *.dSYM *_test *.wav *.sbc ${BTSTACK_ROOT}/port/libusb/*.o

View File

@ -54,9 +54,10 @@
#include "hci_dump.h"
#include "l2cap.h"
#include "stdin_support.h"
#include "avdtp_source.h"
#include "btstack_sbc.h"
#include "avdtp.h"
#include "avdtp_source.h"
#include "avdtp_util.h"
typedef struct {
@ -112,7 +113,7 @@ static const char * avdtp_si_name[] = {
"AVDTP_SI_GET_CAPABILITIES",
"AVDTP_SI_SET_CONFIGURATION",
"AVDTP_SI_GET_CONFIGURATION",
"AVDTP_SI_RECONFIGURE,"
"AVDTP_SI_RECONFIGURE",
"AVDTP_SI_OPEN",
"AVDTP_SI_START",
"AVDTP_SI_CLOSE",
@ -455,7 +456,7 @@ int btstack_main(int argc, const char * argv[]){
// Initialize SDP
sdp_init();
memset(sdp_avdtp_source_service_buffer, 0, sizeof(sdp_avdtp_source_service_buffer));
a2dp_sink_create_sdp_record(sdp_avdtp_source_service_buffer, 0x10002, 1, NULL, NULL);
a2dp_source_create_sdp_record(sdp_avdtp_source_service_buffer, 0x10002, 1, NULL, NULL);
sdp_register_service(sdp_avdtp_source_service_buffer);
gap_set_local_name("BTstack A2DP Source Test");

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python
import math
import sys
SAMPLES = 100
VALUES_PER_LINE = 10
print ('''
// input signal: pre-computed sine wave, 160 Hz at 16000 kHz
static const int16_t sine_int16[] = {''')
items = 0
for sample in range(SAMPLES):
angle = (sample * 360.0) / SAMPLES
sine = math.sin(math.radians(angle))
rescaled = int(round(sine * 32767))
print ("%6d, " % rescaled),
items += 1
if items == VALUES_PER_LINE:
items = 0
print
print( "};")

View File

@ -11,6 +11,7 @@ import btstack_parser as parser
meta_events = [
'ANCS',
'AVDTP',
'A2DP',
'AVRCP',
'GOEP',
'HFP',

50
tool/sine_table_generator.py Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
import math
import sys
# 1HZ == 1 sine
# sample rate at 44100Hz, sine at 441Hz -> 441 sines in 44100 samples -> 44100/441 samples/sine
sine_array = '''
// input signal: pre-computed int16 sine wave, {sine_sample_rate} Hz at {sine_frequency} Hz
static const int16_t sine_int16[] = {{'''
VALUES_PER_LINE = 10
sine_sample_rate = 44100
sine_frequency = 441
if __name__ == "__main__":
usage = '''
Usage: ./sine_table.py sine_frequency sine_sample_rate
'''
if (len(sys.argv) < 3):
print(usage)
sys.exit(1)
sine_frequency = int(sys.argv[1])
sine_sample_rate = int(sys.argv[2])
if sine_frequency <= 0:
print(usage)
sys.exit(1)
if sine_sample_rate <= 0:
print(usage)
sys.exit(1)
sine_num_samples = sine_sample_rate/sine_frequency
print(sine_array.format(sine_sample_rate=sine_sample_rate, sine_frequency=sine_frequency))
items = 0
for sample in range(0,sine_num_samples):
items = items + 1
angle = (sample * 360.0) / sine_num_samples
sine = math.sin(math.radians(angle))
rescaled = int(round(sine * 32767))
print ("%6d, " % rescaled),
if items == VALUES_PER_LINE:
items = 0
print
print( "};")