A2DP - Advanced Audio Distribution Profile
A2DP提供通過藍(lán)牙連接傳輸音頻流的能力,比如手機(jī)播放音樂,藍(lán)牙耳機(jī)通過藍(lán)牙連接聽歌。在上面的例子中,手機(jī)扮演A2DP源(Source)的角色,藍(lán)牙耳機(jī)扮演A2DP接收器(Sink)的角色。因此A2DP服務(wù)是單項(xiàng)傳輸,無論是單聲道(mono)還是雙聲道(stereo)。A2DP主要實(shí)現(xiàn)SDC(sub band codec,默認(rèn)的a2dp編解碼方式),AAC,F(xiàn)DK, LDAC,APTX等簡單codec。
A2DP的服務(wù)能力
A2DP服務(wù)是需要和AVRCP服務(wù)一起使用的。AVRCP控制器用來獲取A2DP源的數(shù)據(jù)信息,如title(曲名),artist(演唱者),album(專輯)及控制命令(play,stop,repeat等)。
1,A2DP接收器(Sink)
需要注冊(cè)的回調(diào):
1,hci_packet_handler (注冊(cè)回調(diào)處理接收到的包,比如發(fā)現(xiàn)包,配對(duì)包,數(shù)據(jù)包等等)
2,a2dp_sink_packet_handler(注冊(cè)回調(diào)處理連接事件,如established/released,并執(zhí)行對(duì)應(yīng)的配置工作,如codec配置;處理播放狀態(tài)如opened,paused,stopped,并執(zhí)行對(duì)應(yīng)的動(dòng)作;
3,handle_l2cap_media_data_packet(注冊(cè)回調(diào)處理音頻流數(shù)據(jù),支持存儲(chǔ)和播放,默認(rèn)是SBC編碼格式,可以解碼成PCM進(jìn)行播放)
4,avrcp_packet_handler(注冊(cè)回調(diào)處理avrcp的命令回調(diào),如connect,disconnect等)
5,avrcp_controller_packet_handler(注冊(cè)回調(diào)處理avrcp命令和消息通知,如poschanged,statuschanged等)
6,stdin_process,用戶控制的回調(diào)
A2DP和AVRCP服務(wù)配置
應(yīng)用層需要?jiǎng)?chuàng)建A2DP和AVRCP的SDP記錄,然后注冊(cè)在SDP服務(wù)里
// 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);
所以整個(gè)服務(wù)啟動(dòng)流程如下:
1,l2cap_init();? //初始化藍(lán)牙鏈路
2,sm_init(); //初始化security manager,BLE也就是藍(lán)牙4.0后需要;
3,a2dp_sink_init();? //初始化a2dp和回調(diào)
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(...); //初始化音頻流終端,并進(jìn)行對(duì)應(yīng)的配置如codec,大小等,可視作處理音頻流的具體對(duì)象)
5,avrcp_init();? ? //初始化avrcp并注冊(cè)回調(diào)
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,其他設(shè)備可以發(fā)現(xiàn)a2dp和avrcp服務(wù)
?// Create A2DP Sink service record and register it with SDP? ?
memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));? ? // 150字節(jié)內(nèi)存
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");? ? //設(shè)置設(shè)備名稱和address(mac地址)
gap_discoverable_control(1);? ? //可被發(fā)現(xiàn)
gap_set_class_of_device(0x200408); //設(shè)置device class
8,hci_event_callback_registration.callback = &hci_packet_handler;? ? // Register for HCI events?
hci_add_event_handler(&hci_event_callback_registration);
總結(jié):從底到頂?shù)呐渲眠^程就是:初始化l2cap, sm(如果要支持ble)-> 注冊(cè)hci回調(diào)->配置gap(名稱,地址,設(shè)備類型,并確認(rèn)可被發(fā)現(xiàn))-> 配置SDP(設(shè)備id,產(chǎn)品id,avrcp和a2dp的服務(wù)配置)-> 初始化avrcp, avrcp target, avrcp controller及a2dp sink(source),stream endpoint并注冊(cè)對(duì)應(yīng)的回調(diào)
2,A2DP源(Source)
成為A2DP源需要應(yīng)用的藍(lán)牙協(xié)議棧和Sink大致一樣。區(qū)別主要在以下內(nèi)容:
1,A2DP源在經(jīng)典藍(lán)牙協(xié)議框架里是作為master設(shè)備存在,不是外設(shè),所以需要配置hci:hci_set_master_slave_policy(0),0是master,1是讓連接設(shè)備確認(rèn);
2,不同于A2DP Sink,A2DP初始化源的過程相對(duì)簡單,只需要a2dp_source_init()和a2dp_source_register_packet_handler就可,此handle為處理音頻流的handle;
3,stream_endpoint和avrcp初始化和Sink一樣,同理SDP,GAP都一樣
4,配置音頻流,如采樣率等
總結(jié):大致和A2DP接收器一樣,只是具體角色和handle不一樣