zoukankan      html  css  js  c++  java
  • A2dp和HFP的使用

    这两天看了CSR中的A2dp和HFP协议的相关内容,主要是看如何在CSR8670上使用这两个协议。

    一.A2dp协议

    A2dp(Advanced Audio Distribution Profile)协议,即高级蓝牙音频传输模型协议,主要用来实现蓝牙音频传输,下面简单记录一下A2DP协议如何在CSR8670上使用。

    1. 调用ConnectionWriteScanEnable(hci_scan_enable_page)让蓝牙设备可以scan和page;
    2. 调用A2dpInit()初始化A2dp库;
    3. 编写handleA2dpMessage()函数处理A2dp消息。

    注1:其中AudioConnect()函数是调用kalimba的DSP处理函数来实现的,所以工程目录里一个有一个对应的kalimba程序,而且应该在主程序的.mak文件将该程序的编译选项添加进去。比如:

    ######################################################################################################
    ##### A2DP DECODER VERSIONS
    ######################################################################################################
    
    # copy in sbc decoder 
    image/sbc_decoder/sbc_decoder.kap :
    	$(mkdir) image/sbc_decoder
    	$(copyfile) ....kalimbaappsa2dp_sinkimagesbc_decodersbc_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) ....kalimbaappsa2dp_low_latency_1micimagea2dp_low_latency_1mica2dp_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]
    ",id));
        
        switch(id)
        {
            case A2DP_INIT_CFM:
                 MAIN_DEBUG(("A2DP_INIT_CFM : 
    "));
                 if( ((A2DP_INIT_CFM_T*)message)->status == a2dp_success)
                 {
                     MAIN_DEBUG(("A2DP Init success : 
    "));
                 }
                 break;
             case A2DP_SIGNALLING_CONNECT_IND:
                 MAIN_DEBUG(("A2DP_SIGNALLING_CONNECT_IND : 
    "));
                 A2dpSignallingConnectResponse(((A2DP_SIGNALLING_CONNECT_IND_T *)message)->device_id,TRUE);
                 break;
             case A2DP_SIGNALLING_CONNECT_CFM:
                 MAIN_DEBUG(("A2DP_SIGNALLING_CONNECT_CFM : 
    ")); 
                 A2dpMediaOpenRequest(((A2DP_SIGNALLING_CONNECT_CFM_T*)message)->device_id, 0,NULL);
                 break;
             case A2DP_MEDIA_OPEN_IND:
                 MAIN_DEBUG(("A2DP_MEDIA_OPEN_IND : 
    "));
                 A2dpMediaOpenResponse( ((A2DP_MEDIA_OPEN_CFM_T*)message)->device_id, TRUE);
                 break;
             case A2DP_MEDIA_OPEN_CFM:
                 MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM : 
    "));
                 if( ((A2DP_MEDIA_OPEN_CFM_T*)message)->status == a2dp_success )
                 {
                     MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM SUCEESS: 
    "));
                 }
                 else
                 {
                     MAIN_DEBUG(("A2DP_MEDIA_OPEN_CFM FAIL: 
    "));
                 }
                 break;
             case A2DP_MEDIA_START_IND:
                 MAIN_DEBUG(("A2DP_MEDIA_START_IND : 
    "));
                 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 : 
    "));
                 if( ((A2DP_MEDIA_START_CFM_T*)message)->status == a2dp_success)
                 {
                     MAIN_DEBUG(("A2DP_MEDIA_START_CFM SUCESS: 
    "));
                     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]
    ",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]
    ",id));
        
        switch(id)
        {
            case HFP_INIT_CFM:
                MAIN_DEBUG(("HFP_INIT_CFM
    "));
                
                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
    "));
                }
                else
                    Panic();
                break;
            case HFP_SLC_CONNECT_IND:
                MAIN_DEBUG(("HFP_SLC_CONNECT_IND [%x]
    ", ((HFP_SLC_CONNECT_IND_T *) message)->accepted ));
                
                break;
            case HFP_SLC_CONNECT_CFM:
                MAIN_DEBUG(("HFP_SLC_CONNECT_CFM [%x]
    ", ((HFP_SLC_CONNECT_CFM_T *) message)->status ));
                
                break;
            case HFP_RING_IND:
                MAIN_DEBUG(("HFP_RING_IND
    "));    
                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
    "));
                if( ((HFP_SLC_LINK_LOSS_IND_T*)message)->status == hfp_link_loss_recovery)
                {
                     MAIN_DEBUG(("hfp_link_loss_recovery 
    ")); 
                }
                else if(  ((HFP_SLC_LINK_LOSS_IND_T*)message)->status == hfp_link_loss_none)
                {
                     MAIN_DEBUG(("hfp_link_loss_none 
    ")); 
                }
                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]
    " , ((HFP_SERVICE_IND_T*)message)->service  ));       
                break;
            case HFP_SIGNAL_IND:
                MAIN_DEBUG(("HS: HFP_SIGNAL_IND [%d]
    ", ((HFP_SIGNAL_IND_T* )message)->signal )) ; 
                break ;
            case HFP_ROAM_IND:
                MAIN_DEBUG(("HS: HFP_ROAM_IND [%d]
    ", ((HFP_ROAM_IND_T* )message)->roam )) ;
                break; 
            case HFP_BATTCHG_IND:     
                MAIN_DEBUG(("HS: HFP_BATTCHG_IND [%d]
    ", ((HFP_BATTCHG_IND_T* )message)->battchg )) ;
                break;
            case HFP_AUDIO_CONNECT_IND:
                MAIN_DEBUG(("HFP_AUDIO_CONNECT_IND
    ")) ;
                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
    ")) ;
                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]
    ",id));
                break;
        }
    }
    

      注:参数都是临时的,真正开发的时候应该将其配置在CSR的PSKEY上。

  • 相关阅读:
    django 项目需要注意的一些点
    VUE之路
    Oracle 表格碎片的查看方法
    RHEL 6.x or 7.x 使用分区绑定ASM 磁盘的方法
    RMAN 修复主库 nologging 操作导致物理备库的坏块
    Oracle 数据库19c 回退降级到 11.2.0.4 方案
    如何评估oracle 数据库rman全备和增量备份大小
    在将Oracle GI和DB升级到19c或降级到以前的版本之前需要应用的补丁 (Doc ID 2668071.1)
    Oracle 数据库坏块处理
    opatch auto 安装11.2.0.4.20190115 PSU遇到 OUI-67133: Execution of PRE script failed,with returen value 1 报错
  • 原文地址:https://www.cnblogs.com/fingertouch/p/4643794.html
Copyright © 2011-2022 走看看