任何stream试图连接到PA的时候,socket的callback会调用这个函数
pa_native_protocol_connect (pa_native_protocol *p, pa_iochannel *io, pa_native_options *o)
改函数,将建立一个S端stream对应这个io,同时注册这个stream的callback,在命令扩展中,关注的是如下这个cb
static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata)
注册如下
pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
c[ pa_native_connection *c;]是userdata
同时,注意到:
c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
一般的命令将匹配到这个command_table的函数指针来处理。
如何调用到这些函数指针
1. pstream 的io_callback调用到do_read
2. pstream_packet_callback是之前注册的cb,在上述函数被调用
3. 看pstream_packet_callback这个函数,掉用了pa_pdispatch_run
4. 最后看看这个run函数
上面还只是一般命令的执行过程,下面看看,如何扩展命令,如何使用自己扩展的命令
发送扩展命令的时候,命令有两个部分,主命令,子命令。主命令是固定的
PA_COMMAND_EXTENSION
子命令即用户自定义命令,这个首先要定义好的。例如
enum
{
SUBCOMMAND_TEST,
SUBCOMMAND_READ,
SUBCOMMAND_WRITE,
SUBCOMMAND_DELETE,
SUBCOMMAND_SUBSCRIBE,
SUBCOMMAND_EVENT
};
然后建立扩展命令的入口函数,函数名任意,格式固定的
static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t)
然后,通过如下函数,置函数指针。
pa_native_protocol_install_ext(u->protocol, m, extension_cb);
再看通用扩展函数 command_extension
这样,就可以了解扩展命令的工作流程。
至于如何调用,参考如下这段代码
pa_operation *pa_ext_stream_restore_test(
pa_context *c,
pa_ext_stream_restore_test_cb_t cb,
void *userdata) {
uint32_t tag;
pa_operation *o;
pa_tagstruct *t;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 14, PA_ERR_NOTSUPPORTED);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_EXTENSION, &tag);
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, "module-stream-restore"
);
pa_tagstruct_putu32(t, SUBCOMMAND_TEST);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_stream_restore_test_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return
o;
}
对于 pa_pdispatch_register_reply 的双重callback,我的理解是,当前注册的cb为自己所用,pa_operation_new引入的cb为用户应用自定义callback
我的理解源于 Moblin Audio Manager的API
pa_operation* am_set_stream_volume(pa_context * c, am_set_cb_t cb, uint32_t index, pa_volume_t v, void* userdata){
uint32_t tag;
pa_tagstruct *t;
pa_operation* o;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, NULL);
t = am_tag_command(c, &tag, AM_COMMAND_SET_STREAM_VOLUME);
pa_tagstruct_putu32(t,index) ;
pa_tagstruct_putu32(t,v) ;
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, am_set_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return
o;
}