之前一篇裡已經分析過在核心的驅動部分。現在開始具體的流程分析,結合實際應用開始:
撥打到電話10010,call recorder自動開始錄音,進入adb shell
cat /proc/kmsg
通過篩選log得出:
開始:
<6>[06-25 03:30:13.510000] [428: ex.callrecorder]voc_register_client: 2 success
<6>[06-25 03:30:13.510000] [428: ex.callrecorder]voc_register_client: 0 success
<6>[06-25 03:30:13.520000] [1080: voc_rpc_thread]voc_rpc_thread() start
<6>[06-25 03:30:13.520000] [1080: voc_rpc_thread]voc: rpc_reply status 0
<6>[06-25 03:30:13.520000] [1080: voc_rpc_thread]voc: rpc_reply status 0
結束:
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc:
stopping vocpcm_read()
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc_unregister_client: 2 success
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc: stopping vocpcm_read()
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc_unregister_client: 0 success
<6>[06-25 03:30:31.970000] [1080: voc_rpc_thread]voc: rpc_reply status 0
<6>[06-25 03:30:31.970000] [1080: voc_rpc_thread]voc: rpc_reply status 0
1.現在開始從“開始”開始分析 :
a.voc_register_client: 2 success
出現在:static int voc_register_client(struct voc_ctxt *ctxt)
pr_info("%s: %d success\n", __func__, ctxt->intr);
ctxt->intr=2,即:voc_tx_record
向前追溯==》static
long vocpcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static long vocpcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct voc_ctxt *ctxt = file->private_data;
struct buffer *frame;
unsigned long flags;
uint32_t index;
uint32_t data_index;
uint32_t len = 0;
uint8_t *dest;
int rc = 0;
mutex_lock(&ctxt->lock);
switch (cmd) {
case VOCPCM_REGISTER_CLIENT:
rc =
voc_register_client(ctxt);
break;
...
}
由此可見當ioctl的cmd為VOCPCM_REGISTER_CLIENT的時候,會執行這個註冊動作。
b.voc_register_client: 0 success
同a的原理一樣,只不過裝置不一樣,0即:voc_rx_record
**a.b總結錄音的開始起於對voc_tx_record、voc_rx_record兩個裝置的註冊,這個註冊動作應該是通過上層ioctl與核心互動達到的。
c.voc_rpc_thread() start
這條LOG能夠在static int voc_rpc_thread(void *d)這裡找到:
static int voc_rpc_thread(void *d)
{
struct rpc_request_hdr *hdr = NULL;
uint32_t type;
int len;
pr_info("voc_rpc_thread() start\n");
...
}
向前追溯==》static int vocpcm_open(struct inode *inode, struct file *file),這個函數引用了voc_roc_thread函數。
the_voc.task = kthread_run(voc_rpc_thread, NULL, "voc_rpc_thread");這裡執行了。
這個open是檔案操作中的定義。
**abc總結:要開始錄音,先註冊兩個通道的錄音裝置,然後開啟線程。
d.voc: rpc_reply status 0 出現兩次
還是在static int voc_rpc_thread(void
*d)中:
if (status == RPCMSG_REPLYSTAT_ACCEPTED)
{
status = be32_to_cpu(rep->
data.acc_hdr.accept_stat);
pr_info("voc: rpc_reply status %d\n", status);
} else {
pr_info("voc: rpc_reply denied!\n");
說明之前的操作已經被接受,並沒有拒絕。成功。出現兩次,應該是因為註冊了兩個裝置。
//--------------------------開始部分結束-------------------------------------//
總結:開始錄音的操作需要先用ioctl註冊裝置,2個。之後再開啟裝置,如果註冊成功且開啟沒有問題,那麼錄音就已經開始了。
//-------------------------------------------------------------------------------//
2.結束部分的流程分析:
a.voc: stopping vocpcm_read()
static long vocpcm_ioctl(struct
file *file, unsigned int cmd, unsigned long arg)中:
case
VOCPCM_UNREGISTER_CLIENT:
if (ctxt->intr % 2) {
if (ctxt->s_ptr) {
index = ctxt->head;
frame = &ctxt->buf[index];
data_index = FRAME_NUM * FRAME_SIZE - 1;
dest = (uint8_t *)&frame->data[data_index] + 1;
len = dest - ctxt->s_ptr + 1;
memset(ctxt->s_ptr, 0, len);
spin_lock_irqsave(&ctxt->dsp_lock, flags);
frame->index = 0;
ctxt->head = (ctxt->head + 1) &
(BUFFER_NUM - 1);
ctxt->count++;
ctxt->final_input = 1;
spin_unlock_irqrestore(&ctxt->dsp_lock, flags);
rc = wait_event_interruptible_timeout(
ctxt->last_write_wait,
ctxt->count == 0,
5 * HZ);
if (rc < 0)
break;
}
} else {
pr_info("voc: stopping vocpcm_read()\n");
ctxt->final_input = 1;
wake_up_interruptible(&ctxt->wait);
}
...
}
這條log只有在反註冊0.2裝置的時候才會出現。
那麼不難理解,結束的時候這幾條log是什麼意思:
<6>[06-25 03:30:31.960000] [1086:
ex.callrecorder]voc: stopping vocpcm_read()
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc_unregister_client: 2 success //反註冊2成功
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc: stopping vocpcm_read()
<6>[06-25 03:30:31.960000] [1086: ex.callrecorder]voc_unregister_client: 0 success //反註冊0成功
b.voc:
rpc_reply status 0 出現兩次
就是說反註冊的操作被承認。再release就結束了。