static void tinymix_set_value(struct mixer *mixer, unsigned int id, char *string) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; ctl = mixer_get_ctl(mixer, id); type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); if (isdigit(string[0])) { int value = atoi(string); for (i = 0; i < num_values; i++) { if (mixer_ctl_set_value(ctl, i, value)) { fprintf(stderr, "Error: invalid value\n"); return; } } } else { if (type == MIXER_CTL_TYPE_ENUM) { if (mixer_ctl_set_enum_by_string(ctl, string)) fprintf(stderr, "Error: invalid enum value\n"); } else { fprintf(stderr, "Error: only enum types can be set with strings\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; }
int mixer_cache_apply(struct audio_tool_mixer_cache *cache, struct mixer *mixer) { struct audio_tool_mixer_control_info *cur; struct mixer_ctl *ctl; int n, k, ret=0; for (n = 0 ; n < cache->count ; ++n) { cur = &cache->ctrls[n]; ctl = mixer_get_ctl(mixer, n); for (k = 0 ; k < cur->num_values ; ++k) { switch (cur->type) { case MIXER_CTL_TYPE_BOOL: case MIXER_CTL_TYPE_INT: mixer_ctl_set_value(ctl, k, cur->value.integer[k]); break; case MIXER_CTL_TYPE_ENUM: mixer_ctl_set_enum_by_string(ctl, cur->value.enumerated[k]); break; case MIXER_CTL_TYPE_BYTE: mixer_ctl_set_value(ctl, k, cur->value.byte[k]); break; case MIXER_CTL_TYPE_INT64: mixer_ctl_set_value(ctl, k, cur->value.integer64[k]); break; default: ret = 1; } } } return ret; }
static void tinymix_set_value(struct mixer *mixer, const char *control, char **values, unsigned int num_values) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_ctl_values; unsigned int i; 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_ctl_values = mixer_ctl_get_num_values(ctl); if (isdigit(values[0][0])) { if (num_values == 1) { /* Set all values the same */ int value = atoi(values[0]); for (i = 0; i < num_ctl_values; i++) { if (mixer_ctl_set_value(ctl, i, value)) { fprintf(stderr, "Error: invalid value\n"); return; } } } else { /* Set multiple values */ if (num_values > num_ctl_values) { fprintf(stderr, "Error: %d values given, but control only takes %d\n", num_values, num_ctl_values); return; } for (i = 0; i < num_values; i++) { if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) { fprintf(stderr, "Error: invalid value for index %d\n", i); return; } } } } else { if (type == MIXER_CTL_TYPE_ENUM) { if (num_values != 1) { fprintf(stderr, "Enclose strings in quotes and try again\n"); return; } if (mixer_ctl_set_enum_by_string(ctl, values[0])) fprintf(stderr, "Error: invalid enum value\n"); } else { fprintf(stderr, "Error: only enum types can be set with strings\n"); } } }
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"); } }
static int alloc_mixer_state(struct audio_route *ar) { unsigned int i; unsigned int j; if (!ar) { ALOGE("%s: invalid audio_route", __func__); return -1; } ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); if (!ar->mixer_state) return -1; for (i = 0; i < ar->num_mixer_ctls; i++) { ar->mixer_state[i].ctl = mixer_get_ctl(ar->mixer, i); ar->mixer_state[i].ctl_vals = mixer_ctl_get_num_values(ar->mixer_state[i].ctl); ar->mixer_state[i].ignored = 0; if (ar->mixer_state[i].ctl_vals > MAX_CTL_VALS) { ar->mixer_state[i].ctl_vals = MAX_CTL_VALS; } for (j = 0; j < ar->mixer_state[i].ctl_vals; j++) { ar->mixer_state[i].old_value[j] = mixer_ctl_get_value(ar->mixer_state[i].ctl, j); ar->mixer_state[i].new_value[j] = ar->mixer_state[i].old_value[j]; } } 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; 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 int alloc_mixer_state(struct audio_route *ar) { unsigned int i; unsigned int j; unsigned int num_values; struct mixer_ctl *ctl; bool linked; ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); if (!ar->mixer_state) return -1; for (i = 0; i < ar->num_mixer_ctls; i++) { ctl = mixer_get_ctl(ar->mixer, i); num_values = mixer_ctl_get_num_values(ctl); ar->mixer_state[i].old_value = malloc(num_values * sizeof(int)); ar->mixer_state[i].new_value = malloc(num_values * sizeof(int)); ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int)); /* * Get all mixer values for controls with multiple values. If all * values are the same, set the linked flag. */ linked = true; for (j = 0; j < num_values; j++) { ar->mixer_state[i].old_value[j] = mixer_ctl_get_value(ctl, j); ar->mixer_state[i].new_value[j] = ar->mixer_state[i].old_value[j]; /* * If the next value is different from the last, set linked to * false. */ if ((j > 0) && (ar->mixer_state[i].old_value[j - 1] != ar->mixer_state[i].old_value[j])) { linked = false; } } ar->mixer_state[i].ctl = ctl; ar->mixer_state[i].old_linked = linked; ar->mixer_state[i].new_linked = linked; ar->mixer_state[i].num_values = num_values; } return 0; }
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; }
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; }
static int alloc_mixer_state(struct audio_route *ar) { unsigned int i; ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); if (!ar->mixer_state) return -1; for (i = 0; i < ar->num_mixer_ctls; i++) { ar->mixer_state[i].ctl = mixer_get_ctl(ar->mixer, i); /* only get value 0, assume multiple ctl values are the same */ ar->mixer_state[i].old_value = mixer_ctl_get_value(ar->mixer_state[i].ctl, 0); ar->mixer_state[i].new_value = ar->mixer_state[i].old_value; } return 0; }
static void tinymix_set_value(struct mixer *mixer, unsigned int id, unsigned int value) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; ctl = mixer_get_ctl(mixer, id); type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); for (i = 0; i < num_values; i++) { if (mixer_ctl_set_value(ctl, i, value)) { fprintf(stderr, "Error: invalid value\n"); return; } } }
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 int alloc_mixer_state(struct audio_route *ar) { unsigned int i; unsigned int j; unsigned int num_values; struct mixer_ctl *ctl; enum mixer_ctl_type type; ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer); ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state)); if (!ar->mixer_state) return -1; for (i = 0; i < ar->num_mixer_ctls; i++) { ctl = mixer_get_ctl(ar->mixer, i); num_values = mixer_ctl_get_num_values(ctl); ar->mixer_state[i].ctl = ctl; ar->mixer_state[i].num_values = num_values; /* Skip unsupported types that are not supported yet in XML */ type = mixer_ctl_get_type(ctl); if ((type != MIXER_CTL_TYPE_BOOL) && (type != MIXER_CTL_TYPE_INT) && (type != MIXER_CTL_TYPE_ENUM)) continue; ar->mixer_state[i].old_value = malloc(num_values * sizeof(int)); ar->mixer_state[i].new_value = malloc(num_values * sizeof(int)); ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int)); if (type == MIXER_CTL_TYPE_ENUM) ar->mixer_state[i].old_value[0] = mixer_ctl_get_value(ctl, 0); else mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value, num_values); memcpy(ar->mixer_state[i].new_value, ar->mixer_state[i].old_value, num_values * sizeof(int)); } 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[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"); }
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 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"); }
bool TinyAmixerControl::accessHW(bool receive, std::string &error) { CAutoLog autoLog(getConfigurableElement(), "ALSA", isDebugEnabled()); // Mixer handle struct mixer *mixer; // Mixer control handle struct mixer_ctl *mixerControl; uint32_t elementCount; std::string controlName = getControlName(); // Debug conditionnaly enabled in XML logControlInfo(receive); // Check parameter type is ok (deferred error, no exceptions available :-() if (!isTypeSupported()) { error = "Parameter type not supported."; return false; } // Check card number int32_t cardIndex = getCardNumber(); if (cardIndex < 0) { error = "Card " + getCardName() + " not found. Error: " + strerror(-cardIndex); return false; } // Open alsa mixer // getMixerHandle is non-const; we need to forcefully remove the constness // then, we need to cast the generic subsystem into a TinyAlsaSubsystem. mixer = static_cast<TinyAlsaSubsystem *>( const_cast<CSubsystem *>(getSubsystem()))->getMixerHandle(cardIndex); if (!mixer) { error = "Failed to open mixer for card: " + getCardName(); return false; } // Get control handle if (isdigit(controlName[0])) { mixerControl = mixer_get_ctl(mixer, asInteger(controlName)); } else { mixerControl = mixer_get_ctl_by_name(mixer, controlName.c_str()); } // Check control has been found if (!mixerControl) { error = "Failed to open mixer control: " + controlName; return false; } // Get element count elementCount = getNumValues(mixerControl); uint32_t scalarSize = getScalarSize(); // Check available size if (elementCount * scalarSize != getSize()) { error = "ALSA: Control element count (" + asString(elementCount) + ") and configurable scalar element count (" + asString(getSize() / scalarSize) + ") mismatch"; return false; } // Read/Write element bool success; if (receive) { success = readControl(mixerControl, elementCount, error); } else { success = writeControl(mixerControl, elementCount, error); } return success; }
static void tinymix_detail_control(struct mixer *mixer, const char *control) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int num_values; unsigned int i; int min, max; int ret; char *buf = NULL; unsigned int tlv_header_size = 0; 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)) { if (mixer_ctl_is_access_tlv_rw(ctl) != 0) { tlv_header_size = TLV_HEADER_SIZE; } buf = calloc(1, num_values + tlv_header_size); if (buf == NULL) { fprintf(stderr, "Failed to alloc mem for bytes %u\n", num_values); return; } ret = mixer_ctl_get_array(ctl, buf, num_values + tlv_header_size); if (ret < 0) { fprintf(stderr, "Failed to mixer_ctl_get_array\n"); free(buf); return; } } 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); break; case MIXER_CTL_TYPE_BYTE: /* skip printing TLV header if exists */ printf(" %02x", buf[i + tlv_header_size]); break; default: printf("unknown"); break; }; if ((i + 1) < num_values) { printf(", "); } } 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); }
/* Notes: * - param 'line' is modified by this function * - param 'db' has mixer_cache_touch() called on it. */ static void process_line(char* line, struct audio_tool_mixer_cache *db, struct mixer *mixer) { size_t length = strlen(line); size_t pos = 0, sep; const char* sep_ptr; enum field_t { FNAME=0, FTYPE, FCOUNT, FVALS } field = FNAME; unsigned control_id, val, val_no; const char *ctl_type; unsigned file_count, ctl_count; struct mixer_ctl *ctl; if (!length) return; if (line[0] == '#') return; control_id = -1; val_no = 0; while (pos < length) { sep_ptr = strstr(&line[pos], "\t"); if (sep_ptr) sep = (size_t) (sep_ptr - line); else sep = length; if (sep < length) line[sep] = '\0'; switch(field) { case FNAME: control_id = mixer_cache_get_id_by_name(db, &line[pos]); if (control_id == -1) { printf("Error: could not find control %s\n", &line[pos]); pos = length; } ctl = mixer_get_ctl(mixer, control_id); break; case FTYPE: ctl_type = mixer_ctl_get_type_string(ctl); if (0 != strcmp(ctl_type, &line[pos])) { printf("Error: type mismatch for control #%d: file=%s card=%s\n", control_id, &line[pos], ctl_type); pos = length; } break; case FCOUNT: ctl_count = mixer_ctl_get_num_values(ctl); file_count = atoi(&line[pos]); if (ctl_count != file_count) { printf("Error: mismatch in the count of control #%d's values: " "file=%d card=%d\n", control_id, file_count, ctl_count); pos = length; } break; case FVALS: if (0 == strcmp("#N/A", &line[pos])) { pos = length; } else if (0 == strcmp("ENUM", ctl_type)) { mixer_ctl_set_enum_by_string(ctl, &line[pos]); } else { val = atoi(&line[pos]); mixer_ctl_set_value(ctl, val_no, val); } ++val_no; break; } if (field != FVALS) ++field; pos = sep + 1; } mixer_cache_touch(db, control_id); }