ALSA lib open分析


alsa-lib如何解析asound.conf

一.打開代碼流程分析
無論是在錄音還是在放音,都要打開一個PCM流,具體對應的函數原型為:
 int snd_pcm_open(snd_pcm_t **pcmp, const char *name,  snd_pcm_stream_t stream, int mode);
先解一下各個參數的函義:
  • pcmp: 是帶回的pcm流
  • name是要找開的流即放音還是錄音,放音對應AndroidPlayback_Speaker_normal,錄音對應AndroidCapture。放音的字符串會因為當前使用設備和設備狀況不一樣而有所不同,不同之處在下划線后面那部分。錄音則因為大多數板子成型后,都只有一個錄音設備或者接口,因此錄音串對應的就是AndroidCapture。對於linux就是放音的設備,比如hw:0,2
  • stream對應流的類型,是放音(0)還是錄音(1).
  • mode是指設備打開模式,阻塞或非阻塞。
  •  
 
snd_pcm_open
    //this function increases a reference counter so that the obtained tree won't be deleted until unreferenced by #snd_config_unref.
    //這個函數增加了一個引用計數器,這樣得到的樹在未被引用之前不會被刪除# snd_config_unref。
    snd_config_update_ref(&top);
    snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0);
    if (snd_config_get_string(pcm_conf, &str) >= 0) //獲取配置節點的字符串
        snd_pcm_open_noupdate(pcmp, root, str, stream, mode, hop + 1);
    else
        snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode); //單獨分析1
        // 此函數將在配置樹中查找對應的結點,然后將查找到的結點復制一份到pcm_conf中
        snd_config_search_definition(root, "pcm", name, &pcm_conf);
    //Decreases a reference counter of the given config tree, and eventually deletes the tree if all references are gone. This is the counterpart of #snd_config_unref.
    //減少給定配置樹的引用計數器,最終如果所有引用都已消失,則刪除樹。這是#snd_config_unref的對等項。
    snd_config_unref(top);
 
 
單獨分析1:
static const char *const build_in_pcms[] = {
 "adpcm", "alaw", "copy", "dmix", "file", "hooks", "hw", "ladspa", "lfloat",
 "linear", "meter", "mulaw", "multi", "null", "empty", "plug", "rate", "route", "share",
 "shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul",
 NULL
};
 
