void update_mixer_state(struct audio_route *ar) { unsigned int i; unsigned int j; if (!ar) { ALOGE("%s: invalid audio_route", __func__); return; } for (i = 0; i < ar->num_mixer_ctls; i++) { /* if the value has changed, update the mixer */ if (ar->mixer_state[i].old_value != ar->mixer_state[i].new_value) { if (!(ar->mixer_state[i].ignored)) { for (j = 0; j < ar->mixer_state[i].ctl_vals; j++) { #if 0 ALOGV("%s: '%s'[%u] -> %d", __func__, mixer_ctl_get_name(ar->mixer_state[i].ctl), j, ar->mixer_state[i].new_value[j]); #endif #if 0 mixer_ctl_set_value(ar->mixer_state[i].ctl, j, ar->mixer_state[i].new_value[j]); #endif ar->mixer_state[i].old_value[j] = ar->mixer_state[i].new_value[j]; } } } } }
static int path_add_setting(struct mixer_path *path, struct mixer_setting *setting) { unsigned int i; int path_index; if (find_ctl_in_path(path, setting->ctl) != -1) { ALOGE("Control '%s' already exists in path '%s'", mixer_ctl_get_name(setting->ctl), path->name); return -1; } path_index = alloc_path_setting(path); if (path_index < 0) return -1; path->setting[path_index].ctl = setting->ctl; path->setting[path_index].num_values = setting->num_values; path->setting[path_index].value = malloc(setting->num_values * sizeof(int)); path->setting[path_index].linked = setting->linked; if (setting->linked) { path->setting[path_index].value[0] = setting->value[0]; } else { for (i = 0; i < setting->num_values; i++) path->setting[path_index].value[i] = setting->value[i]; } return 0; }
static void tinymix_list_controls(struct mixer *mixer, int print_all) { struct mixer_ctl *ctl; const char *name, *type; unsigned int num_ctls, num_values; unsigned int i; num_ctls = mixer_get_num_ctls(mixer); printf("Number of controls: %u\n", num_ctls); if (print_all) printf("ctl\ttype\tnum\t%-40svalue\n", "name"); else printf("ctl\ttype\tnum\t%-40s\n", "name"); for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(mixer, i); name = mixer_ctl_get_name(ctl); type = mixer_ctl_get_type_string(ctl); num_values = mixer_ctl_get_num_values(ctl); printf("%u\t%s\t%u\t%-40s", i, type, num_values, name); if (print_all) tinymix_detail_control(mixer, name); printf("\n"); } }
int list(int argc, char **argv) { int nMixer = -1; if (argc == 3) nMixer = atoi(argv[2]); if (argc != 3 || nMixer < 0 || nMixer > 7) { printf("Usage: ainfo list <card number>\n" "where <card number> is between 0 and 7\n"); return 0; } mixer *m = mixer_open(nMixer); if (m == NULL) { printf("Unable to open card #%d\n", nMixer); return 0; } int count = mixer_get_num_ctls(m); printf("Found %d controls:\n", count); for (int i = 0; i < count; i++) { char name[64], type[64]; mixer_ctl *ctl = mixer_get_ctl(m, i); mixer_ctl_get_name(ctl, name, sizeof(name)); printf("%d: %s (0x%x)\n", i, name, mixer_ctl_get_type(ctl)); } return 0; }
static int path_add_setting(struct mixer_path *path, struct mixer_setting *setting) { struct mixer_setting *new_path_setting; if (path_setting_exists(path, setting)) { ALOGE("Duplicate path setting '%s'", mixer_ctl_get_name(setting->ctl)); return -1; } /* check if we need to allocate more space for path settings */ if (path->size <= path->length) { if (path->size == 0) path->size = INITIAL_MIXER_PATH_SIZE; else path->size *= 2; new_path_setting = realloc(path->setting, path->size * sizeof(struct mixer_setting)); if (new_path_setting == NULL) { ALOGE("Unable to allocate more path settings"); return -1; } else { path->setting = new_path_setting; } } /* initialise the new path setting */ path->setting[path->length].ctl = setting->ctl; path->setting[path->length].value = setting->value; path->length++; return 0; }
static int path_add_setting(struct audio_route *ar, struct mixer_path *path, struct mixer_setting *setting) { int path_index; if (find_ctl_index_in_path(path, setting->ctl_index) != -1) { struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index); ALOGE("Control '%s' already exists in path '%s'", mixer_ctl_get_name(ctl), path->name); return -1; } path_index = alloc_path_setting(path); if (path_index < 0) return -1; path->setting[path_index].ctl_index = setting->ctl_index; path->setting[path_index].num_values = setting->num_values; path->setting[path_index].value = malloc(setting->num_values * sizeof(int)); /* copy all values */ memcpy(path->setting[path_index].value, setting->value, setting->num_values * sizeof(int)); return 0; }
static void path_print(struct mixer_path *path) { unsigned int i; ALOGV("Path: %s, length: %d", path->name, path->length); for (i = 0; i < path->length; i++) ALOGV(" %d: %s -> %d", i, mixer_ctl_get_name(path->setting[i].ctl), path->setting[i].value); }
static void tinymix_detail_control(struct mixer *mixer, const char *control, int print_all) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; int min, max; if (isdigit(control[0])) ctl = mixer_get_ctl(mixer, atoi(control)); else ctl = mixer_get_ctl_by_name(mixer, control); if (!ctl) { fprintf(stderr, "Invalid mixer control\n"); return; } type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); if (print_all) printf("%s:", mixer_ctl_get_name(ctl)); for (i = 0; i < num_values; i++) { switch (type) { case MIXER_CTL_TYPE_INT: printf(" %d", mixer_ctl_get_value(ctl, i)); break; case MIXER_CTL_TYPE_BOOL: printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: tinymix_print_enum(ctl, print_all); break; case MIXER_CTL_TYPE_BYTE: printf(" 0x%02x", mixer_ctl_get_value(ctl, i)); break; default: printf(" unknown"); break; }; } if (print_all) { if (type == MIXER_CTL_TYPE_INT) { min = mixer_ctl_get_range_min(ctl); max = mixer_ctl_get_range_max(ctl); printf(" (range %d->%d)", min, max); } } printf("\n"); }
static void tinymix_detail_control(struct mixer *mixer, unsigned int id, int print_all) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; char buffer[256]; unsigned int i; int min, max; if (id >= mixer_get_num_ctls(mixer)) { fprintf(stderr, "Invalid mixer control\n"); return; } ctl = mixer_get_ctl(mixer, id); mixer_ctl_get_name(ctl, buffer, sizeof(buffer)); type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); if (print_all) printf("%s:", buffer); for (i = 0; i < num_values; i++) { switch (type) { case MIXER_CTL_TYPE_INT: printf(" %d", mixer_ctl_get_value(ctl, i)); break; case MIXER_CTL_TYPE_BOOL: printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: tinymix_print_enum(ctl, print_all); break; case MIXER_CTL_TYPE_BYTE: printf(" 0x%02x", mixer_ctl_get_value(ctl, i)); break; default: printf(" unknown"); break; }; } if (print_all) { if (type == MIXER_CTL_TYPE_INT) { min = mixer_ctl_get_range_min(ctl); max = mixer_ctl_get_range_max(ctl); printf(" (range %d->%d)", min, max); } } printf("\n"); }
static void path_print(struct mixer_path *path) { unsigned int i; unsigned int j; ALOGV("Path: %s, length: %d", path->name, path->length); for (i = 0; i < path->length; i++) for (j = 0; j < path->setting[i].ctl_vals; j++) ALOGV(" %d: %s [%d]-> %d", i, mixer_ctl_get_name(path->setting[i].ctl), j, path->setting[i].value[j]); }
static void path_print(struct mixer_path *path) { unsigned int i; unsigned int j; ALOGE("Path: %s, length: %d", path->name, path->length); for (i = 0; i < path->length; i++) { ALOGE(" id=%d: ctl=%s linked=%c", i, mixer_ctl_get_name(path->setting[i].ctl), path->setting[i].linked ? 'y' : 'n'); for (j = 0; j < path->setting[i].num_values; j++) ALOGE(" id=%d value=%d", j, path->setting[i].value[j]); } }
static void path_print(struct audio_route *ar, struct mixer_path *path) { unsigned int i; unsigned int j; ALOGE("Path: %s, length: %d", path->name, path->length); for (i = 0; i < path->length; i++) { struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index); ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl)); for (j = 0; j < path->setting[i].num_values; j++) ALOGE(" id=%d value=%d", j, path->setting[i].value[j]); } }
static int path_add_value(struct mixer_path *path, struct mixer_value *mixer_value) { unsigned int i; int path_index; unsigned int num_values; /* Check that mixer value index is within range */ num_values = mixer_ctl_get_num_values(mixer_value->ctl); if (mixer_value->index >= (int)num_values) { ALOGE("mixer index %d is out of range for '%s'", mixer_value->index, mixer_ctl_get_name(mixer_value->ctl)); return -1; } path_index = find_ctl_in_path(path, mixer_value->ctl); if (path_index < 0) { /* New path */ path_index = alloc_path_setting(path); if (path_index < 0) return -1; /* initialise the new path setting */ path->setting[path_index].ctl = mixer_value->ctl; path->setting[path_index].num_values = num_values; path->setting[path_index].value = malloc(num_values * sizeof(int)); path->setting[path_index].linked = true; path->setting[path_index].value[0] = mixer_value->value; } if (mixer_value->index == -1) { /* Linked, so only set the first value */ path->setting[path_index].linked = true; path->setting[path_index].value[0] = mixer_value->value; } else { if (path->setting[path_index].linked && (num_values > 1)) { /* Unlinking the values, so duplicate them across */ for (i = 1; i < num_values; i++) { path->setting[path_index].value[i] = path->setting[path_index].value[0]; } path->setting[path_index].linked = false; } path->setting[path_index].value[mixer_value->index] = mixer_value->value; } return 0; }
int audio_route_control_set_number(unsigned int card_slot, char *control_name, char *string) { struct mixer *control_mixer; struct mixer_ctl *ctl; const char *name; unsigned int num_ctls, num_values; unsigned int i, j; enum mixer_ctl_type type; int value; int ret, mixer_ret; control_mixer = mixer_open(card_slot); if (!control_mixer) { ALOGE("Unable to open the control mixer, aborting."); return -1; } ALOGV("Control mixer open successful."); num_ctls = mixer_get_num_ctls(control_mixer); ret = 0; for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(control_mixer, i); name = mixer_ctl_get_name(ctl); if (name && strcmp(name, control_name) == 0) { /* Found the control, update and exit */ value = atoi(string); num_values = mixer_ctl_get_num_values(ctl); for (j = 0; j < num_values; j++) { mixer_ret = mixer_ctl_set_value(ctl, j, value); if (mixer_ret) { ALOGE("Error: invalid value (%s to %d)", name, value); mixer_close(control_mixer); /* Add up the number of failed controller values */ ret += -1; } } if (ret == 0) ALOGV("Setting %s to int %d", name, value); break; } } return ret; }
int audio_route_control_set_enum(unsigned int card_slot, char *control_name, char *string) { struct mixer *control_mixer; struct mixer_ctl *ctl; const char *name; unsigned int num_ctls, num_values; unsigned int i, j; enum mixer_ctl_type type; int value; int ret, mixer_ret; control_mixer = mixer_open(card_slot); if (!control_mixer) { ALOGE("Unable to open the control mixer, aborting."); return -1; } ALOGV("Control mixer open successful."); num_ctls = mixer_get_num_ctls(control_mixer); ret = 0; for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(control_mixer, i); name = mixer_ctl_get_name(ctl); if (name && strcmp(name, control_name) == 0) { /* Found the control, update and exit */ type = mixer_ctl_get_type(ctl); if (type == MIXER_CTL_TYPE_ENUM) { if (mixer_ctl_set_enum_by_string(ctl, string)) { ALOGE("Error: invalid enum value"); ret = -1; } else { ALOGV("Setting %s to string %s", name, string); } } else { ALOGV("Error: only enum types can be set with strings"); ret = -1; } break; } } mixer_close(control_mixer); return ret; }
static int path_apply(struct audio_route *ar, struct mixer_path *path) { unsigned int i; unsigned int j; unsigned int k; if (!ar) { ALOGE("%s: invalid audio_route", __func__); return -1; } for (i = 0; i < path->length; i++) { struct mixer_ctl *ctl = path->setting[i].ctl; /* locate the mixer ctl in the list */ for (j = 0; j < ar->num_mixer_ctls; j++) { if (ar->mixer_state[j].ctl == ctl) break; } /* apply the new value */ #if 0 for (k = 0; k < path->setting[i].ctl_vals; k++) { ar->mixer_state[j].new_value[k] = path->setting[i].value[k]; mixer_ctl_set_value(ctl, k, ar->mixer_state[j].new_value[k]); } #else for (k = 0; k < path->setting[i].ctl_vals; k++) { ar->mixer_state[j].new_value[k] = path->setting[i].value[k]; } ALOGV("mixer_set: '%s' %d,%d,%d\n", mixer_ctl_get_name(ctl), path->setting[i].value[0], path->setting[i].value[1], path->setting[i].value[2] ); mixer_ctl_set_multivalue(ctl, path->setting[i].ctl_vals, path->setting[i].value); #endif ar->mixer_state[j].ctl_vals = path->setting[i].ctl_vals; } return 0; }
static int path_add_value(struct audio_route *ar, struct mixer_path *path, struct mixer_value *mixer_value) { unsigned int i; int path_index; unsigned int num_values; struct mixer_ctl *ctl; /* Check that mixer value index is within range */ ctl = index_to_ctl(ar, mixer_value->ctl_index); num_values = mixer_ctl_get_num_values(ctl); if (mixer_value->index >= (int)num_values) { ALOGE("mixer index %d is out of range for '%s'", mixer_value->index, mixer_ctl_get_name(ctl)); return -1; } path_index = find_ctl_index_in_path(path, mixer_value->ctl_index); if (path_index < 0) { /* New path */ path_index = alloc_path_setting(path); if (path_index < 0) return -1; /* initialise the new path setting */ path->setting[path_index].ctl_index = mixer_value->ctl_index; path->setting[path_index].num_values = num_values; path->setting[path_index].value = malloc(num_values * sizeof(int)); path->setting[path_index].value[0] = mixer_value->value; } if (mixer_value->index == -1) { /* set all values the same */ for (i = 0; i < num_values; i++) path->setting[path_index].value[i] = mixer_value->value; } else { /* set only one value */ path->setting[path_index].value[mixer_value->index] = mixer_value->value; } return 0; }
TEST_F(MixerTest, tryTinyAlsaTest) { int hwId = AudioHardware::detectAudioHw(); ASSERT_TRUE(hwId >= 0); struct mixer* mixerp = mixer_open(hwId); ASSERT_TRUE(mixerp != NULL); int num_ctls = mixer_get_num_ctls(mixerp); LOGI("Number of mixel control %d", num_ctls); for (int i = 0; i < num_ctls; i++) { struct mixer_ctl* control = mixer_get_ctl(mixerp, i); ASSERT_TRUE(control != NULL); LOGI("Mixer control %s type %s value %d", mixer_ctl_get_name(control), mixer_ctl_get_type_string(control), mixer_ctl_get_num_values(control)); free(control); } // no mixer control for MobilePre. If this assumption fails, // mixer control should be added. ASSERT_TRUE(num_ctls == 0); mixer_close(mixerp); }
int write_percentage(int argc, char **argv) { int nMixer = -1, nControl = -1; int location = -1, value = -1; if (argc == 6) { nMixer = atoi(argv[2]); nControl = atoi(argv[3]); location = atoi(argv[4]); value = atoi(argv[5]); } if (argc != 6 || nMixer < 0 || nMixer > 7 || nControl < 0 || location < 0) { printf("Usage: ainfo write-percentage <card number> <control number> <location> <value>\n" "where <card number> is between 0 and 7\n" "<control number> is the control to be written\n" "<location> is the location to be written\n" "<value> is the value to be written\n"); return 0; } mixer *m = mixer_open(nMixer); if (m == NULL) { printf("Unable to open card #%d\n", nMixer); return 0; } mixer_ctl *c = mixer_get_ctl(m, nControl); if (c == NULL) { printf("Unable to open control #%d\n", nControl); return 0; } char name[64], type[64]; mixer_ctl_get_name(c, name, sizeof(name)); mixer_ctl_set_percent(c, location, value); printf("Control: %s\nPercent: %d\nValue: %d\n", name, mixer_ctl_get_percent(c, location), mixer_ctl_get_value(c, location)); return 0; }
static void tinymix_list_controls(struct mixer *mixer) { struct mixer_ctl *ctl; const char *type; unsigned int num_ctls, num_values; char buffer[256]; unsigned int i; num_ctls = mixer_get_num_ctls(mixer); printf("Number of controls: %d\n", num_ctls); printf("ctl\ttype\tnum\t%-40s value\n", "name"); for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(mixer, i); mixer_ctl_get_name(ctl, buffer, sizeof(buffer)); type = mixer_ctl_get_type_string(ctl); num_values = mixer_ctl_get_num_values(ctl); printf("%d\t%s\t%d\t%-40s", i, type, num_values, buffer); tinymix_detail_control(mixer, i, 0); } }
int read_range(int argc, char **argv) { int nMixer = -1, nControl = -1; int location = -1; if (argc == 4) { nMixer = atoi(argv[2]); nControl = atoi(argv[3]); } if (argc != 4 || nMixer < 0 || nMixer > 7 || nControl < 0) { printf("Usage: ainfo read-range <card number> <control number> <location>\n" "where <card number> is between 0 and 7\n" "<control number> is the control to be read\n"); return 0; } mixer *m = mixer_open(nMixer); if (m == NULL) { printf("Unable to open card #%d\n", nMixer); return 0; } mixer_ctl *c = mixer_get_ctl(m, nControl); if (c == NULL) { printf("Unable to open control #%d\n", nControl); return 0; } char name[64], type[64]; mixer_ctl_get_name(c, name, sizeof(name)); printf("Control: %s\nMin: %d\nMax: %d\n", name, mixer_ctl_get_range_min(c), mixer_ctl_get_range_max(c)); return 0; }
static void tinymix_detail_control(struct mixer *mixer, const char *control, int print_all) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; int min, max; int ret; char *buf = NULL; if (isdigit(control[0])) ctl = mixer_get_ctl(mixer, atoi(control)); else ctl = mixer_get_ctl_by_name(mixer, control); if (!ctl) { fprintf(stderr, "Invalid mixer control\n"); return; } type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); if ((type == MIXER_CTL_TYPE_BYTE) && (num_values > 0)) { buf = calloc(1, num_values); if (buf == NULL) { fprintf(stderr, "Failed to alloc mem for bytes %d\n", num_values); return; } ret = mixer_ctl_get_array(ctl, buf, num_values); if (ret < 0) { fprintf(stderr, "Failed to mixer_ctl_get_array\n"); free(buf); return; } } if (print_all) printf("%s:", mixer_ctl_get_name(ctl)); for (i = 0; i < num_values; i++) { switch (type) { case MIXER_CTL_TYPE_INT: printf(" %d", mixer_ctl_get_value(ctl, i)); break; case MIXER_CTL_TYPE_BOOL: printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: tinymix_print_enum(ctl, print_all); break; case MIXER_CTL_TYPE_BYTE: printf("%02x", buf[i]); break; default: printf(" unknown"); break; }; } if (print_all) { if (type == MIXER_CTL_TYPE_INT) { min = mixer_ctl_get_range_min(ctl); max = mixer_ctl_get_range_max(ctl); printf(" (range %d->%d)", min, max); } } free(buf); printf("\n"); }
int mixer_cache_populate(struct audio_tool_mixer_cache *cache, struct mixer *mixer) { struct mixer_ctl *ctl; struct audio_tool_mixer_control_info *cur; const char* name; size_t count, n, v; int tmp; if (!cache) return EINVAL; if (!mixer) return EINVAL; if (cache->ctrls) free(cache->ctrls); count = mixer_get_num_ctls(mixer); cache->count = count; if (count) { cache->ctrls = calloc(count, sizeof(struct audio_tool_mixer_control_info)); if (! cache->ctrls) return -ENOMEM; } for (n = 0, cur = cache->ctrls ; n < count ; ++n, ++cur) { ctl = mixer_get_ctl(mixer, n); if (!ctl) return ENODEV; name = mixer_ctl_get_name(ctl); if (!name) return ENODEV; cur->id = n; cur->type = mixer_ctl_get_type(ctl); strcpy(cur->name, name); cur->num_values = mixer_ctl_get_num_values(ctl); if (cur->num_values > MAX_NUM_VALUES) cur->num_values = MAX_NUM_VALUES; for (v = 0 ; v < cur->num_values ; ++v) { switch (cur->type) { case MIXER_CTL_TYPE_BOOL: case MIXER_CTL_TYPE_INT: cur->value.integer[v] = mixer_ctl_get_value(ctl, v); break; case MIXER_CTL_TYPE_ENUM: tmp = mixer_ctl_get_value(ctl, v); name = mixer_ctl_get_enum_string(ctl, tmp); // null value names were causing seg fault here if (name) strcpy(cur->value.enumerated[v], name); else printf("Skipping ENUM due to null setting for %s\n", cur->name); break; case MIXER_CTL_TYPE_BYTE: cur->value.byte[v] = mixer_ctl_get_value(ctl, v); break; case MIXER_CTL_TYPE_INT64: cur->value.integer64[v] = mixer_ctl_get_value(ctl, v); break; default: (void)0; } } } return 0; }
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; /* 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]; } /* 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 */ state->path = path_create(ar, (char *)attr_name); } else { /* nested path */ struct mixer_path *sub_path = path_get_by_name(ar, attr_name); path_add_path(ar, state->path, sub_path); } } } 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 = atoi((char *)attr_value); 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) */ /* 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++; }
static void tinymix_detail_control(struct mixer *mixer, const char *control, int print_all) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; int min, max; int ret; char buf[512] = { 0 }; size_t len; if (isdigit(control[0])) ctl = mixer_get_ctl(mixer, atoi(control)); else ctl = mixer_get_ctl_by_name(mixer, control); if (!ctl) { fprintf(stderr, "Invalid mixer control\n"); return; } type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); if (type == MIXER_CTL_TYPE_BYTE) { len = num_values; if (len > sizeof(buf)) { fprintf(stderr, "Truncating get to %zu bytes\n", sizeof(buf)); len = sizeof(buf); } ret = mixer_ctl_get_array(ctl, buf, len); if (ret < 0) { fprintf(stderr, "Failed to mixer_ctl_get_array\n"); return; } } if (print_all) printf("%s:", mixer_ctl_get_name(ctl)); for (i = 0; i < num_values; i++) { switch (type) { case MIXER_CTL_TYPE_INT: printf(" %d", mixer_ctl_get_value(ctl, i)); break; case MIXER_CTL_TYPE_BOOL: printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); break; case MIXER_CTL_TYPE_ENUM: tinymix_print_enum(ctl, print_all); break; case MIXER_CTL_TYPE_BYTE: printf("%02x", buf[i]); break; default: printf(" unknown"); break; }; } if (print_all) { if (type == MIXER_CTL_TYPE_INT) { min = mixer_ctl_get_range_min(ctl); max = mixer_ctl_get_range_max(ctl); printf(" (range %d->%d)", min, max); } } printf("\n"); }