• 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上。

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    开源数据库在平安的应用实践
    从Oracle到PostgreSQL:Storage Index 特性 vs BRIN 索引
    Cosmos 白皮书
    基于支付场景下的微服务改造与性能优化
    MySQL数据库备份之主从同步配置
    Maven Gradle 区别
    荐书:《PostgreSQL指南:内幕探索》| 留言送书
    SQL、NoSQL、NewSQL,论开源之路谁主沉浮
  • 原文地址:https://www.cnblogs.com/fingertouch/p/4643794.html
Copyright © 2020-2023  润新知