static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,  snd_config_t *pcm_root, snd_config_t *pcm_conf,
        snd_pcm_stream_t stream, int mode)
    //Searches for a node in a configuration tree.
     * \code
 * config {
 *      a   42                                 # "a"
 *      b {                                     # "b"
 *             c   "cee"                     # "b.c"
 *              d {                             # "b.d"
 *                     e   2.71828        # "b.d.e"
 *                 }
 *         }
 * }
 * \endcode
    snd_config_search(pcm_conf, "type", &conf); //搜索config里面type的節點
    snd_config_get_id(conf, &id);  //獲取ID
    snd_config_get_string(conf, &str); //獲取字符串
    snd_config_search_definition(pcm_root, "pcm_type", str, &type_conf); //搜索pcm_type
        snd_config_for_each(i, next, type_conf)
            snd_config_t *n = snd_config_iterator_entry(i);
            if (snd_config_get_id(n, &id) < 0) //看看是否有comment和open的字符
            if (strcmp(id, "comment") == 0)
            if (strcmp(id, "open") == 0)
    if (!open_name) //如果沒有指定打開的設備
        buf = malloc(strlen(str) + 32); //分配空間
        open_name = buf;
        sprintf(buf, "_snd_pcm_%s_open", str); //這里是這個是str是前面type獲得的
    if (!lib) ////如果前面沒有指定lib
        const char *const *build_in = build_in_pcms; //賦值字符串數組build_in_pcms
        while (*build_in) //如果存在
            if (!strcmp(*build_in, str))  //如果與字符串數組中的字符相等就跳出
                break;
             build_in++;
        if (*build_in == NULL)
            buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32); //分配空間
            lib = buf1;
            sprintf(buf1, "%s/libasound_module_pcm_%s.so", ALSA_PLUGIN_DIR, str); //賦值plugin的so的路徑
            //加載相關的so
            open_func = snd_dlobj_cache_get(lib, open_name, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION), 1);
                //打開動態庫,如果是默認的plugin就打開這個/usr/lib64/libasound.so.2, 否則就打開額外添加的/usr/lib/alsa-lib/libasound_module_pcm_pmaplug.so的plugin庫
                dlobj = snd_dlopen(lib, RTLD_NOW);
                func = snd_dlsym(dlobj, name, version);  //解析來自動態庫的符號,找到函數的地址,如果有的符號沒有就會報錯
                    return dlsym(handle, name);
                c->lib = lib ? strdup(lib) : NULL;
                c->name = strdup(name);
                list_add_tail(&c->list, &pcm_dlobj_list); //把找到的函數加入到pcm_dlobj_list這個鏈表
            if (open_func) //如果加載成功
                 //打開這個plugin,可能調用的函數:_snd_pcm_asym_open, _snd_pcm_plug_open,等,還有執行SND_PCM_PLUGIN_DEFINE_FUNC,這些都是從so庫里面得到的,獲取到函數的地址
                open_func(pcmp, name, pcm_root, pcm_conf, stream, mode);
                if ((*pcmp)->open_func)
                    snd_dlobj_cache_put(open_func); //釋放解析動態庫的緩存
                else 
                    (*pcmp)->open_func = open_func; //賦值
    if (err >= 0)
        snd_config_search(pcm_root, "defaults.pcm.compat", &tmp); //搜索defaults.pcm.compat這個節點
        if (err >= 0)
            if (snd_config_get_integer(tmp, &i) >= 0)
                (*pcmp)->compat = 1;
        char *str = getenv("LIBASOUND_COMPAT");
        if (str && *str) //如果環境變量有配置LIBASOUND_COMPAT,置1
            (*pcmp)->compat = 1;
        snd_config_search(pcm_root, "defaults.pcm.minperiodtime", &tmp); //獲取defaults.pcm.minperiodtime
            snd_config_get_integer(tmp, &(*pcmp)->minperiodtime); //最小周期時間
 
 
 
二.實例分析
1.asound.conf內容
pcm.7input {
    type plug
    slave {
 pcm "hw:0,2"
 format S16_LE
 rate 16000
    }
}
pcm.pma {
   type pmaplug
   slave {
      pcm 7input
   }
   input_channels 8
   loopback 1
   local 1
}
pcm.speech_route {
    type route
    slave.pcm pma
    slave.channels 8
    ttable{
        0.0 1
        0.1 1
        0.2 1
        0.3 1
 0.4 1
 0.5 1
 0.6 1
 0.7 1
    }
}
pcm.speech {
    type asym
    capture.pcm speech_route
    playback.pcm default
}
 
