标签:
这两天看了CSR中的A2dp和HFP协议的相关内容,主要是看如何在CSR8670上使用这两个协议。
一.A2dp协议
A2dp(Advanced Audio Distribution Profile)协议,即高级蓝牙音频传输模型协议,主要用来实现蓝牙音频传输,下面简单记录一下A2DP协议如何在CSR8670上使用。

注1:其中AudioConnect()函数是调用kalimba的DSP处理函数来实现的,所以工程目录里一个有一个对应的kalimba程序,而且应该在主程序的.mak文件将该程序的编译选项添加进去。比如:
###################################################################################################### ##### A2DP DECODER VERSIONS ###################################################################################################### # copy in sbc decoder image/sbc_decoder/sbc_decoder.kap : $(mkdir) image/sbc_decoder $(copyfile) ..\..\kalimba\apps\a2dp_sink\image\sbc_decoder\sbc_decoder.kap $@ image.fs : image/sbc_decoder/sbc_decoder.kap # copy in a2dp_low_latency_1mic decoder image/a2dp_low_latency_1mic/a2dp_low_latency_1mic.kap : $(mkdir) image/a2dp_low_latency_1mic $(copyfile) ..\..\kalimba\apps\a2dp_low_latency_1mic\image\a2dp_low_latency_1mic\a2dp_low_latency_1mic.kap $@ image.fs : image/a2dp_low_latency_1mic/a2dp_low_latency_1mic.kap
注2:AudioConnect()使用前要调用AudioLibraryInit()来初始化Audio库。
部分处理代码:
static void handleA2dpMessage(Task task, MessageId id, Message message)
{
Sink sink;
AUDIO_PLUGIN_SET_VOLUME_A2DP_MSG_T volumeInitAudio;
a2dp_codec_settings * codec_settings;
AUDIO_MODE_T mode = AUDIO_MODE_CONNECTED;
A2dpPluginConnectParams a2dp_audio_connect_params;
AudioPluginFeatures PluginFeatures;
MAIN_DEBUG(("A2dpMessage Received: [%x]\n",id));
switch(id)
{
case A2DP_INIT_CFM:
MAIN_DEBUG(("A2DP_INIT_CFM : \n"));
if( ((A2DP_INIT_CFM_T*)message)->status == a2dp_success)
{
MAIN_DEBUG(("A2DP Init success : \n"));
}
break;
case A2DP_SIGNALLING_CONNECT_IND:
MAIN_DEBUG(("A2DP_SIGNALLING_CONNECT_IND : \n"));
A2dpSignallingConnectResponse(((A2DP_SIGNALLING_CONNECT_IND_T *)message)->device_id,TRUE);
break;
case A2DP_SIGNALLING_CONNECT_CFM:
MAIN_DEBUG(("A2DP_SIGNALLING_CONNECT_CFM : \n"));
A2dpMediaOpenRequest(((A2DP_SIGNALLING_CONNECT_CFM_T*)message)->device_id, 0,NULL);
break;
case A2DP_MEDIA_OPEN_IND:
MAIN_DEBUG(("A2DP_MEDIA_OPEN_IND : \n"));
A2dpMediaOpenResponse( ((A2DP_MEDIA_OPEN_CFM_T*)message)->device_id, TRUE);
break;
case A2DP_MEDIA_OPEN_CFM:
MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM : \n"));
if( ((A2DP_MEDIA_OPEN_CFM_T*)message)->status == a2dp_success )
{
MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM SUCEESS: \n"));
}
else
{
MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM FAIL: \n"));
}
break;
case A2DP_MEDIA_START_IND:
MAIN_DEBUG(("A2DP_MEDIA_START_IND : \n"));
A2dpMediaStartResponse(((A2DP_MEDIA_START_IND_T*)message)->device_id, ((A2DP_MEDIA_START_IND_T*)message)->stream_id, TRUE);
break;
case A2DP_MEDIA_START_CFM:
MAIN_DEBUG(("A2DP_MEDIA_START_CFM : \n"));
if( ((A2DP_MEDIA_START_CFM_T*)message)->status == a2dp_success)
{
MAIN_DEBUG(("A2DP_MEDIA_START_CFM SUCESS: \n"));
sink = A2dpMediaGetSink( ((A2DP_MEDIA_START_CFM_T*)message)->device_id, ((A2DP_MEDIA_START_CFM_T*)message)->stream_id);
if(sink)
{
codec_settings = A2dpCodecGetSettings( ((A2DP_MEDIA_START_CFM_T*)message)->device_id, ((A2DP_MEDIA_START_CFM_T*)message)->stream_id);
if(codec_settings)
{
a2dp_audio_connect_params.packet_size = codec_settings->codecData.packet_size; /* Packet size retrieved from a2dp library */
a2dp_audio_connect_params.content_protection = codec_settings->codecData.content_protection; /* content protection retrieved from a2dp library */
a2dp_audio_connect_params.clock_mismatch =0xFF59; /*clock mismatch rate for this device */
a2dp_audio_connect_params.currentEQ =0x0000;
a2dp_audio_connect_params.enhancements =0x0000;
a2dp_audio_connect_params.silence_threshold =0x0000;
a2dp_audio_connect_params.silence_trigger_time =0x0000;
a2dp_audio_connect_params.speaker_pio =0x0000;
theSink.a2dp_audio_mode_params.music_mode_processing = A2DP_MUSIC_PROCESSING_FULL_SET_EQ_BANK0;
theSink.a2dp_audio_mode_params.external_mic_settings = EXTERNAL_MIC_NOT_FITTED;
theSink.a2dp_audio_mode_params.mic_mute = SEND_PATH_UNMUTE;
theSink.a2dp_audio_mode_params.external_volume_enabled = 0;
theSink.a2dp_audio_mode_params.master_routing_mode = 1;
theSink.a2dp_audio_mode_params.slave_routing_mode = 2;
theSink.a2dp_audio_mode_params.unused = 0;
theSink.a2dp_audio_mode_params.music_mode_enhancements = 0x0040;
/* We need to set A2DP volume info as the audio is in mute state after connection */
volumeInitAudio.volume_type = DIGITAL_ONLY;
volumeInitAudio.codec_task = theSink.codecTask;
volumeInitAudio.system_gain = 15;
volumeInitAudio.trim_gain_left = 0;
volumeInitAudio.trim_gain_right= 0;
volumeInitAudio.mute_active = FALSE;
PluginFeatures.audio_output_type = OUTPUT_INTERFACE_TYPE_NONE;
/* connect the audio via the audio plugin */
AudioConnect((TaskData *)&csr_sbc_decoder_plugin,
sink ,
AUDIO_SINK_AV ,
theSink.codecTask,
volumeInitAudio.tones_gain,
codec_settings->rate,
PluginFeatures ,
mode,
AUDIO_ROUTE_INTERNAL,
(AUDIO_POWER_T)POWER_BATT_LEVEL3,
&a2dp_audio_connect_params,
&theSink.task);
AudioSetVolumeA2DP(&volumeInitAudio);
AudioSetMode(mode, &theSink.a2dp_audio_mode_params);
}
}
}
break;
default:
MAIN_DEBUG(("unRecognised A2DP Message: [%x]\n",id));
break;
}
}
注:参数都是临时的,真正开发的时候应该将其配置在CSR的PSKEY上。
二.HFP协议
HFP(Hands-free Profile)协议,主要用来处理蓝牙语音连接的协议,通常用它来实现接听、挂断、拒接、语音拨号等功能。其实现方法和A2DP协议类似,直接上图。

