blob: b3db9de5f5eeca1421bd2f196efc3ce0e102fbbf [file] [log] [blame]
// 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();
}