audio_route.c 是 android 提供的一个 audio route的so 库, 其位于 /system/media/audio_route 目录下。

libaudioroute.so 这个动态库的主要功能有一下几点: 

1.解析 /system/etc/mixer_paths.xml 配置文件

2. 对audio 的ctl 访问方式进行封装,方便提供给hardware层的audio_hw 进行调用。 

 

driver 层的codec 会通过 alsa-driver 接口提供多个ctl 节点,用于配置codec的ctl节点 。

在android 系统中,可以将这些ctl 节点,设置在 mixer_paths.xml 。 可以组合成一个path,

在调用对用 path 的name的时候,所有的ctl 都会进行调用。 

 

audio_route.c 的源码:http://androidxref.com/5.1.1_r6/xref/system/media/audio_route/

mixer_paths.xml 距离:http://androidxref.com/5.1.1_r6/xref/device/htc/flounder/ 下 mixer_paths_0.xml 

调用 libaudioroute.so的hardware层代码。 位于 device/htc 目录下。

http://androidxref.com/5.1.1_r6/xref/device/htc/flounder/audio/hal/audio_hw.c

 

代码分析

//xml的回调函数static void start_tag(void *data, const XML_Char *tag_name,                      const XML_Char **attr){    const XML_Char *attr_name = NULL;    const XML_Char *attr_id = NULL;    const XML_Char *attr_value = NULL;    struct config_parse_state *state = data;    struct audio_route *ar = state->ar;    unsigned int i;    unsigned int ctl_index;    struct mixer_ctl *ctl;    int value;    unsigned int id;    struct mixer_value mixer_value;    enum mixer_ctl_type type;    /* Get name, id and value attributes (these may be empty) */    for (i = 0; attr[i]; i += 2) {        if (strcmp(attr[i], "name") == 0)            attr_name = attr[i + 1];        if (strcmp(attr[i], "id") == 0)            attr_id = attr[i + 1];        else if (strcmp(attr[i], "value") == 0)            attr_value = attr[i + 1];    } //这里查找的是名字为path的tag    /* Look at tags */    if (strcmp(tag_name, "path") == 0) {        if (attr_name == NULL) {            ALOGE("Unnamed path!");        } else {            if (state->level == 1) {                /* top level path: create and stash the path */                //创建一个path                state->path = path_create(ar, (char *)attr_name);            } else {                //如果是嵌套的path,则使用调用path_add_path                /* nested path */                struct mixer_path *sub_path = path_get_by_name(ar, attr_name);                path_add_path(ar, state->path, sub_path);            }        }    }//这里解析ctl tag ,ctl tag 是带有name  和value的    else if (strcmp(tag_name, "ctl") == 0) {        /* Obtain the mixer ctl and value */        ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);        if (ctl == NULL) {            ALOGE("Control '%s' doesn't exist - skipping", attr_name);            goto done;        }        switch (mixer_ctl_get_type(ctl)) {        case MIXER_CTL_TYPE_BOOL:        case MIXER_CTL_TYPE_INT:            value = (int) strtol((char *)attr_value, NULL, 0);            break;        case MIXER_CTL_TYPE_ENUM:            value = mixer_enum_string_to_value(ctl, (char *)attr_value);            break;        default:            value = 0;            break;        }        /* locate the mixer ctl in the list */        for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {            if (ar->mixer_state[ctl_index].ctl == ctl)                break;        }        if (state->level == 1) {            /* top level ctl (initial setting) */            type = mixer_ctl_get_type(ctl);            if (is_supported_ctl_type(type)) {                /* apply the new value */                if (attr_id) {                    /* set only one value */                    id = atoi((char *)attr_id);                    if (id < ar->mixer_state[ctl_index].num_values)                        ar->mixer_state[ctl_index].new_value[id] = value;                    else                        ALOGE("value id out of range for mixer ctl '%s'",                              mixer_ctl_get_name(ctl));                } else {                    /* set all values the same */                    for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)                        ar->mixer_state[ctl_index].new_value[i] = value;                }            }        } else {            /* nested ctl (within a path) */            mixer_value.ctl_index = ctl_index;            mixer_value.value = value;            if (attr_id)                mixer_value.index = atoi((char *)attr_id);            else                mixer_value.index = -1;            path_add_value(ar, state->path, &mixer_value);        }    }done:    state->level++;}//audio_route的初始化函数,传递参数为card 和 xml_paths  struct audio_route *audio_route_init(unsigned int card, const char *xml_path){    struct config_parse_state state;    XML_Parser parser;    FILE *file;    int bytes_read;    void *buf;    int i;  //解析的结果保存在ar中    struct audio_route *ar;    ar = calloc(1, sizeof(struct audio_route));    if (!ar)        goto err_calloc; // 调用tinyalsa 提供的mixer_open 函数    ar->mixer = mixer_open(card);    if (!ar->mixer) {        ALOGE("Unable to open the mixer, aborting.");        goto err_mixer_open;    }    ar->mixer_path = NULL;    ar->mixer_path_size = 0;    ar->num_mixer_paths = 0;    /* allocate space for and read current mixer settings */    if (alloc_mixer_state(ar) < 0)        goto err_mixer_state;//根据传递进来的参数 mixer_paths 决定是否使用默认的 /system/etc/mixer_paths.xml 文件    /* use the default XML path if none is provided */    if (xml_path == NULL)        xml_path = MIXER_XML_PATH;    file = fopen(xml_path, "r");    if (!file) {        ALOGE("Failed to open %s", xml_path);        goto err_fopen;    } // 创建一个 xml 的handler,    parser = XML_ParserCreate(NULL);    if (!parser) {        ALOGE("Failed to create XML parser");        goto err_parser_create;    }    memset(&state, 0, sizeof(state));    state.ar = ar;    XML_SetUserData(parser, &state);// 设置解析的callback 函数,分别是 start_tag and end_tag     XML_SetElementHandler(parser, start_tag, end_tag);    for (;;) {        buf = XML_GetBuffer(parser, BUF_SIZE);        if (buf == NULL)            goto err_parse;        bytes_read = fread(buf, 1, BUF_SIZE, file);        if (bytes_read < 0)            goto err_parse; // 进行数据的解析        if (XML_ParseBuffer(parser, bytes_read,                            bytes_read == 0) == XML_STATUS_ERROR) {            ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);            goto err_parse;        }        if (bytes_read == 0)            break;    }    /* apply the initial mixer values, and save them so we can reset the       mixer to the original values */    audio_route_update_mixer(ar);    save_mixer_state(ar);    XML_ParserFree(parser);    fclose(file);    return ar;err_parse:    XML_ParserFree(parser);err_parser_create:    fclose(file);err_fopen:    free_mixer_state(ar);err_mixer_state:    mixer_close(ar->mixer);err_mixer_open:    free(ar);    ar = NULL;err_calloc:    return NULL;}

