MTK音頻播放器案例實現
MTK音頻播放器案例實現是本文介紹的內容,主要是介紹MTK音頻播放器的使用。MTK 6225上的audio player 的結構整體上可以分為三層,最上面的應用程序界面層, 中間的audio 播放api層, 和底層的編解碼庫及音頻驅動. 其結構圖大致如下所示:
由上圖可以看出,整個調用層次較深. 我們分別來學習個層.
1、MMI Task 層
在該層 audio player 模塊實現了播放器程序, 其中主要包括對界面視圖的實現, 界面邏輯的處理以及調用MID模塊的接口,實現音頻操作. 在學習其具體的實現細節(jié)上,可以按view 和 model+control的簡化MVC模式來看, 包含與顯示有關的screen操作顯示部分, 處理消息的msghandler部分以及主的程序邏輯及按鍵處理部分.
MTK平臺對事件的處理是通過callback function方式, 所以程序的流程不是順序的, 事件的發(fā)生將導致相應的callback被調用, 從而觸發(fā)整個audio player的一次響應. 需要注意的是,在每個不同的界面對相同事件的處理callback函數可能有所不同, 這是在創(chuàng)建,進入該界面時設定的.
該模塊的接口比較復雜,為了提供對BT的統一接口, 有兩層的播放接口,如mmi_audply_play 和 mmi_audply_do_play_action(). 整個模塊的接口不夠清晰, 有些龐雜和混亂. 模塊的顯示部分使用控件實現,較為簡單, 可進一步參考控件的實現細節(jié)以了解平臺的顯示子系統, 對播放文件列表的管理是通過文件操作實現的,具體可參見audioplayerplaylist部分.
MDI層和Media接口層,這兩個部分可看作一個整體, 是MMI層對媒體操作的封裝.它包括了多個部分的接口,在此我們只看audio接口部分,其他模塊如video,fm的接口類似. Audio接口包括了播放,暫停,停止,獲取播放時間,獲取播放頻譜等. 這些接口基本上都是按同步處理方式實現的. 比如播放接口:
MDI層接口是
- mdi_result mdi_audio_play_file(void *file_name, U8 play_style, void *cache_p, mdi_callback handler);
調用的Media接口為:
- kal_int32 media_aud_play_file(module_type src_mod_id, void *file_param)
- {
- aud_result = MED_RES_OK;
- aud_send_play_file_req(src_mod_id, file_param);
- AUD_WAIT_EVENT(AUD_EVT_PLAY);
- return aud_result;
- }
其中的aud_send_play_file_req(src_mod_id, file_param調用msg_send_ext_queue(ilm_ptr);
向media task的external Message queue 發(fā)送播放請求消息.其中AUD_WAIT_EVENT(AUD_EVT_PLAY);定義如下:
- #define AUD_WAIT_EVENT(evt_) do{
- kal_uint32 retrieved_events;
- kal_retrieve_eg_events(aud_context_p->aud_event, (evt_),
- KAL_OR_CONSUME, &retrieved_events, KAL_SUSPEND); }while(0)
等待AUD_EVT_PLAY事件的到達. 通過事件實現了同步.
2、Media Task層, media task啟動后, med_task_main在獲得外部消息后,調用med_main((void*)¤t_ilm);進行消息處理, med_main會根據消息類型再進行一次
分發(fā) ,audio消息會被分發(fā)給void aud_main(ilm_struct *ilm_ptr)來進行處理. 根據相應的請求消息,aud_main調用相應的handler函數進行處理.如對播放請求消息MSG_ID_L4AUD_MEDIA_PLAY_REQ的處理函數如下:
- void aud_media_play_req_hdlr(ilm_struct *ilm_ptr)
- {
- …. // 省略其他分支處理,及錯誤處理
- // step 1::釋放沖突資源, 設置播放的參數等
- // step 2: 根據格式選擇播放函數
- switch (aud_context_p->current_format)
- {
- ...
- case MED_TYPE_MMF:
- result = aud_melody_play_by_name(msg_p->file_name, msg_p->play_style, 0);
- break;
- …
- case MED_TYPE_M4A:
- aud_context_p->source_type = AUD_FILE;
- aud_context_p->play_style = msg_p->play_style;
- result = aud_media_play_file_stream(
- msg_p->file_name,
- msg_p->play_style,
- 1,
- KAL_FALSE,
- msg_p->cache_p);
- break;
- case MED_TYPE_3GP:
- case MED_TYPE_MP4:
- aud_context_p->source_type = AUD_FILE;
- aud_context_p->play_style = msg_p->play_style;
- result = aud_media_play_audio_track_in_video(
- msg_p->file_name,
- msg_p->play_style,
- KAL_TRUE,
- KAL_FALSE);
- break;
- default:
- result = MED_RES_INVALID_FORMAT;
- break;
- }
- // step 3: 開始播放后處理
- aud_set_result((kal_int32) result); // 設置播放操作返回結果
- AUD_SET_EVENT(AUD_EVT_PLAY); // 設置AUD_EVT_PLAY事件
- if (aud_context_p->src_mod != MOD_MMI) //播放請求是否來自MMI task
- {
- aud_send_media_play_cnf(result); //發(fā)送播放反饋消息到請求模塊
- }
- }
3、L1Audio module層, 該層包括了底層的解碼庫和對更底層的驅動程序,及音頻硬件的調用和處理. 其中包括了對具體的音頻格式的處理接口,如對AAC文件的接口有:
- MHdl *AAC_Open(void(*handler)( MHdl *handle, Media_Event event ),
- STFSAL *pstFSAL, void *param)
- Media_Status aacMFPlayFile( MHdl *hdl );
- Media_Status aacMFResumeFile( MHdl *hdl );
- Media_Status aacMFPause( MHdl *hdl );
- Media_Status aacMFStop( MHdl *hdl );
....
一整套的接口. 在上面的第二層的講解中的play請求的處理函數中, 如果待處理的文件格式是AAC, 則實現上它會調用AAC_Open接口來獲得與播放操作相關的所有函數接口. 為此后的其他操作提供處理函數.
MTK的task和mod是怎么劃分的?
實在搞不清MTK中task與mod,一個task就只加載一個mod么?
在task_init.c 里面void InitApplication()中,
- for(i=0;i<TOTAL_TASKS-9;i++)
- {
- task_info_g1[i+9].task_ext_qid=OslCreateMsgQ(task_create_tbl[i].task_qname,
- sizeof(MYQUEUE),
- task_create_tbl[i].task_ext_qsize);
- task_info_g1[i+9].task_id = osl_create_task (task_create_tbl[i].task_name,
- task_create_tbl[i].task_priority,
- task_create_tbl[i].task_stack_size,
- task_create_tbl[i].task_entry_func,
- (void *)(i+9),0);
- task_info_g1[i+9].task_name=task_create_tbl[i].task_name;
- task_info_g1[i+9].task_priority=task_create_tbl[i].task_priority;
- task_info_g1[i+9].task_stack_size=task_create_tbl[i].task_stack_size;
- task_info_g1[i+9].task_entry_func=task_create_tbl[i].task_entry_func;
- task_info_g1[i+9].task_qname=task_create_tbl[i].task_qname;
- task_info_g1[i+9].task_ext_qsize=task_create_tbl[i].task_ext_qsize;
- }
這里為什么是task_info_g1[i+9],在0到9的位置上還有 別的什么任務在運行?
這里生成的各個任務,TOTAL_TASKS的定義,我選取了MMItask.c中的一個如下:
- #ifdef MMI_ON_WIN32
- #define MOD_MMI MOD_PRT
- typedef enum {
- MOD_DUM1=0x09,
- MOD_L4C1,
- MOD_PRT,
- MOD_DUM2,
- TOTAL_TASKS
- }task_indx_type;
- extern osl_task_info task_info_g1[TOTAL_TASKS];
- #endif
這一看, 在task生成之時,就把task和mod對上關系了。但是任務通信時,又有很多msg_send_ext_queue 和receive_ext_queue,src_mod_id 和dest_mod_id,分別為不同的mod。
請教除了MMI task與MOD_MMI,別的mod在哪些任務中運行?
不是的。task就像一個進程一樣在運行,當從隊列中得到消息后就被喚醒。
一個task可以加載N個mod。
小結:MTK音頻播放器案例實現的內容介紹完了,希望通過本文的學習能對你有所幫助!