部分处理代码:
static void handleHFPMessage(Task task, MessageId id, Message message)
{
AudioPluginFeatures features;
sep_data_type seps[1];
typed_bdaddr ag_addr;
Sink sink;
sync_pkt_type packet_types;
hfp_audio_params audio_params;
bool disable_wbs_override = FALSE;
pio_config_type* pio;
uint16 ps_ret_len = 0;
MAIN_DEBUG(("HFPMessage Received: [%x]\n",id));
switch(id)
{
case HFP_INIT_CFM:
MAIN_DEBUG(("HFP_INIT_CFM\n"));
seps[0].sep_config = codecList[0].config;
seps[0].in_use = FALSE;
A2dpInit(&theSink.task, A2DP_INIT_ROLE_SINK, NULL, 1, seps, 60);
ConnectionWriteClassOfDevice(AUDIO_MAJOR_SERV_CLASS | AV_MAJOR_DEVICE_CLASS | AV_MINOR_HEADSET);
if ( ((HFP_INIT_CFM_T*)message)->status == hfp_success )
{
MAIN_DEBUG(("hfp_success\n"));
}
else
Panic();
break;
case HFP_SLC_CONNECT_IND:
MAIN_DEBUG(("HFP_SLC_CONNECT_IND [%x]\n", ((HFP_SLC_CONNECT_IND_T *) message)->accepted ));
break;
case HFP_SLC_CONNECT_CFM:
MAIN_DEBUG(("HFP_SLC_CONNECT_CFM [%x]\n", ((HFP_SLC_CONNECT_CFM_T *) message)->status ));
break;
case HFP_RING_IND:
MAIN_DEBUG(("HFP_RING_IND\n"));
features.audio_output_type = OUTPUT_INTERFACE_TYPE_NONE;
AudioPlayTone( good_tone , TRUE , theSink.codecTask, 0x15, features) ;
break;
case HFP_SLC_LINK_LOSS_IND:
MAIN_DEBUG(("HFP_SLC_LINK_LOSS_IND\n"));
if( ((HFP_SLC_LINK_LOSS_IND_T*)message)->status == hfp_link_loss_recovery)
{
MAIN_DEBUG(("hfp_link_loss_recovery \n"));
}
else if( ((HFP_SLC_LINK_LOSS_IND_T*)message)->status == hfp_link_loss_none)
{
MAIN_DEBUG(("hfp_link_loss_none \n"));
}
HfpLinkGetSlcSink( ((HFP_SLC_LINK_LOSS_IND_T*)message)->priority, &sink);
SinkGetBdAddr(sink, &ag_addr);
A2dpSignallingConnectRequest((bdaddr *)&ag_addr.addr);
break;
case HFP_SERVICE_IND:
MAIN_DEBUG(("HFP_SERVICE_IND [%x]\n" , ((HFP_SERVICE_IND_T*)message)->service ));
break;
case HFP_SIGNAL_IND:
MAIN_DEBUG(("HS: HFP_SIGNAL_IND [%d]\n", ((HFP_SIGNAL_IND_T* )message)->signal )) ;
break ;
case HFP_ROAM_IND:
MAIN_DEBUG(("HS: HFP_ROAM_IND [%d]\n", ((HFP_ROAM_IND_T* )message)->roam )) ;
break;
case HFP_BATTCHG_IND:
MAIN_DEBUG(("HS: HFP_BATTCHG_IND [%d]\n", ((HFP_BATTCHG_IND_T* )message)->battchg )) ;
break;
case HFP_AUDIO_CONNECT_IND:
MAIN_DEBUG(("HFP_AUDIO_CONNECT_IND\n")) ;
packet_types = sync_all_sco;
disable_wbs_override = TRUE;
audio_params.bandwidth = 0x1f40;
audio_params.max_latency = 0xc;
audio_params.voice_settings = 0;
audio_params.retx_effort = sync_retx_link_quality;
HfpAudioConnectResponse( ((HFP_AUDIO_CONNECT_IND_T *)message)->priority, TRUE, packet_types, &audio_params, TRUE);
break ;
case HFP_AUDIO_CONNECT_CFM:
MAIN_DEBUG(("HFP_AUDIO_CONNECT_CFM\n")) ;
if( ((HFP_AUDIO_CONNECT_CFM_T *)message)->status == hfp_success)
{
HfpLinkGetSlcSink( ((HFP_AUDIO_CONNECT_IND_T*)message)->priority, &sink);
features.audio_output_type = OUTPUT_INTERFACE_TYPE_NONE;
pio = malloc( sizeof(pio_config_type) );
memset(pio, 0, sizeof (pio_config_type));
ps_ret_len = PsRetrieve(16, pio, sizeof (pio_config_type) );
MAIN_DEBUG(("ps return len:[%x]",ps_ret_len)) ;
theSink.digital = malloc( sizeof(common_mic_params) );
(theSink.digital)->mic_a.digital = 0;
(theSink.digital)->mic_a.pre_amp = 1;
(theSink.digital)->mic_a.drive_pio = 1;
(theSink.digital)->mic_a.pio = 0;
(theSink.digital)->mic_a.bias = 1;
(theSink.digital)->mic_a.unused = 0;
(theSink.digital)->mic_a.gain = 5;
(theSink.digital)->mic_b.digital = 0;
(theSink.digital)->mic_b.pre_amp = 1;
(theSink.digital)->mic_b.drive_pio = 1;
(theSink.digital)->mic_b.pio = 1;
(theSink.digital)->mic_b.bias = 1;
(theSink.digital)->mic_b.unused = 0;
(theSink.digital)->mic_b.gain = 5;
(theSink.digital)->line_a.digital = 0;
(theSink.digital)->line_a.pre_amp = 0;
(theSink.digital)->line_a.drive_pio = 0;
(theSink.digital)->line_a.pio = 0;
(theSink.digital)->line_a.bias = 0;
(theSink.digital)->line_a.unused = 0;
(theSink.digital)->line_a.gain = 15;
(theSink.digital)->line_b.digital = 0;
(theSink.digital)->line_b.pre_amp = 0;
(theSink.digital)->line_b.drive_pio = 0;
(theSink.digital)->line_b.pio = 0;
(theSink.digital)->line_b.bias = 0;
(theSink.digital)->line_b.unused = 0;
(theSink.digital)->line_b.gain = 15;
theSink.plugin_params.digital = theSink.digital;
theSink.dsp_data.key.key = 0x0063;
theSink.dsp_data.key.len = 48;
theSink.dsp_data.key.cur_len = 0;
theSink.dsp_data.key.cache = theSink.dsp_data.cache;
PblockInit(&theSink.dsp_data.key);
/* connect audio using the audio plugin selected above */
AudioConnect ( CVCHS1MICWBS,/*CVCHS1MIC*/
sink,
sync_link_esco,/*sync_link_esco*/
theSink.codecTask ,
20,
0x00001F40,
features,
AUDIO_MODE_CONNECTED,
AUDIO_ROUTE_INTERNAL,
(AUDIO_POWER_T)POWER_BATT_LEVEL3,
&theSink.plugin_params,
NULL) ;
}
AudioSetVolume ( 20, 20, theSink.codecTask );
theSink.a2dp_audio_mode_params.music_mode_processing = A2DP_MUSIC_PROCESSING_FULL_SET_EQ_BANK0;
theSink.a2dp_audio_mode_params.external_mic_settings = 1;
theSink.a2dp_audio_mode_params.mic_mute = 1;
theSink.a2dp_audio_mode_params.external_volume_enabled = 0;
theSink.a2dp_audio_mode_params.master_routing_mode = 1;
theSink.a2dp_audio_mode_params.slave_routing_mode = 2;
theSink.a2dp_audio_mode_params.unused = 0;
theSink.a2dp_audio_mode_params.music_mode_enhancements = 0;
/* mute control */
AudioSetMode(AUDIO_MODE_CONNECTED, &theSink.a2dp_audio_mode_params);
break;
default:
MAIN_DEBUG(("unRecognised HFP Message: [%x]\n",id));
break;
}
}
注:参数都是临时的,真正开发的时候应该将其配置在CSR的PSKEY上。
标签:
原文地址:http://www.cnblogs.com/fingertouch/p/4643794.html