| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <gtest/gtest.h> |
| #include <stdio.h> |
| #include <syslog.h> |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| extern "C" { |
| #include "cras_alsa_mixer.h" |
| #include "cras_alsa_mixer_name.h" |
| #include "cras_types.h" |
| #include "cras_util.h" |
| #include "cras_volume_curve.h" |
| #include "utlist.h" |
| |
| // Include C file to test static functions and use the definition of some |
| // structure. |
| #include "cras_alsa_mixer.c" |
| } |
| |
| namespace { |
| |
| static size_t snd_mixer_open_called; |
| static int snd_mixer_open_return_value; |
| static size_t snd_mixer_close_called; |
| static size_t snd_mixer_attach_called; |
| static int snd_mixer_attach_return_value; |
| const char* snd_mixer_attach_mixdev; |
| static size_t snd_mixer_selem_register_called; |
| static int snd_mixer_selem_register_return_value; |
| static size_t snd_mixer_load_called; |
| static int snd_mixer_load_return_value; |
| static size_t snd_mixer_first_elem_called; |
| static snd_mixer_elem_t* snd_mixer_first_elem_return_value; |
| static int snd_mixer_elem_next_called; |
| static snd_mixer_elem_t** snd_mixer_elem_next_return_values; |
| static int snd_mixer_elem_next_return_values_index; |
| static int snd_mixer_elem_next_return_values_length; |
| static int snd_mixer_selem_set_playback_dB_all_called; |
| static long* snd_mixer_selem_set_playback_dB_all_values; |
| static int snd_mixer_selem_set_playback_dB_all_values_length; |
| static int snd_mixer_selem_set_playback_switch_all_called; |
| static int snd_mixer_selem_set_playback_switch_all_value; |
| static int snd_mixer_selem_has_playback_volume_called; |
| static int* snd_mixer_selem_has_playback_volume_return_values; |
| static int snd_mixer_selem_has_playback_volume_return_values_length; |
| static int snd_mixer_selem_has_playback_switch_called; |
| static int* snd_mixer_selem_has_playback_switch_return_values; |
| static int snd_mixer_selem_has_playback_switch_return_values_length; |
| static int snd_mixer_selem_set_capture_dB_all_called; |
| static long* snd_mixer_selem_set_capture_dB_all_values; |
| static int snd_mixer_selem_set_capture_dB_all_values_length; |
| static int snd_mixer_selem_set_capture_switch_all_called; |
| static int snd_mixer_selem_set_capture_switch_all_value; |
| static int snd_mixer_selem_has_capture_volume_called; |
| static int* snd_mixer_selem_has_capture_volume_return_values; |
| static int snd_mixer_selem_has_capture_volume_return_values_length; |
| static int snd_mixer_selem_has_capture_switch_called; |
| static int* snd_mixer_selem_has_capture_switch_return_values; |
| static int snd_mixer_selem_has_capture_switch_return_values_length; |
| static int snd_mixer_selem_get_name_called; |
| static const char** snd_mixer_selem_get_name_return_values; |
| static int snd_mixer_selem_get_name_return_values_length; |
| static int snd_mixer_selem_get_playback_dB_called; |
| static long* snd_mixer_selem_get_playback_dB_return_values; |
| static int snd_mixer_selem_get_playback_dB_return_values_length; |
| static int snd_mixer_selem_get_capture_dB_called; |
| static long* snd_mixer_selem_get_capture_dB_return_values; |
| static int snd_mixer_selem_get_capture_dB_return_values_length; |
| static size_t cras_volume_curve_destroy_called; |
| static size_t snd_mixer_selem_get_playback_dB_range_called; |
| static size_t snd_mixer_selem_get_playback_dB_range_values_length; |
| static const long* snd_mixer_selem_get_playback_dB_range_min_values; |
| static const long* snd_mixer_selem_get_playback_dB_range_max_values; |
| static size_t snd_mixer_selem_get_capture_dB_range_called; |
| static size_t snd_mixer_selem_get_capture_dB_range_values_length; |
| static const long* snd_mixer_selem_get_capture_dB_range_min_values; |
| static const long* snd_mixer_selem_get_capture_dB_range_max_values; |
| static size_t iniparser_getstring_return_index; |
| static size_t iniparser_getstring_return_length; |
| static char** iniparser_getstring_returns; |
| static size_t snd_mixer_find_selem_called; |
| static std::map<std::string, snd_mixer_elem_t*> snd_mixer_find_elem_map; |
| static std::string snd_mixer_find_elem_id_name; |
| |
| static void ResetStubData() { |
| iniparser_getstring_return_index = 0; |
| iniparser_getstring_return_length = 0; |
| snd_mixer_open_called = 0; |
| snd_mixer_open_return_value = 0; |
| snd_mixer_close_called = 0; |
| snd_mixer_attach_called = 0; |
| snd_mixer_attach_return_value = 0; |
| snd_mixer_attach_mixdev = static_cast<const char*>(NULL); |
| snd_mixer_selem_register_called = 0; |
| snd_mixer_selem_register_return_value = 0; |
| snd_mixer_load_called = 0; |
| snd_mixer_load_return_value = 0; |
| snd_mixer_first_elem_called = 0; |
| snd_mixer_first_elem_return_value = static_cast<snd_mixer_elem_t*>(NULL); |
| snd_mixer_elem_next_called = 0; |
| snd_mixer_elem_next_return_values = static_cast<snd_mixer_elem_t**>(NULL); |
| snd_mixer_elem_next_return_values_index = 0; |
| snd_mixer_elem_next_return_values_length = 0; |
| snd_mixer_selem_set_playback_dB_all_called = 0; |
| snd_mixer_selem_set_playback_dB_all_values = static_cast<long*>(NULL); |
| snd_mixer_selem_set_playback_dB_all_values_length = 0; |
| snd_mixer_selem_set_playback_switch_all_called = 0; |
| snd_mixer_selem_has_playback_volume_called = 0; |
| snd_mixer_selem_has_playback_volume_return_values = static_cast<int*>(NULL); |
| snd_mixer_selem_has_playback_volume_return_values_length = 0; |
| snd_mixer_selem_has_playback_switch_called = 0; |
| snd_mixer_selem_has_playback_switch_return_values = static_cast<int*>(NULL); |
| snd_mixer_selem_has_playback_switch_return_values_length = 0; |
| snd_mixer_selem_set_capture_dB_all_called = 0; |
| snd_mixer_selem_set_capture_dB_all_values = static_cast<long*>(NULL); |
| snd_mixer_selem_set_capture_dB_all_values_length = 0; |
| snd_mixer_selem_set_capture_switch_all_called = 0; |
| snd_mixer_selem_has_capture_volume_called = 0; |
| snd_mixer_selem_has_capture_volume_return_values = static_cast<int*>(NULL); |
| snd_mixer_selem_has_capture_volume_return_values_length = 0; |
| snd_mixer_selem_has_capture_switch_called = 0; |
| snd_mixer_selem_has_capture_switch_return_values = static_cast<int*>(NULL); |
| snd_mixer_selem_has_capture_switch_return_values_length = 0; |
| snd_mixer_selem_get_name_called = 0; |
| snd_mixer_selem_get_name_return_values = static_cast<const char**>(NULL); |
| snd_mixer_selem_get_name_return_values_length = 0; |
| snd_mixer_selem_get_playback_dB_called = 0; |
| snd_mixer_selem_get_playback_dB_return_values = static_cast<long*>(NULL); |
| snd_mixer_selem_get_playback_dB_return_values_length = 0; |
| snd_mixer_selem_get_capture_dB_called = 0; |
| snd_mixer_selem_get_capture_dB_return_values = static_cast<long*>(NULL); |
| snd_mixer_selem_get_capture_dB_return_values_length = 0; |
| cras_volume_curve_destroy_called = 0; |
| snd_mixer_selem_get_playback_dB_range_called = 0; |
| snd_mixer_selem_get_playback_dB_range_values_length = 0; |
| snd_mixer_selem_get_playback_dB_range_min_values = static_cast<long*>(NULL); |
| snd_mixer_selem_get_playback_dB_range_max_values = static_cast<long*>(NULL); |
| snd_mixer_selem_get_capture_dB_range_called = 0; |
| snd_mixer_selem_get_capture_dB_range_values_length = 0; |
| snd_mixer_selem_get_capture_dB_range_min_values = static_cast<long*>(NULL); |
| snd_mixer_selem_get_capture_dB_range_max_values = static_cast<long*>(NULL); |
| snd_mixer_find_selem_called = 0; |
| snd_mixer_find_elem_map.clear(); |
| snd_mixer_find_elem_id_name.clear(); |
| } |
| |
| struct cras_alsa_mixer* create_mixer_and_add_controls_by_name_matching( |
| const char* card_name, |
| struct mixer_name* extra_controls, |
| struct mixer_name* coupled_controls) { |
| struct cras_alsa_mixer* cmix = cras_alsa_mixer_create(card_name); |
| cras_alsa_mixer_add_controls_by_name_matching(cmix, extra_controls, |
| coupled_controls); |
| return cmix; |
| } |
| |
| TEST(AlsaMixer, CreateFailOpen) { |
| struct cras_alsa_mixer* c; |
| |
| ResetStubData(); |
| snd_mixer_open_return_value = -1; |
| c = cras_alsa_mixer_create("hw:0"); |
| EXPECT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| cras_alsa_mixer_destroy(c); |
| } |
| |
| TEST(AlsaMixer, CreateFailAttach) { |
| struct cras_alsa_mixer* c; |
| |
| ResetStubData(); |
| snd_mixer_attach_return_value = -1; |
| c = cras_alsa_mixer_create("hw:0"); |
| EXPECT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| cras_alsa_mixer_destroy(c); |
| } |
| |
| TEST(AlsaMixer, CreateFailSelemRegister) { |
| struct cras_alsa_mixer* c; |
| |
| ResetStubData(); |
| snd_mixer_selem_register_return_value = -1; |
| c = cras_alsa_mixer_create("hw:0"); |
| EXPECT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| cras_alsa_mixer_destroy(c); |
| } |
| |
| TEST(AlsaMixer, CreateFailLoad) { |
| struct cras_alsa_mixer* c; |
| |
| ResetStubData(); |
| snd_mixer_load_return_value = -1; |
| c = cras_alsa_mixer_create("hw:0"); |
| EXPECT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| cras_alsa_mixer_destroy(c); |
| } |
| |
| TEST(AlsaMixer, CreateNoElements) { |
| struct cras_alsa_mixer* c; |
| |
| ResetStubData(); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| |
| /* set mute shouldn't call anything. */ |
| cras_alsa_mixer_set_mute(c, 0, NULL); |
| EXPECT_EQ(0, snd_mixer_selem_set_playback_switch_all_called); |
| /* set volume shouldn't call anything. */ |
| cras_alsa_mixer_set_dBFS(c, 0, NULL); |
| EXPECT_EQ(0, snd_mixer_selem_set_playback_dB_all_called); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| } |
| |
| TEST(AlsaMixer, CreateOneUnknownElementWithoutVolume) { |
| struct cras_alsa_mixer* c; |
| int element_playback_volume[] = { |
| 0, |
| }; |
| int element_playback_switches[] = { |
| 1, |
| }; |
| const char* element_names[] = { |
| "Unknown", |
| }; |
| struct mixer_control* mixer_output; |
| int rc; |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(0, snd_mixer_selem_get_playback_dB_range_called); |
| |
| /* set mute shouldn't call anything. */ |
| cras_alsa_mixer_set_mute(c, 0, NULL); |
| EXPECT_EQ(0, snd_mixer_selem_set_playback_switch_all_called); |
| |
| ResetStubData(); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| rc = mixer_control_create(&mixer_output, NULL, |
| reinterpret_cast<snd_mixer_elem_t*>(1), |
| CRAS_STREAM_OUTPUT); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(1, snd_mixer_selem_get_playback_dB_range_called); |
| |
| /* if passed a mixer output then it should mute that. */ |
| cras_alsa_mixer_set_mute(c, 0, mixer_output); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_called); |
| /* set volume shouldn't call anything. */ |
| cras_alsa_mixer_set_dBFS(c, 0, NULL); |
| EXPECT_EQ(0, snd_mixer_selem_set_playback_dB_all_called); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_control_destroy(mixer_output); |
| } |
| |
| TEST(AlsaMixer, CreateOneUnknownElementWithVolume) { |
| struct cras_alsa_mixer* c; |
| static const long min_volumes[] = {-500}; |
| static const long max_volumes[] = {40}; |
| int element_playback_volume[] = { |
| 1, |
| 0, |
| }; |
| int element_playback_switches[] = { |
| 0, |
| 1, |
| }; |
| const char* element_names[] = { |
| "Unknown", |
| "Playback", |
| }; |
| struct mixer_control* mixer_output; |
| int rc; |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_range_called); |
| EXPECT_EQ(3, snd_mixer_selem_get_name_called); |
| |
| /* Should use "Playback" since it has playback switch. */ |
| cras_alsa_mixer_set_mute(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_called); |
| |
| ResetStubData(); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| rc = mixer_control_create(&mixer_output, NULL, |
| reinterpret_cast<snd_mixer_elem_t*>(2), |
| CRAS_STREAM_OUTPUT); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(0, snd_mixer_selem_get_playback_dB_range_called); |
| |
| /* |
| * If passed a mixer output then it should mute both "Playback" and that |
| * mixer_output. |
| */ |
| cras_alsa_mixer_set_mute(c, 0, mixer_output); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_switch_all_called); |
| cras_alsa_mixer_set_dBFS(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_dB_all_called); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_control_destroy(mixer_output); |
| } |
| |
| TEST(AlsaMixer, CreateOneMainElement) { |
| struct cras_alsa_mixer* c; |
| int element_playback_volume[] = { |
| 1, |
| 1, |
| }; |
| int element_playback_switches[] = { |
| 1, |
| 1, |
| }; |
| const char* element_names[] = {"Master", "Playback"}; |
| struct mixer_control* mixer_output; |
| int rc; |
| long set_dB_values[3]; |
| static const long min_volumes[] = {0, 0}; |
| static const long max_volumes[] = {950, 950}; |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(3, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_elem_next_called); |
| |
| /* set mute should be called for Main. */ |
| cras_alsa_mixer_set_mute(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_called); |
| /* set volume should be called for Main. */ |
| cras_alsa_mixer_set_dBFS(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_dB_all_called); |
| |
| ResetStubData(); |
| snd_mixer_selem_set_playback_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_playback_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| rc = mixer_control_create(&mixer_output, NULL, |
| reinterpret_cast<snd_mixer_elem_t*>(2), |
| CRAS_STREAM_OUTPUT); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(1, snd_mixer_selem_get_playback_dB_range_called); |
| |
| /* if passed a mixer output then it should set the volume for that too. */ |
| cras_alsa_mixer_set_dBFS(c, 0, mixer_output); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_dB_all_called); |
| EXPECT_EQ(950, set_dB_values[0]); |
| EXPECT_EQ(950, set_dB_values[1]); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_control_destroy(mixer_output); |
| } |
| |
| TEST(AlsaMixer, CreateTwoMainVolumeElements) { |
| struct cras_alsa_mixer* c; |
| snd_mixer_elem_t* elements[] = { |
| reinterpret_cast<snd_mixer_elem_t*>(2), |
| }; |
| int element_playback_volume[] = { |
| 1, |
| 1, |
| 1, |
| }; |
| int element_playback_switches[] = { |
| 1, |
| 1, |
| 1, |
| }; |
| const char* element_names[] = { |
| "Master", |
| "PCM", |
| "Other", |
| }; |
| struct mixer_control* mixer_output; |
| int rc; |
| static const long min_volumes[] = {-500, -1250, -500}; |
| static const long max_volumes[] = {40, 40, 0}; |
| long get_dB_returns[] = {0, 0, 0}; |
| long set_dB_values[3]; |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_elem_next_return_values = elements; |
| snd_mixer_elem_next_return_values_length = ARRAY_SIZE(elements); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| snd_mixer_selem_get_playback_dB_range_called = 0; |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| snd_mixer_selem_set_playback_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_playback_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_range_called); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(2, snd_mixer_elem_next_called); |
| EXPECT_EQ(5, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_playback_switch_called); |
| |
| /* Set mute should be called for Main only. */ |
| cras_alsa_mixer_set_mute(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_called); |
| |
| /* Set volume should be called for Main and PCM. If Main doesn't set to |
| * anything but zero then the entire volume should be passed to the PCM |
| * control.*/ |
| |
| /* Set volume should be called for Main and PCM. (without mixer_output) */ |
| snd_mixer_selem_get_playback_dB_return_values = get_dB_returns; |
| snd_mixer_selem_get_playback_dB_return_values_length = |
| ARRAY_SIZE(get_dB_returns); |
| cras_alsa_mixer_set_dBFS(c, -50, NULL); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_called); |
| /* volume should be set relative to max volume (40 + 40). */ |
| EXPECT_EQ(30, set_dB_values[0]); |
| EXPECT_EQ(30, set_dB_values[1]); |
| |
| ResetStubData(); |
| snd_mixer_selem_set_playback_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_playback_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| rc = mixer_control_create(&mixer_output, NULL, |
| reinterpret_cast<snd_mixer_elem_t*>(3), |
| CRAS_STREAM_OUTPUT); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(1, snd_mixer_selem_get_playback_dB_range_called); |
| |
| /* Set volume should be called for Main, PCM, and the mixer_output passed |
| * in. If Main doesn't set to anything but zero then the entire volume |
| * should be passed to the PCM control.*/ |
| cras_alsa_mixer_set_dBFS(c, -50, mixer_output); |
| EXPECT_EQ(3, snd_mixer_selem_set_playback_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_called); |
| EXPECT_EQ(30, set_dB_values[0]); |
| EXPECT_EQ(30, set_dB_values[1]); |
| EXPECT_EQ(30, set_dB_values[2]); |
| /* Set volume should be called for Main and PCM. Since the controls were |
| * sorted, Main should get the volume remaining after PCM is set, in this |
| * case -50 - -24 = -26. */ |
| long get_dB_returns2[] = { |
| -25, |
| -24, |
| }; |
| snd_mixer_selem_get_playback_dB_return_values = get_dB_returns2; |
| snd_mixer_selem_get_playback_dB_return_values_length = |
| ARRAY_SIZE(get_dB_returns2); |
| snd_mixer_selem_set_playback_dB_all_called = 0; |
| snd_mixer_selem_get_playback_dB_called = 0; |
| mixer_output->has_volume = 0; |
| mixer_output->min_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID; |
| mixer_output->max_volume_dB = MIXER_CONTROL_VOLUME_DB_INVALID; |
| cras_alsa_mixer_set_dBFS(c, -50, mixer_output); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_playback_dB_called); |
| EXPECT_EQ(54, set_dB_values[0]); // Main |
| EXPECT_EQ(30, set_dB_values[1]); // PCM |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_control_destroy(mixer_output); |
| } |
| |
| TEST(AlsaMixer, CreateTwoMainCaptureElements) { |
| struct cras_alsa_mixer* c; |
| snd_mixer_elem_t* elements[] = { |
| reinterpret_cast<snd_mixer_elem_t*>(2), |
| }; |
| int element_capture_volume[] = { |
| 1, |
| 1, |
| 1, |
| }; |
| int element_capture_switches[] = { |
| 1, |
| 1, |
| 1, |
| }; |
| const char* element_names[] = { |
| "Capture", |
| "Digital Capture", |
| "Mic", |
| }; |
| struct mixer_control* mixer_input; |
| int rc; |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_elem_next_return_values = elements; |
| snd_mixer_elem_next_return_values_length = ARRAY_SIZE(elements); |
| snd_mixer_selem_has_capture_volume_return_values = element_capture_volume; |
| snd_mixer_selem_has_capture_volume_return_values_length = |
| ARRAY_SIZE(element_capture_volume); |
| snd_mixer_selem_has_capture_switch_return_values = element_capture_switches; |
| snd_mixer_selem_has_capture_switch_return_values_length = |
| ARRAY_SIZE(element_capture_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(2, snd_mixer_elem_next_called); |
| EXPECT_EQ(5, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_capture_switch_called); |
| |
| /* Set mute should be called for Main only. */ |
| cras_alsa_mixer_set_capture_mute(c, 0, NULL); |
| EXPECT_EQ(1, snd_mixer_selem_set_capture_switch_all_called); |
| /* Set volume should be called for Capture and Digital Capture. If Capture |
| * doesn't set to anything but zero then the entire volume should be passed to |
| * the Digital Capture control. */ |
| long get_dB_returns[] = { |
| 0, |
| 0, |
| }; |
| long set_dB_values[2]; |
| snd_mixer_selem_get_capture_dB_return_values = get_dB_returns; |
| snd_mixer_selem_get_capture_dB_return_values_length = |
| ARRAY_SIZE(get_dB_returns); |
| snd_mixer_selem_set_capture_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_capture_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| cras_alsa_mixer_set_capture_dBFS(c, -10, NULL); |
| EXPECT_EQ(2, snd_mixer_selem_set_capture_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_capture_dB_called); |
| EXPECT_EQ(-10, set_dB_values[0]); |
| EXPECT_EQ(-10, set_dB_values[1]); |
| /* Set volume should be called for Capture and Digital Capture. Capture should |
| * get the gain remaining after Mic Boos is set, in this case 20 - 25 = -5. */ |
| long get_dB_returns2[] = { |
| 25, |
| -5, |
| }; |
| snd_mixer_selem_get_capture_dB_return_values = get_dB_returns2; |
| snd_mixer_selem_get_capture_dB_return_values_length = |
| ARRAY_SIZE(get_dB_returns2); |
| snd_mixer_selem_set_capture_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_capture_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| snd_mixer_selem_set_capture_dB_all_called = 0; |
| snd_mixer_selem_get_capture_dB_called = 0; |
| cras_alsa_mixer_set_capture_dBFS(c, 20, NULL); |
| EXPECT_EQ(2, snd_mixer_selem_set_capture_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_capture_dB_called); |
| EXPECT_EQ(20, set_dB_values[0]); |
| EXPECT_EQ(-5, set_dB_values[1]); |
| |
| /* Set volume to the two main controls plus additional specific input |
| * volume control */ |
| |
| long get_dB_returns3[] = { |
| 0, |
| 0, |
| 0, |
| }; |
| long set_dB_values3[3]; |
| |
| snd_mixer_selem_get_capture_dB_return_values = get_dB_returns3; |
| snd_mixer_selem_get_capture_dB_return_values_length = |
| ARRAY_SIZE(get_dB_returns3); |
| snd_mixer_selem_get_capture_dB_called = 0; |
| snd_mixer_selem_set_capture_dB_all_values = set_dB_values3; |
| snd_mixer_selem_set_capture_dB_all_values_length = ARRAY_SIZE(set_dB_values3); |
| snd_mixer_selem_set_capture_dB_all_called = 0; |
| snd_mixer_selem_has_capture_volume_return_values = element_capture_volume; |
| snd_mixer_selem_has_capture_volume_return_values_length = |
| ARRAY_SIZE(element_capture_volume); |
| snd_mixer_selem_has_capture_switch_return_values = element_capture_switches; |
| snd_mixer_selem_has_capture_switch_return_values_length = |
| ARRAY_SIZE(element_capture_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| snd_mixer_selem_get_name_called = 0; |
| snd_mixer_selem_has_capture_volume_called = 0; |
| snd_mixer_selem_has_capture_switch_called = 0; |
| snd_mixer_selem_get_capture_dB_range_called = 0; |
| rc = mixer_control_create(&mixer_input, NULL, |
| reinterpret_cast<snd_mixer_elem_t*>(3), |
| CRAS_STREAM_INPUT); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_get_name_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_capture_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_capture_switch_called); |
| EXPECT_EQ(1, snd_mixer_selem_get_capture_dB_range_called); |
| EXPECT_EQ(1, mixer_input->has_volume); |
| |
| cras_alsa_mixer_set_capture_dBFS(c, 20, mixer_input); |
| |
| EXPECT_EQ(3, snd_mixer_selem_set_capture_dB_all_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_capture_dB_called); |
| EXPECT_EQ(20, set_dB_values3[0]); |
| EXPECT_EQ(20, set_dB_values3[1]); |
| EXPECT_EQ(20, set_dB_values3[2]); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_control_destroy(mixer_input); |
| } |
| |
| class AlsaMixerOutputs : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| output_called_values_.clear(); |
| output_callback_called_ = 0; |
| static snd_mixer_elem_t* elements[] = { |
| reinterpret_cast<snd_mixer_elem_t*>(2), // PCM |
| reinterpret_cast<snd_mixer_elem_t*>(3), // Headphone |
| reinterpret_cast<snd_mixer_elem_t*>(4), // Speaker |
| reinterpret_cast<snd_mixer_elem_t*>(5), // HDMI |
| reinterpret_cast<snd_mixer_elem_t*>(6), // IEC958 |
| reinterpret_cast<snd_mixer_elem_t*>(7), // Mic Boost |
| reinterpret_cast<snd_mixer_elem_t*>(8), // Capture |
| }; |
| static int element_playback_volume[] = { |
| 1, 1, 1, 0, 0, 1, 1, |
| }; |
| static int element_playback_switches[] = { |
| 1, 1, 1, 0, 1, 1, 1, |
| }; |
| static int element_capture_volume[] = { |
| 0, 0, 0, 0, 0, 0, 1, 1, |
| }; |
| static int element_capture_switches[] = { |
| 0, 0, 0, 0, 0, 0, 1, 1, |
| }; |
| static const long min_volumes[] = {0, 0, 0, 0, 0, 0, 500, -1250}; |
| static const long max_volumes[] = {0, 0, 0, 0, 0, 0, 3000, 400}; |
| static const char* element_names[] = { |
| "Master", "PCM", "Headphone", "Speaker", |
| "HDMI", "IEC958", "Capture", "Digital Capture", |
| }; |
| static const char* output_names_extra[] = {"IEC958"}; |
| static char* iniparser_returns[] = { |
| NULL, |
| }; |
| struct mixer_name* extra_controls = mixer_name_add_array( |
| NULL, output_names_extra, ARRAY_SIZE(output_names_extra), |
| CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| |
| ResetStubData(); |
| snd_mixer_first_elem_return_value = |
| reinterpret_cast<snd_mixer_elem_t*>(1); // Main |
| snd_mixer_elem_next_return_values = elements; |
| snd_mixer_elem_next_return_values_length = ARRAY_SIZE(elements); |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = |
| element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_has_capture_volume_return_values = element_capture_volume; |
| snd_mixer_selem_has_capture_volume_return_values_length = |
| ARRAY_SIZE(element_capture_volume); |
| snd_mixer_selem_has_capture_switch_return_values = element_capture_switches; |
| snd_mixer_selem_has_capture_switch_return_values_length = |
| ARRAY_SIZE(element_capture_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| snd_mixer_selem_get_capture_dB_range_called = 0; |
| snd_mixer_selem_get_capture_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_capture_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_capture_dB_range_values_length = |
| ARRAY_SIZE(min_volumes); |
| iniparser_getstring_returns = iniparser_returns; |
| iniparser_getstring_return_length = ARRAY_SIZE(iniparser_returns); |
| cras_mixer_ = create_mixer_and_add_controls_by_name_matching( |
| "hw:0", extra_controls, NULL); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), cras_mixer_); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| EXPECT_EQ(ARRAY_SIZE(elements) + 1, snd_mixer_elem_next_called); |
| EXPECT_EQ(8, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(7, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(4, snd_mixer_selem_has_capture_volume_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_capture_switch_called); |
| mixer_name_free(extra_controls); |
| } |
| |
| virtual void TearDown() { |
| cras_alsa_mixer_destroy(cras_mixer_); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| } |
| |
| static void OutputCallback(struct mixer_control* out, void* arg) { |
| output_callback_called_++; |
| output_called_values_.push_back(out); |
| } |
| |
| struct cras_alsa_mixer* cras_mixer_; |
| static size_t output_callback_called_; |
| static std::vector<struct mixer_control*> output_called_values_; |
| }; |
| |
| size_t AlsaMixerOutputs::output_callback_called_; |
| std::vector<struct mixer_control*> AlsaMixerOutputs::output_called_values_; |
| |
| TEST_F(AlsaMixerOutputs, CheckFourOutputs) { |
| cras_alsa_mixer_list_outputs(cras_mixer_, AlsaMixerOutputs::OutputCallback, |
| reinterpret_cast<void*>(555)); |
| EXPECT_EQ(4, output_callback_called_); |
| } |
| |
| TEST_F(AlsaMixerOutputs, CheckFindOutputByNameNoMatch) { |
| struct mixer_control* out; |
| |
| out = cras_alsa_mixer_get_output_matching_name(cras_mixer_, "AAAAA Jack"); |
| EXPECT_EQ(static_cast<struct mixer_control*>(NULL), out); |
| } |
| |
| TEST_F(AlsaMixerOutputs, CheckFindOutputByName) { |
| struct mixer_control* out; |
| |
| out = cras_alsa_mixer_get_output_matching_name(cras_mixer_, "Headphone Jack"); |
| EXPECT_NE(static_cast<struct mixer_control*>(NULL), out); |
| } |
| |
| TEST_F(AlsaMixerOutputs, CheckFindOutputHDMIByName) { |
| struct mixer_control* out; |
| |
| out = cras_alsa_mixer_get_output_matching_name(cras_mixer_, "HDMI Jack"); |
| EXPECT_NE(static_cast<struct mixer_control*>(NULL), out); |
| } |
| |
| TEST_F(AlsaMixerOutputs, CheckFindInputNameWorkaround) { |
| struct mixer_control* control; |
| snd_mixer_elem_t* elements[] = { |
| reinterpret_cast<snd_mixer_elem_t*>(1), // Speaker |
| reinterpret_cast<snd_mixer_elem_t*>(2), // Headphone |
| reinterpret_cast<snd_mixer_elem_t*>(3), // MIC |
| }; |
| const char* element_names[] = { |
| "Speaker", |
| "Headphone", |
| "MIC", |
| }; |
| size_t i; |
| |
| ResetStubData(); |
| for (i = 0; i < ARRAY_SIZE(elements); i++) |
| snd_mixer_find_elem_map[element_names[i]] = elements[i]; |
| |
| snd_mixer_selem_get_name_called = 0; |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| control = cras_alsa_mixer_get_input_matching_name(cras_mixer_, "MIC"); |
| EXPECT_NE(static_cast<struct mixer_control*>(NULL), control); |
| /* This exercises the 'workaround' where the control is added if it was |
| * previouly missing in cras_alsa_mixer_get_input_matching_name(). |
| * snd_mixer_find_selem is called once for the missing control. */ |
| EXPECT_EQ(1, snd_mixer_find_selem_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_capture_volume_called); |
| EXPECT_EQ(1, snd_mixer_selem_has_capture_switch_called); |
| } |
| |
| TEST_F(AlsaMixerOutputs, ActivateDeactivate) { |
| int rc; |
| |
| cras_alsa_mixer_list_outputs(cras_mixer_, AlsaMixerOutputs::OutputCallback, |
| reinterpret_cast<void*>(555)); |
| EXPECT_EQ(4, output_callback_called_); |
| EXPECT_EQ(4, output_called_values_.size()); |
| |
| rc = cras_alsa_mixer_set_output_active_state(output_called_values_[0], 0); |
| ASSERT_EQ(0, rc); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_called); |
| cras_alsa_mixer_set_output_active_state(output_called_values_[0], 1); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_switch_all_called); |
| } |
| |
| TEST_F(AlsaMixerOutputs, MinMaxCaptureGain) { |
| long min, max; |
| min = cras_alsa_mixer_get_minimum_capture_gain(cras_mixer_, NULL); |
| EXPECT_EQ(-750, min); |
| max = cras_alsa_mixer_get_maximum_capture_gain(cras_mixer_, NULL); |
| EXPECT_EQ(3400, max); |
| } |
| |
| TEST_F(AlsaMixerOutputs, MinMaxCaptureGainWithActiveInput) { |
| struct mixer_control* mixer_input; |
| long min, max; |
| |
| mixer_input = (struct mixer_control*)calloc(1, sizeof(*mixer_input)); |
| mixer_input->min_volume_dB = 50; |
| mixer_input->max_volume_dB = 60; |
| mixer_input->has_volume = 1; |
| min = cras_alsa_mixer_get_minimum_capture_gain(cras_mixer_, mixer_input); |
| max = cras_alsa_mixer_get_maximum_capture_gain(cras_mixer_, mixer_input); |
| EXPECT_EQ(-700, min); |
| EXPECT_EQ(3460, max); |
| |
| free((void*)mixer_input); |
| } |
| |
| TEST(AlsaMixer, CreateWithCoupledOutputControls) { |
| struct cras_alsa_mixer* c; |
| struct mixer_control* output_control; |
| struct mixer_control_element *c1, *c2, *c3, *c4; |
| |
| static const long min_volumes[] = {-70, -70}; |
| static const long max_volumes[] = {30, 30}; |
| |
| long set_dB_values[2]; |
| |
| const char* coupled_output_names[] = {"Left Master", "Right Master", |
| "Left Speaker", "Right Speaker"}; |
| struct mixer_name* coupled_controls = mixer_name_add_array( |
| NULL, coupled_output_names, ARRAY_SIZE(coupled_output_names), |
| CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| int element_playback_volume[] = {1, 1, 0, 0}; |
| int element_playback_switches[] = {0, 0, 1, 1}; |
| |
| long target_dBFS = -30; |
| long expected_dB_value = target_dBFS + max_volumes[0]; |
| |
| ResetStubData(); |
| |
| snd_mixer_find_elem_map[std::string("Left Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_find_elem_map[std::string("Right Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(2); |
| snd_mixer_find_elem_map[std::string("Left Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(3); |
| snd_mixer_find_elem_map[std::string("Right Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(4); |
| |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, |
| coupled_controls); |
| |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| |
| output_control = c->output_controls; |
| EXPECT_EQ(NULL, output_control->next); |
| c1 = output_control->elements; |
| c2 = c1->next; |
| c3 = c2->next; |
| c4 = c3->next; |
| EXPECT_EQ(c1->elem, reinterpret_cast<snd_mixer_elem_t*>(1)); |
| EXPECT_EQ(c2->elem, reinterpret_cast<snd_mixer_elem_t*>(2)); |
| EXPECT_EQ(c3->elem, reinterpret_cast<snd_mixer_elem_t*>(3)); |
| EXPECT_EQ(c4->elem, reinterpret_cast<snd_mixer_elem_t*>(4)); |
| EXPECT_EQ(c4->next, reinterpret_cast<mixer_control_element*>(NULL)); |
| EXPECT_EQ(c1->has_volume, 1); |
| EXPECT_EQ(c1->has_mute, 0); |
| EXPECT_EQ(c2->has_volume, 1); |
| EXPECT_EQ(c2->has_mute, 0); |
| EXPECT_EQ(c3->has_volume, 0); |
| EXPECT_EQ(c3->has_mute, 1); |
| EXPECT_EQ(c4->has_volume, 0); |
| EXPECT_EQ(c4->has_mute, 1); |
| EXPECT_EQ(output_control->max_volume_dB, max_volumes[0]); |
| EXPECT_EQ(output_control->min_volume_dB, min_volumes[0]); |
| |
| snd_mixer_selem_set_playback_dB_all_values = set_dB_values; |
| snd_mixer_selem_set_playback_dB_all_values_length = ARRAY_SIZE(set_dB_values); |
| |
| cras_alsa_mixer_set_dBFS(c, target_dBFS, output_control); |
| |
| /* Set volume should set playback dB on two of the coupled controls. */ |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_dB_all_called); |
| EXPECT_EQ(set_dB_values[0], expected_dB_value); |
| EXPECT_EQ(set_dB_values[1], expected_dB_value); |
| |
| /* Mute should set playback switch on two of the coupled controls. */ |
| cras_alsa_mixer_set_mute(c, 1, output_control); |
| EXPECT_EQ(2, snd_mixer_selem_set_playback_switch_all_called); |
| EXPECT_EQ(0, snd_mixer_selem_set_playback_switch_all_value); |
| |
| /* Unmute should set playback switch on two of the coupled controls. */ |
| cras_alsa_mixer_set_mute(c, 0, output_control); |
| EXPECT_EQ(4, snd_mixer_selem_set_playback_switch_all_called); |
| EXPECT_EQ(1, snd_mixer_selem_set_playback_switch_all_value); |
| |
| EXPECT_EQ(max_volumes[0] - min_volumes[0], |
| cras_alsa_mixer_get_output_dB_range(output_control)); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_name_free(coupled_controls); |
| } |
| |
| TEST(AlsaMixer, CoupledOutputHasMuteNoVolume) { |
| struct cras_alsa_mixer* c; |
| struct mixer_control* output_control; |
| struct mixer_control_element *c1, *c2, *c3, *c4; |
| |
| static const long min_volumes[] = {-70}; |
| static const long max_volumes[] = {30}; |
| |
| const char* coupled_output_names[] = {"Left Master", "Right Master", |
| "Left Speaker", "Right Speaker"}; |
| struct mixer_name* coupled_controls = mixer_name_add_array( |
| NULL, coupled_output_names, ARRAY_SIZE(coupled_output_names), |
| CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| int element_playback_volume[] = {0, 0, 0, 0}; |
| int element_playback_switches[] = {0, 0, 1, 1}; |
| |
| ResetStubData(); |
| |
| snd_mixer_find_elem_map[std::string("Left Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_find_elem_map[std::string("Right Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(2); |
| snd_mixer_find_elem_map[std::string("Left Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(3); |
| snd_mixer_find_elem_map[std::string("Right Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(4); |
| |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, |
| coupled_controls); |
| |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| |
| output_control = c->output_controls; |
| EXPECT_EQ(NULL, output_control->next); |
| c1 = output_control->elements; |
| c2 = c1->next; |
| c3 = c2->next; |
| c4 = c3->next; |
| EXPECT_EQ(c1->elem, reinterpret_cast<snd_mixer_elem_t*>(1)); |
| EXPECT_EQ(c2->elem, reinterpret_cast<snd_mixer_elem_t*>(2)); |
| EXPECT_EQ(c3->elem, reinterpret_cast<snd_mixer_elem_t*>(3)); |
| EXPECT_EQ(c4->elem, reinterpret_cast<snd_mixer_elem_t*>(4)); |
| EXPECT_EQ(c4->next, reinterpret_cast<mixer_control_element*>(NULL)); |
| EXPECT_EQ(c1->has_volume, 0); |
| EXPECT_EQ(c1->has_mute, 0); |
| EXPECT_EQ(c2->has_volume, 0); |
| EXPECT_EQ(c2->has_mute, 0); |
| EXPECT_EQ(c3->has_volume, 0); |
| EXPECT_EQ(c3->has_mute, 1); |
| EXPECT_EQ(c4->has_volume, 0); |
| EXPECT_EQ(c4->has_mute, 1); |
| |
| EXPECT_EQ(0, cras_alsa_mixer_has_volume(output_control)); |
| EXPECT_EQ(1, output_control->has_mute); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_name_free(coupled_controls); |
| } |
| |
| TEST(AlsaMixer, CoupledOutputHasVolumeNoMute) { |
| struct cras_alsa_mixer* c; |
| struct mixer_control* output_control; |
| struct mixer_control_element *c1, *c2, *c3, *c4; |
| |
| static const long min_volumes[] = {-70, -70}; |
| static const long max_volumes[] = {30, 30}; |
| |
| const char* coupled_output_names[] = {"Left Master", "Right Master", |
| "Left Speaker", "Right Speaker"}; |
| struct mixer_name* coupled_controls = mixer_name_add_array( |
| NULL, coupled_output_names, ARRAY_SIZE(coupled_output_names), |
| CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| int element_playback_volume[] = {1, 1, 0, 0}; |
| int element_playback_switches[] = {0, 0, 0, 0}; |
| |
| ResetStubData(); |
| |
| snd_mixer_find_elem_map[std::string("Left Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(1); |
| snd_mixer_find_elem_map[std::string("Right Master")] = |
| reinterpret_cast<snd_mixer_elem_t*>(2); |
| snd_mixer_find_elem_map[std::string("Left Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(3); |
| snd_mixer_find_elem_map[std::string("Right Speaker")] = |
| reinterpret_cast<snd_mixer_elem_t*>(4); |
| |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| |
| snd_mixer_selem_get_playback_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_playback_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_playback_dB_range_values_length = ARRAY_SIZE(min_volumes); |
| |
| c = create_mixer_and_add_controls_by_name_matching("hw:0", NULL, |
| coupled_controls); |
| |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), c); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| |
| output_control = c->output_controls; |
| EXPECT_EQ(NULL, output_control->next); |
| c1 = output_control->elements; |
| c2 = c1->next; |
| c3 = c2->next; |
| c4 = c3->next; |
| EXPECT_EQ(c1->elem, reinterpret_cast<snd_mixer_elem_t*>(1)); |
| EXPECT_EQ(c2->elem, reinterpret_cast<snd_mixer_elem_t*>(2)); |
| EXPECT_EQ(c3->elem, reinterpret_cast<snd_mixer_elem_t*>(3)); |
| EXPECT_EQ(c4->elem, reinterpret_cast<snd_mixer_elem_t*>(4)); |
| EXPECT_EQ(c4->next, reinterpret_cast<mixer_control_element*>(NULL)); |
| EXPECT_EQ(c1->has_volume, 1); |
| EXPECT_EQ(c1->has_mute, 0); |
| EXPECT_EQ(c2->has_volume, 1); |
| EXPECT_EQ(c2->has_mute, 0); |
| EXPECT_EQ(c3->has_volume, 0); |
| EXPECT_EQ(c3->has_mute, 0); |
| EXPECT_EQ(c4->has_volume, 0); |
| EXPECT_EQ(c4->has_mute, 0); |
| |
| EXPECT_EQ(1, cras_alsa_mixer_has_volume(output_control)); |
| EXPECT_EQ(0, output_control->has_mute); |
| |
| cras_alsa_mixer_destroy(c); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| mixer_name_free(coupled_controls); |
| } |
| |
| TEST(AlsaMixer, MixerName) { |
| struct mixer_name* names; |
| struct mixer_name* control; |
| size_t mixer_name_count; |
| static const char* element_names[] = { |
| "Master", "PCM", "Headphone", "Speaker", "HDMI", "IEC958", |
| }; |
| |
| names = mixer_name_add_array(NULL, element_names, ARRAY_SIZE(element_names), |
| CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| names = |
| mixer_name_add(names, "Playback", CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| names = |
| mixer_name_add(names, "Main", CRAS_STREAM_OUTPUT, MIXER_NAME_MAIN_VOLUME); |
| names = mixer_name_add(names, "Mic", CRAS_STREAM_INPUT, MIXER_NAME_VOLUME); |
| names = mixer_name_add(names, "Capture", CRAS_STREAM_INPUT, |
| MIXER_NAME_MAIN_VOLUME); |
| |
| /* Number of items (test mixer_name_add(_array)). */ |
| mixer_name_count = 0; |
| DL_FOREACH (names, control) { mixer_name_count++; } |
| EXPECT_EQ(10, mixer_name_count); |
| |
| /* Item not in the list: mismatch direction. */ |
| control = |
| mixer_name_find(names, "Main", CRAS_STREAM_INPUT, MIXER_NAME_UNDEFINED); |
| EXPECT_EQ(1, control == NULL); |
| |
| /* Item not in the list: mismatch type. */ |
| control = |
| mixer_name_find(names, "Main", CRAS_STREAM_OUTPUT, MIXER_NAME_VOLUME); |
| EXPECT_EQ(1, control == NULL); |
| |
| /* Find by name and direction. */ |
| control = |
| mixer_name_find(names, "Main", CRAS_STREAM_OUTPUT, MIXER_NAME_UNDEFINED); |
| EXPECT_EQ(0, strcmp("Main", control->name)); |
| |
| /* Find by type and direction. */ |
| control = mixer_name_find(names, NULL, CRAS_STREAM_INPUT, MIXER_NAME_VOLUME); |
| EXPECT_EQ(0, strcmp("Mic", control->name)); |
| |
| mixer_name_free(names); |
| } |
| |
| class AlsaMixerFullySpeced : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| callback_values_.clear(); |
| callback_called_ = 0; |
| static snd_mixer_elem_t* elements[] = { |
| reinterpret_cast<snd_mixer_elem_t*>(1), // HP-L |
| reinterpret_cast<snd_mixer_elem_t*>(2), // HP-R |
| reinterpret_cast<snd_mixer_elem_t*>(3), // SPK-L |
| reinterpret_cast<snd_mixer_elem_t*>(4), // SPK-R |
| reinterpret_cast<snd_mixer_elem_t*>(5), // HDMI |
| reinterpret_cast<snd_mixer_elem_t*>(6), // CAPTURE |
| reinterpret_cast<snd_mixer_elem_t*>(7), // MIC-L |
| reinterpret_cast<snd_mixer_elem_t*>(8), // MIC-R |
| reinterpret_cast<snd_mixer_elem_t*>(0), // Unknown |
| }; |
| static int element_playback_volume[] = { |
| 1, 1, 1, 1, 1, 0, 0, 0, |
| }; |
| static int element_playback_switches[] = { |
| 0, 0, 0, 0, 1, 0, 0, 0, |
| }; |
| static int element_capture_volume[] = { |
| 0, 0, 0, 0, 0, 0, 1, 1, |
| }; |
| static int element_capture_switches[] = { |
| 0, 0, 0, 0, 0, 1, 0, 0, |
| }; |
| static const long min_volumes[] = {-84, -84, -84, -84, -84, 0, 0, 0}; |
| static const long max_volumes[] = {0, 0, 0, 0, 0, 0, 84, 84}; |
| static const char* element_names[] = {"HP-L", "HP-R", "SPK-L", |
| "SPK-R", "HDMI", "CAPTURE", |
| "MIC-L", "MIC-R", "Unknown"}; |
| struct ucm_section* sections = NULL; |
| struct ucm_section* section; |
| size_t i; |
| |
| ResetStubData(); |
| |
| for (i = 0; i < ARRAY_SIZE(elements); i++) |
| snd_mixer_find_elem_map[element_names[i]] = elements[i]; |
| |
| section = ucm_section_create("NullElement", "hw:0,1", 0, -1, |
| CRAS_STREAM_OUTPUT, NULL, NULL); |
| ucm_section_set_mixer_name(section, "Unknown"); |
| DL_APPEND(sections, section); |
| section = |
| ucm_section_create("Headphone", "hw:0,1", 0, -1, CRAS_STREAM_OUTPUT, |
| "my-sound-card Headset Jack", "gpio"); |
| ucm_section_add_coupled(section, "HP-L", MIXER_NAME_VOLUME); |
| ucm_section_add_coupled(section, "HP-R", MIXER_NAME_VOLUME); |
| DL_APPEND(sections, section); |
| section = ucm_section_create("Speaker", "hw:0,1", 0, -1, CRAS_STREAM_OUTPUT, |
| NULL, NULL); |
| ucm_section_add_coupled(section, "SPK-L", MIXER_NAME_VOLUME); |
| ucm_section_add_coupled(section, "SPK-R", MIXER_NAME_VOLUME); |
| DL_APPEND(sections, section); |
| section = ucm_section_create("Mic", "hw:0,1", 0, -1, CRAS_STREAM_INPUT, |
| "my-sound-card Headset Jack", "gpio"); |
| ucm_section_set_mixer_name(section, "CAPTURE"); |
| DL_APPEND(sections, section); |
| section = ucm_section_create("Internal Mic", "hw:0,1", 0, -1, |
| CRAS_STREAM_INPUT, NULL, NULL); |
| ucm_section_add_coupled(section, "MIC-L", MIXER_NAME_VOLUME); |
| ucm_section_add_coupled(section, "MIC-R", MIXER_NAME_VOLUME); |
| DL_APPEND(sections, section); |
| section = ucm_section_create("HDMI", "hw:0,1", 0, -1, CRAS_STREAM_OUTPUT, |
| NULL, NULL); |
| ucm_section_set_mixer_name(section, "HDMI"); |
| DL_APPEND(sections, section); |
| ASSERT_NE(sections, (struct ucm_section*)NULL); |
| |
| snd_mixer_selem_has_playback_volume_return_values = element_playback_volume; |
| snd_mixer_selem_has_playback_volume_return_values_length = |
| ARRAY_SIZE(element_playback_volume); |
| snd_mixer_selem_has_playback_switch_return_values = |
| element_playback_switches; |
| snd_mixer_selem_has_playback_switch_return_values_length = |
| ARRAY_SIZE(element_playback_switches); |
| snd_mixer_selem_has_capture_volume_return_values = element_capture_volume; |
| snd_mixer_selem_has_capture_volume_return_values_length = |
| ARRAY_SIZE(element_capture_volume); |
| snd_mixer_selem_has_capture_switch_return_values = element_capture_switches; |
| snd_mixer_selem_has_capture_switch_return_values_length = |
| ARRAY_SIZE(element_capture_switches); |
| snd_mixer_selem_get_name_return_values = element_names; |
| snd_mixer_selem_get_name_return_values_length = ARRAY_SIZE(element_names); |
| snd_mixer_selem_get_capture_dB_range_min_values = min_volumes; |
| snd_mixer_selem_get_capture_dB_range_max_values = max_volumes; |
| snd_mixer_selem_get_capture_dB_range_values_length = |
| ARRAY_SIZE(min_volumes); |
| |
| cras_mixer_ = cras_alsa_mixer_create("hw:0"); |
| ASSERT_NE(static_cast<struct cras_alsa_mixer*>(NULL), cras_mixer_); |
| EXPECT_EQ(1, snd_mixer_open_called); |
| EXPECT_EQ(1, snd_mixer_attach_called); |
| EXPECT_EQ(0, strcmp(snd_mixer_attach_mixdev, "hw:0")); |
| EXPECT_EQ(1, snd_mixer_selem_register_called); |
| EXPECT_EQ(1, snd_mixer_load_called); |
| EXPECT_EQ(0, snd_mixer_close_called); |
| |
| section = sections; |
| EXPECT_EQ(-ENOENT, |
| cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| ASSERT_NE((struct ucm_section*)NULL, section->next); |
| section = section->next; |
| EXPECT_EQ(0, cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| ASSERT_NE((struct ucm_section*)NULL, section->next); |
| section = section->next; |
| EXPECT_EQ(0, cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| ASSERT_NE((struct ucm_section*)NULL, section->next); |
| section = section->next; |
| EXPECT_EQ(0, cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| ASSERT_NE((struct ucm_section*)NULL, section->next); |
| section = section->next; |
| EXPECT_EQ(0, cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| ASSERT_NE((struct ucm_section*)NULL, section->next); |
| section = section->next; |
| EXPECT_EQ(0, cras_alsa_mixer_add_controls_in_section(cras_mixer_, section)); |
| EXPECT_EQ(section->next, (struct ucm_section*)NULL); |
| |
| EXPECT_EQ(9, snd_mixer_find_selem_called); |
| EXPECT_EQ(5, snd_mixer_selem_has_playback_volume_called); |
| EXPECT_EQ(5, snd_mixer_selem_has_playback_switch_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_capture_volume_called); |
| EXPECT_EQ(3, snd_mixer_selem_has_capture_switch_called); |
| EXPECT_EQ(5, snd_mixer_selem_get_playback_dB_range_called); |
| EXPECT_EQ(2, snd_mixer_selem_get_capture_dB_range_called); |
| |
| sections_ = sections; |
| } |
| |
| virtual void TearDown() { |
| ucm_section_free_list(sections_); |
| cras_alsa_mixer_destroy(cras_mixer_); |
| EXPECT_EQ(1, snd_mixer_close_called); |
| } |
| |
| static void Callback(struct mixer_control* control, void* arg) { |
| callback_called_++; |
| callback_values_.push_back(control); |
| } |
| |
| struct cras_alsa_mixer* cras_mixer_; |
| static size_t callback_called_; |
| static std::vector<struct mixer_control*> callback_values_; |
| struct ucm_section* sections_; |
| }; |
| |
| size_t AlsaMixerFullySpeced::callback_called_; |
| std::vector<struct mixer_control*> AlsaMixerFullySpeced::callback_values_; |
| |
| TEST_F(AlsaMixerFullySpeced, CheckControlCounts) { |
| cras_alsa_mixer_list_outputs(cras_mixer_, AlsaMixerFullySpeced::Callback, |
| reinterpret_cast<void*>(555)); |
| EXPECT_EQ(3, callback_called_); |
| callback_called_ = 0; |
| cras_alsa_mixer_list_inputs(cras_mixer_, AlsaMixerFullySpeced::Callback, |
| reinterpret_cast<void*>(555)); |
| EXPECT_EQ(2, callback_called_); |
| } |
| |
| TEST_F(AlsaMixerFullySpeced, CheckFindOutputByNameNoMatch) { |
| struct mixer_control* out; |
| |
| out = cras_alsa_mixer_get_output_matching_name(cras_mixer_, "AAAAA Jack"); |
| EXPECT_EQ(static_cast<struct mixer_control*>(NULL), out); |
| } |
| |
| TEST_F(AlsaMixerFullySpeced, CheckFindOutputByName) { |
| struct mixer_control* out; |
| |
| out = cras_alsa_mixer_get_output_matching_name(cras_mixer_, "Headphone Jack"); |
| EXPECT_NE(static_cast<struct mixer_control*>(NULL), out); |
| } |
| |
| TEST_F(AlsaMixerFullySpeced, CheckFindControlForSection) { |
| struct mixer_control* control; |
| struct ucm_section* section = sections_; |
| |
| // Look for the control for the Headphone section. |
| // We've already asserted that section != NULL above. |
| // Matching the control created by CoupledMixers. |
| section = section->next; |
| control = cras_alsa_mixer_get_control_for_section(cras_mixer_, section); |
| ASSERT_NE(static_cast<struct mixer_control*>(NULL), control); |
| EXPECT_EQ(0, strcmp(control->name, "Headphone")); |
| |
| // Look for the control for the Mic section. |
| // Matching the control created by MixerName. |
| section = section->next->next; |
| control = cras_alsa_mixer_get_control_for_section(cras_mixer_, section); |
| ASSERT_NE(static_cast<struct mixer_control*>(NULL), control); |
| EXPECT_EQ(0, strcmp(control->name, "CAPTURE")); |
| } |
| |
| /* Stubs */ |
| |
| extern "C" { |
| int snd_mixer_open(snd_mixer_t** mixer, int mode) { |
| snd_mixer_open_called++; |
| *mixer = reinterpret_cast<snd_mixer_t*>(2); |
| return snd_mixer_open_return_value; |
| } |
| int snd_mixer_attach(snd_mixer_t* mixer, const char* name) { |
| snd_mixer_attach_called++; |
| snd_mixer_attach_mixdev = name; |
| return snd_mixer_attach_return_value; |
| } |
| int snd_mixer_selem_register(snd_mixer_t* mixer, |
| struct snd_mixer_selem_regopt* options, |
| snd_mixer_class_t** classp) { |
| snd_mixer_selem_register_called++; |
| return snd_mixer_selem_register_return_value; |
| } |
| int snd_mixer_load(snd_mixer_t* mixer) { |
| snd_mixer_load_called++; |
| return snd_mixer_load_return_value; |
| } |
| const char* snd_mixer_selem_get_name(snd_mixer_elem_t* elem) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_get_name_called++; |
| if (index >= snd_mixer_selem_get_name_return_values_length) |
| return static_cast<char*>(NULL); |
| |
| return snd_mixer_selem_get_name_return_values[index]; |
| } |
| unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t* elem) { |
| return 0; |
| } |
| int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t* elem) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_has_playback_volume_called++; |
| if (index >= snd_mixer_selem_has_playback_volume_return_values_length) |
| return -1; |
| |
| return snd_mixer_selem_has_playback_volume_return_values[index]; |
| } |
| int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t* elem) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_has_playback_switch_called++; |
| if (index >= snd_mixer_selem_has_playback_switch_return_values_length) |
| return -1; |
| |
| return snd_mixer_selem_has_playback_switch_return_values[index]; |
| } |
| int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t* elem) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_has_capture_volume_called++; |
| if (index >= snd_mixer_selem_has_capture_volume_return_values_length) |
| return -1; |
| |
| return snd_mixer_selem_has_capture_volume_return_values[index]; |
| } |
| int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t* elem) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_has_capture_switch_called++; |
| if (index >= snd_mixer_selem_has_capture_switch_return_values_length) |
| return -1; |
| |
| return snd_mixer_selem_has_capture_switch_return_values[index]; |
| } |
| snd_mixer_elem_t* snd_mixer_first_elem(snd_mixer_t* mixer) { |
| snd_mixer_first_elem_called++; |
| return snd_mixer_first_elem_return_value; |
| } |
| snd_mixer_elem_t* snd_mixer_elem_next(snd_mixer_elem_t* elem) { |
| snd_mixer_elem_next_called++; |
| if (snd_mixer_elem_next_return_values_index >= |
| snd_mixer_elem_next_return_values_length) |
| return static_cast<snd_mixer_elem_t*>(NULL); |
| |
| return snd_mixer_elem_next_return_values |
| [snd_mixer_elem_next_return_values_index++]; |
| } |
| int snd_mixer_close(snd_mixer_t* mixer) { |
| snd_mixer_close_called++; |
| return 0; |
| } |
| int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t* elem, |
| long value, |
| int dir) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_set_playback_dB_all_called++; |
| if (index < snd_mixer_selem_set_playback_dB_all_values_length) |
| snd_mixer_selem_set_playback_dB_all_values[index] = value; |
| return 0; |
| } |
| int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t* elem, |
| snd_mixer_selem_channel_id_t channel, |
| long* value) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_get_playback_dB_called++; |
| if (index >= snd_mixer_selem_get_playback_dB_return_values_length) |
| *value = 0; |
| else |
| *value = snd_mixer_selem_get_playback_dB_return_values[index]; |
| return 0; |
| } |
| int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t* elem, int value) { |
| snd_mixer_selem_set_playback_switch_all_called++; |
| snd_mixer_selem_set_playback_switch_all_value = value; |
| return 0; |
| } |
| int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t* elem, |
| long value, |
| int dir) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_set_capture_dB_all_called++; |
| if (index < snd_mixer_selem_set_capture_dB_all_values_length) |
| snd_mixer_selem_set_capture_dB_all_values[index] = value; |
| return 0; |
| } |
| int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t* elem, |
| snd_mixer_selem_channel_id_t channel, |
| long* value) { |
| int index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_get_capture_dB_called++; |
| if (index >= snd_mixer_selem_get_capture_dB_return_values_length) |
| *value = 0; |
| else |
| *value = snd_mixer_selem_get_capture_dB_return_values[index]; |
| return 0; |
| } |
| int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t* elem, int value) { |
| snd_mixer_selem_set_capture_switch_all_called++; |
| snd_mixer_selem_set_capture_switch_all_value = value; |
| return 0; |
| } |
| int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t* elem, |
| long* min, |
| long* max) { |
| size_t index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_get_capture_dB_range_called++; |
| if (index >= snd_mixer_selem_get_capture_dB_range_values_length) { |
| *min = 0; |
| *max = 0; |
| } else { |
| *min = snd_mixer_selem_get_capture_dB_range_min_values[index]; |
| *max = snd_mixer_selem_get_capture_dB_range_max_values[index]; |
| } |
| return 0; |
| } |
| int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t* elem, |
| long* min, |
| long* max) { |
| size_t index = reinterpret_cast<size_t>(elem) - 1; |
| snd_mixer_selem_get_playback_dB_range_called++; |
| if (index >= snd_mixer_selem_get_playback_dB_range_values_length) { |
| *min = 0; |
| *max = 0; |
| } else { |
| *min = snd_mixer_selem_get_playback_dB_range_min_values[index]; |
| *max = snd_mixer_selem_get_playback_dB_range_max_values[index]; |
| } |
| return 0; |
| } |
| |
| snd_mixer_elem_t* snd_mixer_find_selem(snd_mixer_t* mixer, |
| const snd_mixer_selem_id_t* id) { |
| std::string name(snd_mixer_selem_id_get_name(id)); |
| unsigned int index = snd_mixer_selem_id_get_index(id); |
| snd_mixer_find_selem_called++; |
| if (index != 0) |
| return NULL; |
| if (snd_mixer_find_elem_map.find(name) == snd_mixer_find_elem_map.end()) { |
| return NULL; |
| } |
| return snd_mixer_find_elem_map[name]; |
| } |
| |
| // From cras_volume_curve. |
| static long get_dBFS_default(const struct cras_volume_curve* curve, |
| size_t volume) { |
| return 100 * (volume - 100); |
| } |
| |
| struct cras_volume_curve* cras_volume_curve_create_default() { |
| struct cras_volume_curve* curve; |
| curve = (struct cras_volume_curve*)calloc(1, sizeof(*curve)); |
| if (curve) |
| curve->get_dBFS = get_dBFS_default; |
| return curve; |
| } |
| |
| void cras_volume_curve_destroy(struct cras_volume_curve* curve) { |
| cras_volume_curve_destroy_called++; |
| free(curve); |
| } |
| |
| // From libiniparser. |
| struct cras_volume_curve* cras_card_config_get_volume_curve_for_control( |
| const struct cras_card_config* card_config, |
| const char* control_name) { |
| struct cras_volume_curve* curve; |
| curve = (struct cras_volume_curve*)calloc(1, sizeof(*curve)); |
| if (curve != NULL) |
| curve->get_dBFS = get_dBFS_default; |
| return curve; |
| } |
| |
| } /* extern "C" */ |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| openlog(NULL, LOG_PERROR, LOG_USER); |
| return RUN_ALL_TESTS(); |
| } |