2.添加打印后的log
第一步
ALSA lib pcm.c:2567:(snd_pcm_open_conf) cxw conf id =type, str = asym
ALSA lib pcm.c:2613:(snd_pcm_open_conf) open_name = _snd_pcm_asym_open  //獲取到type asym
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = asym
............................................
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = asym
ALSA lib pcm.c:2637:(snd_pcm_open_conf) open_name lib = (null), open_name = 428883088
ALSA lib pcm.c:2641:(snd_pcm_open_conf) open_name name = speech
ALSA lib pcm_asym.c:84:(_snd_pcm_asym_open) open_name _snd_pcm_asym_open //調用到_snd_pcm_asym_open 函數
第二步
ALSA lib pcm.c:2567:(snd_pcm_open_conf) cxw conf id =type, str = route
ALSA lib pcm.c:2613:(snd_pcm_open_conf) open_name = _snd_pcm_route_open //獲取到type route
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = route
................................
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = route
ALSA lib pcm.c:2637:(snd_pcm_open_conf) open_name lib = (null), open_name = 428883248
ALSA lib pcm.c:2641:(snd_pcm_open_conf) open_name name = speech_route
ALSA lib pcm_route.c:1293:(_snd_pcm_route_open) open_name _snd_pcm_route_open  //調用到_snd_pcm_route_open  函數
第三步
ALSA lib pcm.c:2567:(snd_pcm_open_conf) cxw conf id =type, str = pmaplug
ALSA lib pcm.c:2613:(snd_pcm_open_conf) open_name = _snd_pcm_pmaplug_open //獲取到type pmaplug
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = pmaplug
.................................
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = pmaplug
ALSA lib pcm.c:2631:(snd_pcm_open_conf) open_name buf1 = /usr/lib/alsa-lib/libasound_module_pcm_pmaplug.so
//加載libasound_module_pcm_pmaplug.so庫,並調用SND_PCM_PLUGIN_DEFINE_FUNC
ALSA lib pcm.c:2637:(snd_pcm_open_conf) open_name lib = /usr/lib/alsa-lib/libasound_module_pcm_pmaplug.so, open_name = 428882960
ALSA lib pcm.c:2641:(snd_pcm_open_conf) open_name name = pma
pmaplug() name: pma stream: 1 mode: 0
snd_pcm_extplug_create
第四步
ALSA lib pcm.c:2567:(snd_pcm_open_conf) cxw conf id =type, str = plug
ALSA lib pcm.c:2613:(snd_pcm_open_conf) open_name = _snd_pcm_plug_open  //找到type plug
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = plug
...................................
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = plug
ALSA lib pcm.c:2637:(snd_pcm_open_conf) open_name lib = (null), open_name = 428956384
ALSA lib pcm.c:2641:(snd_pcm_open_conf) open_name name = 7input
第五步
ALSA lib pcm.c:2567:(snd_pcm_open_conf) cxw conf id =type, str = hw
ALSA lib pcm.c:2613:(snd_pcm_open_conf) open_name = _snd_pcm_hw_open
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = hw
..........................................
ALSA lib pcm.c:2618:(snd_pcm_open_conf) open_name str = hw
ALSA lib pcm.c:2637:(snd_pcm_open_conf) open_name lib = (null), open_name = 429049088
ALSA lib pcm.c:2641:(snd_pcm_open_conf) open_name name = hw:0,2 //調用_snd_pcm_hw_open函數
 
分析結果:
    代碼介紹alsa.conf是一個遞歸的過程,根據type不同,調用不同的函數,逐步遞歸下去。
    這是我們系統中snd_pcm_open的整個流程,雖然這里創建失敗但是可以讓我們清晰地認識流創建過程:它是一個分層的流建立過程。asym->route->pmaplug->plug->hw(pcm) 及asym->pmaplug->plug->hw函數層次調用過程。
 
 
 
三._snd_pcm_hw_open分析
Pcm_hw.c (z:\px30_linux\external\alsa-lib-1.1.5\src\pcm)
//Creates a new hw PCM
int _snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,   snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf,
       snd_pcm_stream_t stream, int mode)
    snd_config_for_each(i, next, conf) //遍歷
        n = snd_config_iterator_entry(i);
        if (snd_config_get_id(n, &id) < 0)
        if (snd_pcm_conf_generic_id(id))
        if (strcmp(id, "card") == 0) //獲取card
        if (strcmp(id, "device") == 0)  //獲取device
        if (strcmp(id, "subdevice") == 0)  //獲取subdevice
        。。。。。。。。。。
        if (strcmp(id, "rate") == 0) //獲取rate
        if (strcmp(id, "format") == 0) //獲取format
        if (strcmp(id, "channels") == 0) //獲取channels
        //打開相應的hw stream
        snd_pcm_hw_open(pcmp, name, card, device, subdevice, stream,  mode | (nonblock ? SND_PCM_NONBLOCK : 0),
          0, sync_ptr_ioctl);
            snd_ctl_hw_open(&ctl, NULL, card, 0)) //單獨分析1,打開控制節點
            sprintf(filename, filefmt, card, device); //pcmC%iD%ic,配置pcm節點
            fd = snd_open_device(filename, fmode); //打開stream
                fd = open(filename, fmode);
            ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info) //獲取信息
            return snd_pcm_hw_open_fd(pcmp, name, fd, sync_ptr_ioctl);
                hw = calloc(1, sizeof(snd_pcm_hw_t));
                hw->version = ver;
                hw->card = info.card;
                hw->device = info.device;
                hw->subdevice = info.subdevice;
                hw->fd = fd;
                /* no restriction */
                hw->format = SND_PCM_FORMAT_UNKNOWN;
                hw->rate = 0;
                hw->channels = 0;
                ret = snd_pcm_new(&pcm, SND_PCM_TYPE_HW, name, info.stream, mode); //創建一個snd_pcm_t結構體
                    pcm->ops = &snd_pcm_hw_ops;
                    pcm->fast_ops = &snd_pcm_hw_fast_ops;
                    pcm->private_data = hw;
                    pcm->poll_fd = fd;
                    pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
                    pcm->tstamp_type = tstamp_type;
                map_status_and_control_data(pcm, !!sync_ptr_ioctl); //映射狀態和控制數據
 
 
單獨分析1
int snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode)
    sprintf(filename, SNDRV_FILE_CONTROL, card); //賦值控制"controlC%i"
    fd = snd_open_device(filename, fmode); //打開
        fd = open(filename, fmode); //打開驅動節點
        ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) //控制的版本
        hw->card = card;
        hw->fd = fd;
        hw->protocol = ver;
        err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name); //生成控制相關數據結構
        ctl->ops = &snd_ctl_hw_ops;
        ctl->private_data = hw;
        ctl->poll_fd = fd;
 
 
 
四._snd_pcm_plug_open分析
int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, 
         snd_pcm_stream_t stream, int mode)
    snd_config_for_each(i, next, conf)
        if (strcmp(id, "slave") == 0) 
            slave = n;
#ifdef BUILD_PCM_PLUGIN_ROUTE //可以設置路徑相關的
        if (strcmp(id, "ttable") == 0)
         if (strcmp(id, "route_policy") == 0)
#ifdef BUILD_PCM_PLUGIN_RATE // //可以設置速率相關的
        if (strcmp(id, "rate_converter") == 0)
    //設置從設備的一些配置參數,這里會從alsa.conf里面獲取
    snd_pcm_slave_conf(root, slave, &sconf, 3, SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, &sformat,
     SND_PCM_HW_PARAM_CHANNELS, SCONF_UNCHANGED, &schannels,  SND_PCM_HW_PARAM_RATE, SCONF_UNCHANGED, &srate);
    err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
        return snd_pcm_open_named_slave(pcmp, NULL, root, conf, stream, mode, parent_conf);
            snd_pcm_open_conf(pcmp, name, root, conf, stream, mode); //前面有分析,獲取相關的alsa.conf參數
    //配置返回之后,就會到這里. 單獨分析1
    snd_pcm_plug_open(pcmp, name, sformat, schannels, srate, rate_converter, route_policy, ttable, ssize, cused, sused, spcm, 1);  
 
單獨分析1
int snd_pcm_plug_open(snd_pcm_t **pcmp,  const char *name, snd_pcm_format_t sformat, int schannels, int srate,
        const snd_config_t *rate_converter,  enum snd_pcm_plug_route_policy route_policy,   snd_pcm_route_ttable_entry_t *ttable,
        unsigned int tt_ssize, unsigned int tt_cused, unsigned int tt_sused, snd_pcm_t *slave, int close_slave)
    plug->sformat = sformat;
    plug->schannels = schannels;
    plug->srate = srate;
    //將HW層的pcm流對象存放在PLUG層pcm流的私有數據成員中 ,slave就是那個指針
    plug->gen.slave = plug->req_slave = slave;
    plug->gen.close_slave = close_slave;
    plug->route_policy = route_policy;
    plug->ttable = ttable;
    plug->tt_ssize = tt_ssize;
    plug->tt_cused = tt_cused;
    plug->tt_sused = tt_sused;
    err = snd_pcm_new(&pcm, SND_PCM_TYPE_PLUG, name, slave->stream, slave->mode); //創建SND_PCM_TYPE_PLUG數據流
    pcm->ops = &snd_pcm_plug_ops;
    pcm->fast_ops = slave->fast_ops;
    pcm->fast_op_arg = slave->fast_op_arg;
    pcm->private_data = plug;
    pcm->poll_fd = slave->poll_fd;
    pcm->poll_events = slave->poll_events;
    pcm->mmap_shadow = 1;
    pcm->tstamp_type = slave->tstamp_type;
    snd_pcm_link_hw_ptr(pcm, slave);
    snd_pcm_link_appl_ptr(pcm, slave);
    *pcmp = pcm;
 
 
五._snd_pcm_pmaplug_open 分析
因為有這個兩個宏
#define SND_PCM_PLUGIN_ENTRY(name)   _snd_pcm_##name##_open
SND_PCM_PLUGIN_DEFINE_FUNC(pmaplug) ->_snd_pcm_pmaplug_open
 
#define SND_PCM_PLUGIN_DEFINE_FUNC(plugin) \
int SND_PCM_PLUGIN_ENTRY(plugin) (snd_pcm_t **pcmp, const char *name,\
      snd_config_t *root, snd_config_t *conf, \
      snd_pcm_stream_t stream, int mode)
所有,下面這個就是
_snd_pcm_pmaplug_open (snd_pcm_t **pcmp, const char *name,   snd_config_t *root, snd_config_t *conf, \
      snd_pcm_stream_t stream, int mode)
    snd_config_for_each(i, next, conf) //獲取配置相關
        if (strcmp(id, "slave") == 0)
            slave = n;
        (strcmp(id, "input_channels") == 0)
        。。。。。。。
    pmaplug->ext.version = SND_PCM_EXTPLUG_VERSION;
    pmaplug->ext.name = "pmaplug"; / /名字
    pmaplug->ext.callback = &callbacks; //回調函數
    pmaplug->ext.private_data = pmaplug; //私有
    pmaplug->local = local; //私有的
    pmaplug->loopback = loopback;  
//私有的
    //實例化,Create an extplug instance
    snd_pcm_extplug_create(&pmaplug->ext, name, root, slave, stream, mode);  //單獨分析1
    // mono out, user defined number in,設置
    snd_pcm_extplug_set_param(&pmaplug->ext, SND_PCM_EXTPLUG_HW_CHANNELS, channels);
    snd_pcm_extplug_set_slave_param(&pmaplug->ext, SND_PCM_EXTPLUG_HW_CHANNELS, channels);
    // take double in and write signed 16 bit ints out, doubles are for PMA,設置
    snd_pcm_extplug_set_param(&pmaplug->ext, SND_PCM_EXTPLUG_HW_FORMAT, SND_PCM_FORMAT_S16_LE);
    snd_pcm_extplug_set_slave_param(&pmaplug->ext, SND_PCM_EXTPLUG_HW_FORMAT, SND_PCM_FORMAT_FLOAT64_LE);
    *pcmp = pmaplug->ext.pcm;
 
 
 
 //單獨分析1
int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, 
 snd_config_t *root, snd_config_t *slave_conf,
      snd_pcm_stream_t stream, int mode)
    snd_pcm_slave_conf(root, slave_conf, &sconf, 0); 
    snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL); //之前有分析
    ext = calloc(1, sizeof(*ext));
    ext->data = extplug;
    extplug->stream = stream;
    ext->plug.read = snd_pcm_extplug_read_areas;
    ext->plug.write = snd_pcm_extplug_write_areas;
    ext->plug.undo_read = snd_pcm_plugin_undo_read_generic;
    ext->plug.undo_write = snd_pcm_plugin_undo_write_generic;
    // 將plug層的pcm流對象存放在ext->plug層pcm流的私有數據成員中 ,spcm就是那個指針
    ext->plug.gen.slave = spcm;
    ext->plug.gen.close_slave = 1;
    snd_pcm_new(&pcm, SND_PCM_TYPE_EXTPLUG, name, stream, mode); //創建一個SND_PCM_TYPE_EXTPLUG流
    extplug->pcm = pcm;
    pcm->ops = &snd_pcm_extplug_ops;
    pcm->fast_ops = &snd_pcm_plugin_fast_ops;
    pcm->private_data = ext;
    pcm->poll_fd = spcm->poll_fd;
    pcm->poll_events = spcm->poll_events;
    snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0);
    snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0);
 
 