下边分析一下 mixer_paths.xml 

//初始化设置 ,ctl 包含了 name 和value , 这里的name ,就是对用codec 提供的控件的名字              //定义的path 为headphones                                                                                                                                                                                                             

 

在hardware 层调用

audio_route_apply_and_update_path 或者 audio_route_reset_and_update_path 的时候,会根据提供的名字更新对应path下的ctl控件的值。 

实例代码,可以查看http://androidxref.com/5.1.1_r6/xref/hardware/qcom/audio/hal/msm8974/platform.c  里边对audio_route的使用。

更多相关文章

  1. android initlogo.rle 在32位LCD上显示
  2. android 【点击输入框调出输入法前的】输入框获取焦点和输入法的
  3. Android菜鸟笔记-调用相机拍照后返回照片过小的问题
  4. android类作用整理
  5. android NDK JNI so文件的制作和使用
  6. Android中的Service使用
  7. Android(安卓)Camera 运行流程
  8. 将Gsensor lis301 driver 升级到 lis331 driver 过程总结,以及and
  9. Js Android(安卓)交互

随机推荐

  1. 《Android开发艺术探索》第六章Android的
  2. android对大图片压缩的方法
  3. cocos2dx 玩转震动
  4. android访问静态页面,出现405错误解决方法
  5. android UI效果三: 滚动切换屏幕
  6. Android仿IOS回弹效果 支持任何控件
  7. Android异步处理类AsyncTask
  8. Android(安卓)UI绘制流程之测量篇
  9. Android(安卓)P实现静默安装的方法示例(
  10. Android(安卓)SDK for windows开发环境搭