A2DP - Advanced Audio Distribution Profile
A2DP提供通过蓝牙连接传输音频流的能力,比如手机播放音乐,蓝牙耳机通过蓝牙连接听歌。在上面的例子中,手机扮演A2DP源(Source)的角色,蓝牙耳机扮演A2DP接收器(Sink)的角色。因此A2DP服务是单项传输,无论是单声道(mono)还是双声道(stereo)。A2DP主要实现SDC(sub band codec,默认的a2dp编解码方式),AAC,FDK, LDAC,APTX等简单codec。
A2DP的服务能力
A2DP服务是需要和AVRCP服务一起使用的。AVRCP控制器用来获取A2DP源的数据信息,如title(曲名),artist(演唱者),album(专辑)及控制命令(play,stop,repeat等)。
1,A2DP接收器(Sink)
需要注册的回调:
1,hci_packet_handler (注册回调处理接收到的包,比如发现包,配对包,数据包等等)
2,a2dp_sink_packet_handler(注册回调处理连接事件,如established/released,并执行对应的配置工作,如codec配置;处理播放状态如opened,paused,stopped,并执行对应的动作;
3,handle_l2cap_media_data_packet(注册回调处理音频流数据,支持存储和播放,默认是SBC编码格式,可以解码成PCM进行播放)
4,avrcp_packet_handler(注册回调处理avrcp的命令回调,如connect,disconnect等)
5,avrcp_controller_packet_handler(注册回调处理avrcp命令和消息通知,如poschanged,statuschanged等)
6,stdin_process,用户控制的回调
A2DP和AVRCP服务配置
应用层需要创建A2DP和AVRCP的SDP记录,然后注册在SDP服务里
// Initialize SDP
sdp_init();
// Create A2DP Sink service record and register it with SDP
memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));
a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL);
sdp_register_service(sdp_avdtp_sink_service_buffer);
所以整个服务启动流程如下:
1,l2cap_init(); //初始化蓝牙链路
2,sm_init(); //初始化security manager,BLE也就是蓝牙4.0后需要;
3,a2dp_sink_init(); //初始化a2dp和回调
a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler); a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet);
4,local_stream_endpoint = a2dp_sink_create_stream_endpoint(...); //初始化音频流终端,并进行对应的配置如codec,大小等,可视作处理音频流的具体对象)
5,avrcp_init(); //初始化avrcp并注册回调
avrcp_register_packet_handler(&avrcp_packet_handler);
// Initialize AVRCP Controller
avrcp_controller_init();
avrcp_controller_register_packet_handler(&avrcp_controller_packet_handler);
// Initialize AVRCP Target
avrcp_target_init();
avrcp_target_register_packet_handler(&avrcp_target_packet_handler);
6,sdp_init(); //初始化sdp,其他设备可以发现a2dp和avrcp服务
// Create A2DP Sink service record and register it with SDP
memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer)); // 150字节内存
a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL);
sdp_register_service(sdp_avdtp_sink_service_buffer);
avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, 0x10002, controller_supported_features, NULL, NULL);
sdp_register_service(sdp_avrcp_controller_service_buffer);
// Create AVRCP Target service record and register it with SDP. We receive Category 2 commands from the media player, e.g. volume up/down
memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer));
uint16_t target_supported_features = AVRCP_FEATURE_MASK_CATEGORY_MONITOR_OR_AMPLIFIER;
avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer, 0x10003, target_supported_features, NULL, NULL);
sdp_register_service(sdp_avrcp_target_service_buffer);
// Create Device ID (PnP) service record and register it with SDP
memset(device_id_sdp_service_buffer, 0, sizeof(device_id_sdp_service_buffer));
device_id_create_sdp_record(device_id_sdp_service_buffer, 0x10004, DEVICE_ID_VENDOR_ID_SOURCE_BLUETOOTH, BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH, 1, 1);
sdp_register_service(device_id_sdp_service_buffer);
7,gap_set_local_name("A2DP Sink Demo 00:00:00:00:00:00"); //设置设备名称和address(mac地址)
gap_discoverable_control(1); //可被发现
gap_set_class_of_device(0x200408); //设置device class
8,hci_event_callback_registration.callback = &hci_packet_handler; // Register for HCI events
hci_add_event_handler(&hci_event_callback_registration);
总结:从底到顶的配置过程就是:初始化l2cap, sm(如果要支持ble)-> 注册hci回调->配置gap(名称,地址,设备类型,并确认可被发现)-> 配置SDP(设备id,产品id,avrcp和a2dp的服务配置)-> 初始化avrcp, avrcp target, avrcp controller及a2dp sink(source),stream endpoint并注册对应的回调
2,A2DP源(Source)
成为A2DP源需要应用的蓝牙协议栈和Sink大致一样。区别主要在以下内容:
1,A2DP源在经典蓝牙协议框架里是作为master设备存在,不是外设,所以需要配置hci:hci_set_master_slave_policy(0),0是master,1是让连接设备确认;
2,不同于A2DP Sink,A2DP初始化源的过程相对简单,只需要a2dp_source_init()和a2dp_source_register_packet_handler就可,此handle为处理音频流的handle;
3,stream_endpoint和avrcp初始化和Sink一样,同理SDP,GAP都一样
4,配置音频流,如采样率等
总结:大致和A2DP接收器一样,只是具体角色和handle不一样