六._snd_pcm_route_open分析
int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,  snd_config_t *root, snd_config_t *conf, 
   snd_pcm_stream_t stream, int mode)
    snd_config_for_each(i, next, conf)
        snd_config_t *n = snd_config_iterator_entry(i);
        if (strcmp(id, "slave") == 0)
            slave = n;
        if (strcmp(id, "ttable") == 0)
            tt = n;
        err = snd_pcm_slave_conf(root, slave, &sconf, 2,  SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
         SND_PCM_HW_PARAM_CHANNELS, 0, &schannels);
        determine_chmap(tt, &tt_chmap); //決定通道的map
        snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
        if (tt_chmap)
            find_matching_chmap(spcm, tt_chmap, &chmap, &schannels);
        _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap);
        _snd_pcm_route_load_ttable(tt, ttable, csize, ssize,  &cused, &sused, schannels, chmap);
        snd_pcm_route_open(pcmp, name, sformat, schannels,  ttable, ssize,  cused, sused,  spcm, 1); //單獨分析1
 
單獨分析1
int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,  snd_pcm_format_t sformat, int schannels,
         snd_pcm_route_ttable_entry_t *ttable,  unsigned int tt_ssize,  unsigned int tt_cused, unsigned int tt_sused,
         snd_pcm_t *slave, int close_slave)
    route = calloc(1, sizeof(snd_pcm_route_t));
    snd_pcm_plugin_init(&route->plug);
    route->sformat = sformat;
    route->schannels = schannels;
    route->plug.read = snd_pcm_route_read_areas;
    route->plug.write = snd_pcm_route_write_areas;
    route->plug.undo_read = snd_pcm_plugin_undo_read_generic;
    route->plug.undo_write = snd_pcm_plugin_undo_write_generic;
    route->plug.gen.slave = slave; //賦值slave指針
    route->plug.gen.close_slave = close_slave;
    route->plug.init = route_chmap_init;
    snd_pcm_new(&pcm, SND_PCM_TYPE_ROUTE, name, slave->stream, slave->mode); //創建SND_PCM_TYPE_ROUTE的pcm
    pcm->ops = &snd_pcm_route_ops;
    pcm->fast_ops = &snd_pcm_plugin_fast_ops; //賦值操作函數
    pcm->private_data = route;
    pcm->poll_fd = slave->poll_fd;
    pcm->poll_events = slave->poll_events;
    pcm->tstamp_type = slave->tstamp_type;
    snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0);
    snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0);
    err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
 
 
七.總結
snd_pcm_open函數主要完成如下兩步:
第一步:構建配置樹
 第二步:創建PCM流
 
由此可見,在整個過程中創建了三種類型的pcm流對象,EXTPLUG,PLUG,HW
_snd_pcm_asym_open  -->_snd_pcm_route_open--->_snd_pcm_pmaplug_open--->_snd_pcm_plug_open--->_snd_pcm_hw_open層層遞進分析配置樹
_snd_pcm_asym_open  <--....................................<---_snd_pcm_plug_open<--_snd_pcm_hw_open層層回溯。
 回溯過程依次創建了HW pcm-->PLUG pcm-->EXTPLUG pcm-->ROUTE pcm及和它們區配的私有數據及相關操作函數集,而且可以通過ROUTE層的pcm流,查找到EXTPLUG ,plug,hw的pcm.它們都被寄存在上層的private_data成員中。
 
 

深入了解ALSA

alsa-lib如何解析asound.conf

Why asoundrc?

alsa lib中ttable相關學習

ALSA分析

Audio模擬多聲道

 
 
 
 
 
 
 
        
       
 
            
        
                    
                
 
 
 
 
 



 

Attachment List

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM