目录
一 基本框架
二 源码分析
三 FAQ
摘要
本文主要描述MT6236平台之录音流程,且着重针对驱动源代码做分析,包括时序图,源码层次,以及做了问题的总结。
一基本框架
1.1框架
二源码分析
2.1时序图 与状态机
以36为例:
时序图:不单单以任务为节点,
2.2主要文件,函数以及数据结构
这里只要讨论驱动相关:
相关宏:__MED_AUD_REC_MOD__
AUD_REC_ENABLE
DSP_SOLUTION
SMART_PHONE_CORE
根据audio.mak: 36的 med and audio的代码都是使用V1
文件(自上往下) |
描述 |
UI层 |
|
vapp_soundrec_util.cpp vapp_soundrec.cpp |
录音应用UI相关 |
mdi_audio.c |
mdi层封装record接口函数,当然还包括其他函数 |
aud_api.c |
API包括了主要的音频模块接口函数,播放器,录音等等,到这里未知,这些文件都是为UI层服务的接口文件。 |
aud_ilm.c |
audio消息封装层,转发消息到: MED_TASK |
Med_Task层 |
|
aud_media.c |
Med_task的对UI层的消息的执行函数 |
aud_record.c |
独立的录音的功能函数--这里是med_task来调用的。 |
aud_recorder_media.c |
media层函数定义,功能:操作内存,与L1audio Task 交互。操作硬件层,调用PCM WAV等算法。 |
|
|
函数(自上而下) |
描述 |
UI层 |
|
vadp_soundrec_rec_start() |
录音应用的UI接口 |
mdi_audio_start_record() |
mdi层封装接口 |
media_aud_start_record() |
API层音频模块接口,到这里未知,这些文件都是为UI层服务的接口函数。 |
aud_send_record_req() |
Audio ILM层负责封装消息给Med Task |
Med TASK层 |
|
aud_media_record_req_hdlr() |
MedTask层对UI层的消息处理函数 |
aud_rec_start_record() |
独立的录音的功能函数--这里是med_task来调用的。 |
_aud_recorder_media_record() |
media层函数定义,功能…..录音的硬件驱动都在这里操作。 |
Media_Record() |
最终操作DSP HW的函数,注册回调函数给L1audio_Task |
根据每一层的contex数据结构来理解:
数据结构(自上而下) |
组成 |
描述 |
g_sndrec_cntx |
|
UI层的audio record上下文 |
aud_context_p |
|
Med task层的audio record 上下文 |
med_aud_recorder_t |
kal_int32 (*open) kal_int32 (*close) kal_int32 (*start) kal_int32 (*stop) …... |
Audio Recorder interfaces这些都是media层的接口, 直接打开底层硬件驱动,包括文件操作,设置格式,申请释放buffer, 调用wav PCM等算法 |
|
|
|
请注意关键点:
1. #defineAUD_RECORDER_MEM_MARGIN (512)//对齐
#defineAUD_RECORDER_BUFFER_THRESHOLD (200) /* 200 words (400 bytes) bydefault */
2. 刚开始录的时候要跳过2fame
Media_Record函数里面: media.recorded_time = -40; // skip two speechframes
3.开关MIC:L1SP_SetInputSource(custom_cfg_hw_aud_input_path(msg_p->input_source));
4.文件创建:_aud_recorder_media_open()
5.Allocate buffers:_aud_recorder_media_record()
5.1Buffer for amr:
5.2buffer for ring:---采用环形缓冲机制,-----详细内容请是参考环形buffer设计原理
aud_util_alloc_ring_buffer_ext(AUD_RING_BUFFER_SIZE,&self_p->ring_buffer_p);
Media_SetBuffer(self_p->ring_buffer_p,AUD_RING_BUFFER_LEN);
--->size:AUD_RING_BUFFER_SIZE----是BUFFER_THRESHOLD的10倍
--->len:AUD_RING_BUFFER_LEN
和Media层的media.ctrl.rb_size ;media.ctrl.rb_base一致,
Med_v Task 读取L1audio_Buffer的新data:Media_GetReadBuffer();
6.L1audio与Med Task之间的回调函数
首先注册回电函数: _aud_recorder_media_event_callback_fct
Med Task:
Media_Record(media_format, _aud_recorder_media_event_callback_fct,param_p);
------>media.media_handler = media_handler;
L1audio_Task:
mediaInit(L1Audio_GetAudioID() );
----->L1Audio_SetEventHandler( uint16 audio_id,L1Audio_EventHandler handler )
----->l1audio.evHandler[audio_id] = handler;//handle放到L1audio的handle里面
回调函数_aud_recorder_media_read_data_fct()---->write data to FS
更新文件大小偏移,这样文件就可以逐步加大
/* Update file offset */
self_p->file_offset += len;
*written_len = len;
Callback 门限是:AUD_RECORDER_BUFFER_THRESHOLD;
7.通过L1audio_Task来读取DSP的数据
函数:amrDediEncReadFromDSP-------AMR
pcmReadFromDSP();-------PCM
wavReadFromDSP((int16*)wav.tmp_buf[wav.tmp_w&FRAME_BUF_MASK] );----WAV
…...等等
8.驱动硬件开始录音的函数:
amrRecord()
/*
* Stuff no-dataframe first to handle the situation when DSP issues
* interrupt toMCU for recording, but at that timethe AMR codec in DSP
* has notfinished its job.
*/
三FAQ总结
1.DSP层上面时候发出中断呢?
首先:DSP的时钟与NCU同步,估计是通过系统网络同步时钟:TDMA定时器,定时地产生中断。
其次 :当buffer到达AUD_RECORDER_BUFFER_THRESHOLD时候,触发中断通知MCU。
处理流程是这样
isrC_Main---->定时地发送中断信号过来,---->激活高级中断处理例程kal_activate_hisr(l1audio.hisr);--->HISR判断是否满足AUD_RECORDER_BUFFER_THRESHOLD----->满足则通知L1audio_Task 和Med_Task--->写数据到FS.
2.文件时如何逐步加大的呢?也就是说offset写的过程。
一开始就会创建一个临时文件,每次buffer读回来写到文件之后,offset就计算一下偏移大小,
/* Update file offset */
self_p->file_offset += len;
*written_len =len;
原先的文件句柄不变,根据这个offset,不停地带该文件句柄的最后一簇,查找长度为len的簇,累计到该句柄后面。
更详细请参考文件系统读写流程。
3.能否同时录音上行和下行呢?
No;
函数amrRecord(){ *DP_SC_MUTE = 0x0002; /* uplink path only */}
4.录音格式是那一种?
Arm---:MEDIA_AMR_WB
Wav:---: