MTK 6225 平台 audio player 学习笔记
Mtk 6225 上的 audio player 的结构整体上可以分为三层, 最上面的应用程序界面层, 中
间的 audio 播放 api 层, 和底层的编解码库及音频驱动. 其结构图大致如下所示:
MMI Task
Audio Player
MID audio api
Media audio api
Message request
Events setting/waiting
Media Task
Audio Request handlers
Function call
L1Audio Module
L1Audio task
Drivers HISR LISR
Hardware
由上图可以看出,整个调用层次较深. 我们分别来学习个层.
1: MMI Task 层
在该层 audio player 模块实现了播放器程序, 其中主要包括对界面视图的实现, 界
面逻辑的处理以及调用 MID 模块的接口,实现音频操作. 在学习其具体的实现细节上,
可以按 view 和 model+control 的简化 MVC 模式来看, 包含与显示有关的 screen 操作显
示部分, 处理消息的 msghandler 部分以及主的程序逻辑及按键处理部分. MTK 平台对事
件的处理是通过 callback function 方式, 所以程序的流程不是顺序的, 事件的发生将导
致相应的 callback 被调用, 从而触发整个audio player 的一次响应. 需要注意的是,在每个
不同的界面对相同事件的处理 callback 函数可能有所不同, 这是在创建,进入该界面时
设定的. 该模块的接口比较复杂,为了提供对 BT 的统一接口, 有两层的播放接口,如
mmi_audply_play 和 mmi_audply_do_play_action(). 整个模块的接口不够清晰, 有些
庞杂和混乱. 模块的显示部分使用控件实现,较为简单, 可进一步参考控件的实现细节
以了解平台的显示子系统, 对播放文件列表的管理是通过文件操作实现的,具体可参见
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 发送播放请求消息.
其中 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 会根据消息类型再进行一次
分发 ,audio 消息会被分发给 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);
//发送播放反馈消息到请求模块
}
}
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 接口来获得与播放操作相关的所有函
数接口. 为此后的其他操作提供处理函数.