| // 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 <vector> |
| |
| extern "C" { |
| |
| #include "cras_alsa_mixer.h" |
| #include "cras_iodev.h" |
| #include "cras_shm.h" |
| #include "cras_system_state.h" |
| #include "cras_types.h" |
| |
| // Include C file to test static functions. |
| #include "cras_alsa_io.c" |
| } |
| |
| #define BUFFER_SIZE 8192 |
| |
| // Data for simulating functions stubbed below. |
| static int cras_alsa_open_called; |
| static int cras_iodev_append_stream_ret; |
| static int cras_alsa_get_avail_frames_ret; |
| static int cras_alsa_get_avail_frames_avail; |
| static int cras_alsa_start_called; |
| static uint8_t* cras_alsa_mmap_begin_buffer; |
| static size_t cras_alsa_mmap_begin_frames; |
| static size_t cras_alsa_fill_properties_called; |
| static bool cras_alsa_support_8_channels; |
| static size_t alsa_mixer_set_dBFS_called; |
| static int alsa_mixer_set_dBFS_value; |
| static const struct mixer_control* alsa_mixer_set_dBFS_output; |
| static size_t alsa_mixer_set_capture_dBFS_called; |
| static int alsa_mixer_set_capture_dBFS_value; |
| static const struct mixer_control* alsa_mixer_set_capture_dBFS_input; |
| static const struct mixer_control* |
| cras_alsa_mixer_get_minimum_capture_gain_mixer_input; |
| static const struct mixer_control* |
| cras_alsa_mixer_get_maximum_capture_gain_mixer_input; |
| static size_t cras_alsa_mixer_list_outputs_called; |
| static size_t cras_alsa_mixer_list_inputs_called; |
| static size_t cras_alsa_mixer_get_control_for_section_called; |
| static struct mixer_control* |
| cras_alsa_mixer_get_control_for_section_return_value; |
| static size_t sys_get_volume_called; |
| static size_t sys_get_volume_return_value; |
| static size_t alsa_mixer_set_mute_called; |
| static int alsa_mixer_set_mute_value; |
| static size_t alsa_mixer_get_dB_range_called; |
| static long alsa_mixer_get_dB_range_value; |
| static size_t alsa_mixer_get_output_dB_range_called; |
| static long alsa_mixer_get_output_dB_range_value; |
| static const struct mixer_control* alsa_mixer_set_mute_output; |
| static size_t alsa_mixer_set_capture_mute_called; |
| static int alsa_mixer_set_capture_mute_value; |
| static const struct mixer_control* alsa_mixer_set_capture_mute_input; |
| static size_t sys_get_mute_called; |
| static int sys_get_mute_return_value; |
| static size_t sys_get_capture_mute_called; |
| static int sys_get_capture_mute_return_value; |
| static struct cras_alsa_mixer* fake_mixer = (struct cras_alsa_mixer*)1; |
| static struct cras_card_config* fake_config = (struct cras_card_config*)2; |
| static struct mixer_control** cras_alsa_mixer_list_outputs_outputs; |
| static size_t cras_alsa_mixer_list_outputs_outputs_length; |
| static struct mixer_control** cras_alsa_mixer_list_inputs_outputs; |
| static size_t cras_alsa_mixer_list_inputs_outputs_length; |
| static size_t cras_alsa_mixer_set_output_active_state_called; |
| static std::vector<struct mixer_control*> |
| cras_alsa_mixer_set_output_active_state_outputs; |
| static std::vector<int> cras_alsa_mixer_set_output_active_state_values; |
| static cras_audio_format* fake_format; |
| static size_t sys_set_volume_limits_called; |
| static size_t cras_alsa_mixer_get_minimum_capture_gain_called; |
| static size_t cras_alsa_mixer_get_maximum_capture_gain_called; |
| static struct mixer_control* cras_alsa_jack_get_mixer_output_ret; |
| static struct mixer_control* cras_alsa_jack_get_mixer_input_ret; |
| static size_t cras_alsa_mixer_get_output_volume_curve_called; |
| typedef std::map<const struct mixer_control*, std::string> ControlNameMap; |
| static ControlNameMap cras_alsa_mixer_get_control_name_values; |
| static size_t cras_alsa_mixer_get_control_name_called; |
| static size_t cras_alsa_jack_list_create_called; |
| static size_t cras_alsa_jack_list_find_jacks_by_name_matching_called; |
| static size_t cras_alsa_jack_list_add_jack_for_section_called; |
| static struct cras_alsa_jack* |
| cras_alsa_jack_list_add_jack_for_section_result_jack; |
| static size_t cras_alsa_jack_list_destroy_called; |
| static int cras_alsa_jack_list_has_hctl_jacks_return_val; |
| static jack_state_change_callback* cras_alsa_jack_list_create_cb; |
| static void* cras_alsa_jack_list_create_cb_data; |
| static char test_card_name[] = "TestCard"; |
| static char test_pcm_name[] = "TestPCM"; |
| static char test_dev_name[] = "TestDev"; |
| static char test_dev_id[] = "TestDevId"; |
| static size_t cras_iodev_add_node_called; |
| static struct cras_ionode* cras_iodev_set_node_plugged_ionode; |
| static size_t cras_iodev_set_node_plugged_called; |
| static int cras_iodev_set_node_plugged_value; |
| static unsigned cras_alsa_jack_enable_ucm_called; |
| static unsigned ucm_set_enabled_called; |
| static size_t cras_iodev_update_dsp_called; |
| static const char* cras_iodev_update_dsp_name; |
| typedef std::map<const char*, std::string> DspNameMap; |
| static size_t ucm_get_dsp_name_for_dev_called; |
| static DspNameMap ucm_get_dsp_name_for_dev_values; |
| static size_t cras_iodev_free_resources_called; |
| static size_t cras_alsa_jack_update_node_type_called; |
| static int ucm_swap_mode_exists_ret_value; |
| static int ucm_enable_swap_mode_ret_value; |
| static size_t ucm_enable_swap_mode_called; |
| static int is_utf8_string_ret_value; |
| static const char* cras_alsa_jack_update_monitor_fake_name = 0; |
| static int cras_alsa_jack_get_name_called; |
| static const char* cras_alsa_jack_get_name_ret_value = 0; |
| static char default_jack_name[] = "Something Jack"; |
| static int auto_unplug_input_node_ret = 0; |
| static int auto_unplug_output_node_ret = 0; |
| static long cras_alsa_mixer_get_minimum_capture_gain_ret_value; |
| static long cras_alsa_mixer_get_maximum_capture_gain_ret_value; |
| static snd_pcm_state_t snd_pcm_state_ret; |
| static int cras_alsa_attempt_resume_called; |
| static snd_hctl_t* fake_hctl = (snd_hctl_t*)2; |
| static size_t ucm_get_dma_period_for_dev_called; |
| static unsigned int ucm_get_dma_period_for_dev_ret; |
| static int cras_card_config_get_volume_curve_for_control_called; |
| typedef std::map<std::string, struct cras_volume_curve*> VolCurveMap; |
| static VolCurveMap cras_card_config_get_volume_curve_vals; |
| static int cras_alsa_mmap_get_whole_buffer_called; |
| static int cras_iodev_fill_odev_zeros_called; |
| static unsigned int cras_iodev_fill_odev_zeros_frames; |
| static int cras_iodev_frames_queued_ret; |
| static int cras_iodev_buffer_avail_ret; |
| static int cras_alsa_resume_appl_ptr_called; |
| static int cras_alsa_resume_appl_ptr_ahead; |
| static const struct cras_volume_curve* fake_get_dBFS_volume_curve_val; |
| static int cras_iodev_dsp_set_swap_mode_for_node_called; |
| static std::map<std::string, long> ucm_get_default_node_gain_values; |
| static std::map<std::string, long> ucm_get_intrinsic_sensitivity_values; |
| static thread_callback audio_thread_cb; |
| static void* audio_thread_cb_data; |
| static int hotword_send_triggered_msg_called; |
| static struct timespec clock_gettime_retspec; |
| static unsigned cras_iodev_reset_rate_estimator_called; |
| |
| void ResetStubData() { |
| cras_alsa_open_called = 0; |
| cras_iodev_append_stream_ret = 0; |
| cras_alsa_get_avail_frames_ret = 0; |
| cras_alsa_get_avail_frames_avail = 0; |
| cras_alsa_start_called = 0; |
| cras_alsa_fill_properties_called = 0; |
| cras_alsa_support_8_channels = false; |
| sys_get_volume_called = 0; |
| alsa_mixer_set_dBFS_called = 0; |
| alsa_mixer_set_capture_dBFS_called = 0; |
| sys_get_mute_called = 0; |
| sys_get_capture_mute_called = 0; |
| alsa_mixer_set_mute_called = 0; |
| alsa_mixer_get_dB_range_called = 0; |
| alsa_mixer_get_output_dB_range_called = 0; |
| alsa_mixer_set_capture_mute_called = 0; |
| cras_alsa_mixer_get_control_for_section_called = 0; |
| cras_alsa_mixer_get_control_for_section_return_value = NULL; |
| cras_alsa_mixer_list_outputs_called = 0; |
| cras_alsa_mixer_list_outputs_outputs_length = 0; |
| cras_alsa_mixer_list_inputs_called = 0; |
| cras_alsa_mixer_list_inputs_outputs_length = 0; |
| cras_alsa_mixer_set_output_active_state_called = 0; |
| cras_alsa_mixer_set_output_active_state_outputs.clear(); |
| cras_alsa_mixer_set_output_active_state_values.clear(); |
| sys_set_volume_limits_called = 0; |
| cras_alsa_mixer_get_minimum_capture_gain_called = 0; |
| cras_alsa_mixer_get_maximum_capture_gain_called = 0; |
| cras_alsa_mixer_get_output_volume_curve_called = 0; |
| cras_alsa_jack_get_mixer_output_ret = NULL; |
| cras_alsa_jack_get_mixer_input_ret = NULL; |
| cras_alsa_mixer_get_control_name_values.clear(); |
| cras_alsa_mixer_get_control_name_called = 0; |
| cras_alsa_jack_list_create_called = 0; |
| cras_alsa_jack_list_find_jacks_by_name_matching_called = 0; |
| cras_alsa_jack_list_add_jack_for_section_called = 0; |
| cras_alsa_jack_list_add_jack_for_section_result_jack = NULL; |
| cras_alsa_jack_list_destroy_called = 0; |
| cras_alsa_jack_list_has_hctl_jacks_return_val = 1; |
| cras_iodev_add_node_called = 0; |
| cras_iodev_set_node_plugged_called = 0; |
| cras_alsa_jack_enable_ucm_called = 0; |
| ucm_set_enabled_called = 0; |
| cras_iodev_update_dsp_called = 0; |
| cras_iodev_update_dsp_name = 0; |
| ucm_get_dsp_name_for_dev_called = 0; |
| ucm_get_dsp_name_for_dev_values.clear(); |
| cras_iodev_free_resources_called = 0; |
| cras_alsa_jack_update_node_type_called = 0; |
| ucm_swap_mode_exists_ret_value = 0; |
| ucm_enable_swap_mode_ret_value = 0; |
| ucm_enable_swap_mode_called = 0; |
| is_utf8_string_ret_value = 1; |
| cras_alsa_jack_get_name_called = 0; |
| cras_alsa_jack_get_name_ret_value = default_jack_name; |
| cras_alsa_jack_update_monitor_fake_name = 0; |
| cras_card_config_get_volume_curve_for_control_called = 0; |
| cras_card_config_get_volume_curve_vals.clear(); |
| cras_alsa_mixer_get_minimum_capture_gain_ret_value = 0; |
| cras_alsa_mixer_get_maximum_capture_gain_ret_value = 0; |
| snd_pcm_state_ret = SND_PCM_STATE_RUNNING; |
| cras_alsa_attempt_resume_called = 0; |
| ucm_get_dma_period_for_dev_called = 0; |
| ucm_get_dma_period_for_dev_ret = 0; |
| cras_alsa_mmap_get_whole_buffer_called = 0; |
| cras_iodev_fill_odev_zeros_called = 0; |
| cras_iodev_fill_odev_zeros_frames = 0; |
| cras_iodev_frames_queued_ret = 0; |
| cras_iodev_buffer_avail_ret = 0; |
| cras_alsa_resume_appl_ptr_called = 0; |
| cras_alsa_resume_appl_ptr_ahead = 0; |
| fake_get_dBFS_volume_curve_val = NULL; |
| cras_iodev_dsp_set_swap_mode_for_node_called = 0; |
| ucm_get_default_node_gain_values.clear(); |
| ucm_get_intrinsic_sensitivity_values.clear(); |
| cras_iodev_reset_rate_estimator_called = 0; |
| } |
| |
| static long fake_get_dBFS(const struct cras_volume_curve* curve, |
| size_t volume) { |
| fake_get_dBFS_volume_curve_val = curve; |
| return (volume - 100) * 100; |
| } |
| static cras_volume_curve default_curve = { |
| .get_dBFS = fake_get_dBFS, |
| }; |
| |
| static struct cras_iodev* alsa_iodev_create_with_default_parameters( |
| size_t card_index, |
| const char* dev_id, |
| enum CRAS_ALSA_CARD_TYPE card_type, |
| int is_first, |
| struct cras_alsa_mixer* mixer, |
| struct cras_card_config* config, |
| struct cras_use_case_mgr* ucm, |
| enum CRAS_STREAM_DIRECTION direction) { |
| return alsa_iodev_create(card_index, test_card_name, 0, test_pcm_name, |
| test_dev_name, dev_id, card_type, is_first, mixer, |
| config, ucm, fake_hctl, direction, 0, 0, |
| (char*)"123"); |
| } |
| |
| namespace { |
| TEST(AlsaIoInit, InitializeInvalidDirection) { |
| struct alsa_io* aio; |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_NUM_DIRECTIONS); |
| ASSERT_EQ(aio, (void*)NULL); |
| } |
| |
| TEST(AlsaIoInit, InitializePlayback) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, test_dev_id, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| /* Get volume curve twice for iodev, and default node. */ |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called); |
| EXPECT_EQ( |
| 0, strncmp(test_card_name, aio->base.info.name, strlen(test_card_name))); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ("", cras_iodev_update_dsp_name); |
| ASSERT_NE(reinterpret_cast<const char*>(NULL), aio->dev_name); |
| EXPECT_EQ(0, strcmp(test_dev_name, aio->dev_name)); |
| ASSERT_NE(reinterpret_cast<const char*>(NULL), aio->dev_id); |
| EXPECT_EQ(0, strcmp(test_dev_id, aio->dev_id)); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| EXPECT_EQ(1, cras_iodev_free_resources_called); |
| } |
| |
| TEST(AlsaIoInit, DefaultNodeInternalCard) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(DEFAULT, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| ASSERT_EQ((void*)no_stream, (void*)aio->base.no_stream); |
| ASSERT_EQ((void*)is_free_running, (void*)aio->base.is_free_running); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(INTERNAL_SPEAKER, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| ASSERT_EQ((void*)no_stream, (void*)aio->base.no_stream); |
| ASSERT_EQ((void*)is_free_running, (void*)aio->base.is_free_running); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| /* No more call to get volume curve for input device. */ |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(DEFAULT, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| ASSERT_EQ((void*)no_stream, (void*)aio->base.no_stream); |
| ASSERT_EQ((void*)is_free_running, (void*)aio->base.is_free_running); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(INTERNAL_MICROPHONE, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| ASSERT_EQ((void*)no_stream, (void*)aio->base.no_stream); |
| ASSERT_EQ((void*)is_free_running, (void*)aio->base.is_free_running); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, DefaultNodeUSBCard) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(DEFAULT, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_USB, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| ASSERT_STREQ(DEFAULT, aio->base.active_node->name); |
| ASSERT_EQ(1, aio->base.active_node->plugged); |
| EXPECT_EQ(2, cras_iodev_set_node_plugged_called); |
| |
| /* No extra gain applied. */ |
| ASSERT_EQ(DEFAULT_CAPTURE_VOLUME_DBFS, |
| aio->base.active_node->intrinsic_sensitivity); |
| ASSERT_EQ(0, aio->base.active_node->capture_gain); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, OpenPlayback) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| struct alsa_io* aio; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| /* Call open_dev once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_open_called); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| aio = (struct alsa_io*)iodev; |
| format.frame_rate = 48000; |
| format.num_channels = 1; |
| cras_iodev_set_format(iodev, &format); |
| |
| // Test that these flags are cleared after open_dev. |
| aio->free_running = 1; |
| aio->filled_zeros_for_draining = 512; |
| iodev->open_dev(iodev); |
| EXPECT_EQ(2, cras_alsa_open_called); |
| iodev->configure_dev(iodev); |
| EXPECT_EQ(2, cras_alsa_open_called); |
| EXPECT_EQ(1, sys_set_volume_limits_called); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(0, cras_alsa_start_called); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(0, aio->free_running); |
| EXPECT_EQ(0, aio->filled_zeros_for_draining); |
| EXPECT_EQ(SEVERE_UNDERRUN_MS * format.frame_rate / 1000, |
| aio->severe_underrun_frames); |
| |
| alsa_iodev_destroy(iodev); |
| free(fake_format); |
| } |
| |
| TEST(AlsaIoInit, UsbCardAutoPlug) { |
| struct cras_iodev* iodev; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_called); |
| alsa_iodev_destroy(iodev); |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB, |
| 0, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_called); |
| alsa_iodev_destroy(iodev); |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB, |
| 1, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| // Should assume USB devs are plugged when they appear. |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(1, iodev->active_node->plugged); |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, UsbCardUseSoftwareVolume) { |
| struct cras_iodev* iodev; |
| |
| alsa_mixer_get_dB_range_value = 1000; |
| alsa_mixer_get_output_dB_range_value = 1000; |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB, |
| 1, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(1, alsa_mixer_get_dB_range_called); |
| EXPECT_EQ(1, alsa_mixer_get_output_dB_range_called); |
| EXPECT_EQ(1, iodev->active_node->software_volume_needed); |
| alsa_iodev_destroy(iodev); |
| |
| alsa_mixer_get_dB_range_value = 3000; |
| alsa_mixer_get_output_dB_range_value = 2000; |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB, |
| 1, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(1, alsa_mixer_get_dB_range_called); |
| EXPECT_EQ(1, alsa_mixer_get_output_dB_range_called); |
| EXPECT_EQ(0, iodev->active_node->software_volume_needed); |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, SoftwareGainIntrinsicSensitivity) { |
| struct cras_iodev* iodev; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| long intrinsic_sensitivity = -2700; |
| |
| ResetStubData(); |
| |
| // Set intrinsic sensitivity to -2700 * 0.01 dBFS/Pa. |
| ucm_get_intrinsic_sensitivity_values[INTERNAL_MICROPHONE] = |
| intrinsic_sensitivity; |
| |
| // Assume this is the first device so it gets internal mic node name. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| ASSERT_EQ(intrinsic_sensitivity, iodev->active_node->intrinsic_sensitivity); |
| ASSERT_EQ(DEFAULT_CAPTURE_VOLUME_DBFS - intrinsic_sensitivity, |
| iodev->active_node->capture_gain); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, RouteBasedOnJackCallback) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(aio, (void*)NULL); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_create_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_find_jacks_by_name_matching_called); |
| EXPECT_EQ(0, cras_alsa_jack_list_add_jack_for_section_called); |
| |
| cras_alsa_jack_list_create_cb(NULL, 1, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_value); |
| cras_alsa_jack_list_create_cb(NULL, 0, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(2, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_value); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| EXPECT_EQ(1, cras_alsa_jack_list_destroy_called); |
| } |
| |
| TEST(AlsaIoInit, RouteBasedOnInputJackCallback) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(aio, (void*)NULL); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_create_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_find_jacks_by_name_matching_called); |
| EXPECT_EQ(0, cras_alsa_jack_list_add_jack_for_section_called); |
| |
| cras_alsa_jack_list_create_cb(NULL, 1, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_value); |
| cras_alsa_jack_list_create_cb(NULL, 0, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(2, cras_iodev_set_node_plugged_called); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_value); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| EXPECT_EQ(1, cras_alsa_jack_list_destroy_called); |
| } |
| |
| TEST(AlsaIoInit, InitializeCapture) { |
| struct alsa_io* aio; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(aio, (void*)NULL); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| EXPECT_EQ(1, cras_alsa_mixer_list_inputs_called); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, OpenCapture) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| struct alsa_io* aio; |
| |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| |
| aio = (struct alsa_io*)iodev; |
| format.frame_rate = 48000; |
| format.num_channels = 1; |
| cras_iodev_set_format(iodev, &format); |
| |
| ResetStubData(); |
| iodev->open_dev(iodev); |
| EXPECT_EQ(1, cras_alsa_open_called); |
| iodev->configure_dev(iodev); |
| EXPECT_EQ(1, cras_alsa_open_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_minimum_capture_gain_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_maximum_capture_gain_called); |
| EXPECT_EQ(1, alsa_mixer_set_capture_dBFS_called); |
| EXPECT_EQ(1, sys_get_capture_mute_called); |
| EXPECT_EQ(1, alsa_mixer_set_capture_mute_called); |
| EXPECT_EQ(1, cras_alsa_start_called); |
| EXPECT_EQ(SEVERE_UNDERRUN_MS * format.frame_rate / 1000, |
| aio->severe_underrun_frames); |
| |
| alsa_iodev_destroy(iodev); |
| free(fake_format); |
| } |
| |
| TEST(AlsaIoInit, OpenCaptureSetCaptureGainWithDefaultNodeGain) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| long default_node_gain = 1000; |
| |
| ResetStubData(); |
| // Set default node gain to -1000 * 0.01 dB. |
| ucm_get_default_node_gain_values[INTERNAL_MICROPHONE] = default_node_gain; |
| |
| // Assume this is the first device so it gets internal mic node name. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| |
| cras_iodev_set_format(iodev, &format); |
| |
| // Check the default node gain is the same as what specified in UCM. |
| EXPECT_EQ(default_node_gain, iodev->active_node->capture_gain); |
| cras_alsa_mixer_get_minimum_capture_gain_ret_value = 0; |
| cras_alsa_mixer_get_maximum_capture_gain_ret_value = 2000; |
| |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| // Hardware gain is in the hardware gain range and set to 1000 * 0.01 dB. |
| EXPECT_EQ(default_node_gain, alsa_mixer_set_capture_dBFS_value); |
| |
| // Check we do respect the hardware maximum capture gain. |
| cras_alsa_mixer_get_maximum_capture_gain_ret_value = 500; |
| |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| EXPECT_EQ(500, alsa_mixer_set_capture_dBFS_value); |
| |
| alsa_iodev_destroy(iodev); |
| free(fake_format); |
| } |
| |
| TEST(AlsaIoInit, OpenCaptureSetCaptureGainWithSoftwareGain) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| |
| /* Meet the requirements of using software gain. */ |
| ResetStubData(); |
| |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| |
| format.frame_rate = 48000; |
| format.num_channels = 1; |
| cras_iodev_set_format(iodev, &format); |
| |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| /* Hardware gain is set to 0dB when software gain is used. */ |
| EXPECT_EQ(0, alsa_mixer_set_capture_dBFS_value); |
| |
| /* Test the case where software gain is not needed. */ |
| iodev->active_node->software_volume_needed = 0; |
| iodev->active_node->capture_gain = 1000; |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| /* Hardware gain is set to 1000 * 0.01 dB as got from catpure_gain.*/ |
| EXPECT_EQ(0, alsa_mixer_set_capture_dBFS_value); |
| |
| alsa_iodev_destroy(iodev); |
| free(fake_format); |
| } |
| |
| TEST(AlsaIoInit, OpenCaptureSetCaptureGainWithDefaultUsbDevice) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| |
| iodev = alsa_iodev_create_with_default_parameters(0, NULL, ALSA_CARD_TYPE_USB, |
| 0, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| |
| format.frame_rate = 48000; |
| format.num_channels = 1; |
| cras_iodev_set_format(iodev, &format); |
| |
| iodev->active_node->intrinsic_sensitivity = DEFAULT_CAPTURE_VOLUME_DBFS; |
| iodev->active_node->capture_gain = 0; |
| |
| ResetStubData(); |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| |
| EXPECT_EQ(1, sys_get_capture_mute_called); |
| EXPECT_EQ(1, alsa_mixer_set_capture_mute_called); |
| |
| /* Not change mixer controls for USB devices without UCM config. */ |
| EXPECT_EQ(0, alsa_mixer_set_capture_dBFS_called); |
| |
| alsa_iodev_destroy(iodev); |
| free(fake_format); |
| } |
| |
| TEST(AlsaIoInit, UpdateActiveNode) { |
| struct cras_iodev* iodev; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| |
| iodev->update_active_node(iodev, 0, 1); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, StartDevice) { |
| struct cras_iodev* iodev; |
| int rc; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, NULL, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Return right away if it is already running. |
| snd_pcm_state_ret = SND_PCM_STATE_RUNNING; |
| rc = iodev->start(iodev); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(0, cras_alsa_start_called); |
| |
| // Otherwise, start the device. |
| snd_pcm_state_ret = SND_PCM_STATE_SETUP; |
| rc = iodev->start(iodev); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_start_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, ResumeDevice) { |
| struct cras_iodev* iodev; |
| int rc; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, NULL, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init(iodev)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Attempt to resume if the device is suspended. |
| snd_pcm_state_ret = SND_PCM_STATE_SUSPENDED; |
| rc = iodev->start(iodev); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_attempt_resume_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, DspNameDefault) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(1, ucm_get_dsp_name_for_dev_called); |
| EXPECT_STREQ("", cras_iodev_update_dsp_name); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, DspName) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| |
| ResetStubData(); |
| ucm_get_dsp_name_for_dev_values[DEFAULT] = "hello"; |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(1, ucm_get_dsp_name_for_dev_called); |
| EXPECT_STREQ("hello", cras_iodev_update_dsp_name); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, DspNameJackOverride) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| const struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| static const char* jack_name = "jack"; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(1, ucm_get_dsp_name_for_dev_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_STREQ("", cras_iodev_update_dsp_name); |
| |
| cras_alsa_jack_get_name_ret_value = jack_name; |
| ucm_get_dsp_name_for_dev_values[jack_name] = "override_dsp"; |
| // Add the jack node. |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(2, cras_alsa_jack_get_name_called); |
| EXPECT_EQ(2, ucm_get_dsp_name_for_dev_called); |
| |
| // Mark the jack node as active. |
| alsa_iodev_set_active_node(&aio->base, aio->base.nodes->next, 1); |
| EXPECT_EQ(2, ucm_get_dsp_name_for_dev_called); |
| EXPECT_EQ(2, cras_iodev_update_dsp_called); |
| EXPECT_STREQ("override_dsp", cras_iodev_update_dsp_name); |
| |
| // Mark the default node as active. |
| alsa_iodev_set_active_node(&aio->base, aio->base.nodes, 1); |
| EXPECT_EQ(2, ucm_get_dsp_name_for_dev_called); |
| EXPECT_EQ(3, cras_iodev_update_dsp_called); |
| EXPECT_STREQ("", cras_iodev_update_dsp_name); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, NodeTypeOverride) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| const struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| // Add the jack node. |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| // Verify that cras_alsa_jack_update_node_type is called when an output device |
| // is created. |
| EXPECT_EQ(1, cras_alsa_jack_update_node_type_called); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaIoInit, SwapMode) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_ionode* const fake_node = |
| (cras_ionode*)calloc(1, sizeof(struct cras_ionode)); |
| ResetStubData(); |
| // Stub replies that swap mode does not exist. |
| ucm_swap_mode_exists_ret_value = 0; |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| |
| aio->base.set_swap_mode_for_node((cras_iodev*)aio, fake_node, 1); |
| /* Swap mode is implemented by dsp. */ |
| EXPECT_EQ(1, cras_iodev_dsp_set_swap_mode_for_node_called); |
| |
| // Stub replies that swap mode exists. |
| ucm_swap_mode_exists_ret_value = 1; |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| // Enable swap mode. |
| aio->base.set_swap_mode_for_node((cras_iodev*)aio, fake_node, 1); |
| |
| // Verify that ucm_enable_swap_mode is called when callback to enable |
| // swap mode is called. |
| EXPECT_EQ(1, ucm_enable_swap_mode_called); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| free(fake_node); |
| } |
| |
| TEST(AlsaIoInit, MaxSupportedChannels) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| int i; |
| |
| // i = 0: cras_alsa_support_8_channels is false, support 2 channels only. |
| // i = 1: cras_alsa_support_8_channels is true, support up to 8 channels. |
| for (i = 0; i < 2; i++) { |
| ResetStubData(); |
| cras_alsa_support_8_channels = (bool)i; |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, test_dev_id, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, |
| NULL, CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| uint32_t max_channels = (cras_alsa_support_8_channels) ? 8 : 2; |
| EXPECT_EQ(max_channels, aio->base.info.max_supported_channels); |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| EXPECT_EQ(1, cras_iodev_free_resources_called); |
| } |
| } |
| |
| // Test that system settins aren't touched if no streams active. |
| TEST(AlsaOutputNode, SystemSettingsWhenInactive) { |
| int rc; |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct mixer_control* outputs[2]; |
| |
| ResetStubData(); |
| outputs[0] = reinterpret_cast<struct mixer_control*>(3); |
| outputs[1] = reinterpret_cast<struct mixer_control*>(4); |
| cras_alsa_mixer_list_outputs_outputs = outputs; |
| cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| /* Two mixer controls calls get volume curve. */ |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called); |
| |
| ResetStubData(); |
| rc = alsa_iodev_set_active_node((struct cras_iodev*)aio, |
| aio->base.nodes->next, 1); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(0, alsa_mixer_set_mute_called); |
| EXPECT_EQ(0, alsa_mixer_set_dBFS_called); |
| ASSERT_EQ(2, cras_alsa_mixer_set_output_active_state_called); |
| EXPECT_EQ(outputs[0], cras_alsa_mixer_set_output_active_state_outputs[0]); |
| EXPECT_EQ(0, cras_alsa_mixer_set_output_active_state_values[0]); |
| EXPECT_EQ(outputs[1], cras_alsa_mixer_set_output_active_state_outputs[1]); |
| EXPECT_EQ(1, cras_alsa_mixer_set_output_active_state_values[1]); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| // No jack is defined, and UCM is not used. |
| EXPECT_EQ(0, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(0, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| // Test handling of different amounts of outputs. |
| TEST(AlsaOutputNode, TwoOutputs) { |
| int rc; |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct mixer_control* outputs[2]; |
| |
| ResetStubData(); |
| outputs[0] = reinterpret_cast<struct mixer_control*>(3); |
| outputs[1] = reinterpret_cast<struct mixer_control*>(4); |
| cras_alsa_mixer_list_outputs_outputs = outputs; |
| cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called); |
| |
| aio->handle = (snd_pcm_t*)0x24; |
| |
| ResetStubData(); |
| rc = alsa_iodev_set_active_node((struct cras_iodev*)aio, |
| aio->base.nodes->next, 1); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, alsa_mixer_set_mute_called); |
| EXPECT_EQ(outputs[1], alsa_mixer_set_mute_output); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(outputs[1], alsa_mixer_set_dBFS_output); |
| ASSERT_EQ(2, cras_alsa_mixer_set_output_active_state_called); |
| EXPECT_EQ(outputs[0], cras_alsa_mixer_set_output_active_state_outputs[0]); |
| EXPECT_EQ(0, cras_alsa_mixer_set_output_active_state_values[0]); |
| EXPECT_EQ(outputs[1], cras_alsa_mixer_set_output_active_state_outputs[1]); |
| EXPECT_EQ(1, cras_alsa_mixer_set_output_active_state_values[1]); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| // No jacks defined, and UCM is not used. |
| EXPECT_EQ(0, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(0, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaOutputNode, TwoJacksHeadphoneLineout) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| struct mixer_control* output; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| output = reinterpret_cast<struct mixer_control*>(3); |
| cras_alsa_mixer_get_control_name_values[output] = HEADPHONE; |
| |
| // Create the iodev |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called); |
| |
| // First node 'Headphone' |
| section = ucm_section_create(HEADPHONE, "hw:0,1", 0, -1, CRAS_STREAM_OUTPUT, |
| "fake-jack", "gpio"); |
| ucm_section_set_mixer_name(section, HEADPHONE); |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(10); |
| cras_alsa_mixer_get_control_for_section_return_value = output; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| ucm_section_free_list(section); |
| |
| // Second node 'Line Out' |
| section = ucm_section_create("Line Out", "hw:0.1", 0, -1, CRAS_STREAM_OUTPUT, |
| "fake-jack", "gpio"); |
| ucm_section_set_mixer_name(section, HEADPHONE); |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(20); |
| cras_alsa_mixer_get_control_for_section_return_value = output; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(7, cras_card_config_get_volume_curve_for_control_called); |
| ucm_section_free_list(section); |
| |
| // Both nodes are associated with the same mixer output. Different jack plug |
| // report should trigger different node attribute change. |
| cras_alsa_jack_get_mixer_output_ret = output; |
| jack_output_plug_event(reinterpret_cast<struct cras_alsa_jack*>(10), 0, aio); |
| EXPECT_STREQ(cras_iodev_set_node_plugged_ionode->name, HEADPHONE); |
| |
| jack_output_plug_event(reinterpret_cast<struct cras_alsa_jack*>(20), 0, aio); |
| EXPECT_STREQ(cras_iodev_set_node_plugged_ionode->name, "Line Out"); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, MaxSupportedChannels) { |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| struct ucm_section* section; |
| int i; |
| |
| // i = 0: cras_alsa_support_8_channels is false, support 2 channels only. |
| // i = 1: cras_alsa_support_8_channels is true, support up to 8 channels. |
| for (i = 0; i < 2; i++) { |
| ResetStubData(); |
| cras_alsa_support_8_channels = (bool)i; |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| |
| // Node without controls or jacks. |
| section = ucm_section_create(INTERNAL_SPEAKER, "hw:0,1", 1, -1, |
| CRAS_STREAM_OUTPUT, NULL, NULL); |
| // Device index doesn't match. |
| EXPECT_EQ(-22, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| section->dev_idx = 0; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| uint32_t max_channels = (cras_alsa_support_8_channels) ? 8 : 2; |
| EXPECT_EQ(max_channels, iodev->info.max_supported_channels); |
| alsa_iodev_destroy(iodev); |
| } |
| } |
| |
| TEST(AlsaOutputNode, OutputsFromUCM) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Headset Jack"; |
| struct mixer_control* outputs[2]; |
| int rc; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| outputs[0] = reinterpret_cast<struct mixer_control*>(3); |
| outputs[1] = reinterpret_cast<struct mixer_control*>(4); |
| cras_alsa_mixer_list_outputs_outputs = outputs; |
| cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs); |
| cras_alsa_mixer_get_control_name_values[outputs[0]] = INTERNAL_SPEAKER; |
| cras_alsa_mixer_get_control_name_values[outputs[1]] = HEADPHONE; |
| ucm_get_dma_period_for_dev_ret = 1000; |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called); |
| |
| // First node. |
| section = ucm_section_create(INTERNAL_SPEAKER, "hw:0,1", 0, -1, |
| CRAS_STREAM_OUTPUT, NULL, NULL); |
| ucm_section_set_mixer_name(section, INTERNAL_SPEAKER); |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(1); |
| cras_alsa_mixer_get_control_for_section_return_value = outputs[0]; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Add a second node (will use the same iodev). |
| section = ucm_section_create(HEADPHONE, "hw:0,2", 0, -1, CRAS_STREAM_OUTPUT, |
| jack_name, "hctl"); |
| ucm_section_add_coupled(section, "HP-L", MIXER_NAME_VOLUME); |
| ucm_section_add_coupled(section, "HP-R", MIXER_NAME_VOLUME); |
| cras_alsa_jack_list_add_jack_for_section_result_jack = NULL; |
| cras_alsa_mixer_get_control_for_section_return_value = outputs[1]; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| /* New nodes creation calls get volume curve once, NULL jack doesn't make |
| * more calls. */ |
| EXPECT_EQ(5, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Jack plug of an unkonwn device should do nothing. |
| cras_alsa_jack_get_mixer_output_ret = NULL; |
| cras_alsa_jack_get_name_ret_value = "Some other jack"; |
| jack_output_plug_event(reinterpret_cast<struct cras_alsa_jack*>(4), 0, aio); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_called); |
| |
| // Complete initialization, and make first node active. |
| cras_alsa_support_8_channels = false; // Support 2 channels only. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(2, cras_alsa_jack_list_add_jack_for_section_called); |
| EXPECT_EQ(2, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(1, ucm_get_dma_period_for_dev_called); |
| EXPECT_EQ(ucm_get_dma_period_for_dev_ret, aio->dma_period_set_microsecs); |
| /* Call cras_alsa_fill_properties once on update_max_supported_channels. */ |
| EXPECT_EQ(1, cras_alsa_fill_properties_called); |
| EXPECT_EQ(2, iodev->info.max_supported_channels); |
| |
| aio->handle = (snd_pcm_t*)0x24; |
| |
| ResetStubData(); |
| rc = alsa_iodev_set_active_node(iodev, aio->base.nodes->next, 1); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, alsa_mixer_set_mute_called); |
| EXPECT_EQ(outputs[1], alsa_mixer_set_mute_output); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(outputs[1], alsa_mixer_set_dBFS_output); |
| ASSERT_EQ(2, cras_alsa_mixer_set_output_active_state_called); |
| EXPECT_EQ(outputs[0], cras_alsa_mixer_set_output_active_state_outputs[0]); |
| EXPECT_EQ(0, cras_alsa_mixer_set_output_active_state_values[0]); |
| EXPECT_EQ(outputs[1], cras_alsa_mixer_set_output_active_state_outputs[1]); |
| EXPECT_EQ(1, cras_alsa_mixer_set_output_active_state_values[1]); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(1, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(1, ucm_set_enabled_called); |
| |
| // Simulate jack plug event. |
| cras_alsa_support_8_channels = true; // Support up to 8 channels. |
| cras_alsa_jack_get_mixer_output_ret = outputs[1]; |
| cras_alsa_jack_get_name_ret_value = jack_name; |
| jack_output_plug_event(reinterpret_cast<struct cras_alsa_jack*>(4), 0, aio); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| /* Headphone plug event shouldn't trigger update_max_supported_channels. */ |
| EXPECT_EQ(0, cras_alsa_fill_properties_called); |
| EXPECT_EQ(2, iodev->info.max_supported_channels); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, OutputNoControlsUCM) { |
| struct alsa_io* aio; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Node without controls or jacks. |
| section = ucm_section_create(INTERNAL_SPEAKER, "hw:0,1", 1, -1, |
| CRAS_STREAM_OUTPUT, NULL, NULL); |
| // Device index doesn't match. |
| EXPECT_EQ(-22, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| section->dev_idx = 0; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(1, cras_iodev_add_node_called); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(0, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(1, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, OutputFromJackUCM) { |
| struct alsa_io* aio; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Headset Jack"; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| EXPECT_EQ(1, cras_card_config_get_volume_curve_for_control_called); |
| |
| // Node without controls or jacks. |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(1); |
| section = ucm_section_create(HEADPHONE, "hw:0,1", 0, -1, CRAS_STREAM_OUTPUT, |
| jack_name, "hctl"); |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(4, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(1, cras_iodev_add_node_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_add_jack_for_section_called); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(1, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(0, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, InputsFromUCM) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct mixer_control* inputs[2]; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Headset Jack"; |
| int rc; |
| struct ucm_section* section; |
| long intrinsic_sensitivity = -2700; |
| |
| ResetStubData(); |
| inputs[0] = reinterpret_cast<struct mixer_control*>(3); |
| inputs[1] = reinterpret_cast<struct mixer_control*>(4); |
| cras_alsa_mixer_list_inputs_outputs = inputs; |
| cras_alsa_mixer_list_inputs_outputs_length = ARRAY_SIZE(inputs); |
| cras_alsa_mixer_get_control_name_values[inputs[0]] = INTERNAL_MICROPHONE; |
| cras_alsa_mixer_get_control_name_values[inputs[1]] = MIC; |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| |
| // First node. |
| cras_alsa_mixer_get_control_for_section_return_value = inputs[0]; |
| section = ucm_section_create(INTERNAL_MICROPHONE, "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); |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| |
| // Add a second node (will use the same iodev). |
| cras_alsa_mixer_get_control_name_called = 0; |
| // Set intrinsic sensitivity to enable software gain. |
| ucm_get_intrinsic_sensitivity_values[MIC] = intrinsic_sensitivity; |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(1); |
| cras_alsa_mixer_get_control_for_section_return_value = inputs[1]; |
| section = ucm_section_create(MIC, "hw:0,2", 0, -1, CRAS_STREAM_INPUT, |
| jack_name, "hctl"); |
| ucm_section_set_mixer_name(section, MIC); |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| |
| // Jack plug of an unknown device should do nothing. |
| cras_alsa_jack_get_mixer_input_ret = NULL; |
| cras_alsa_jack_get_name_ret_value = "Some other jack"; |
| jack_input_plug_event(reinterpret_cast<struct cras_alsa_jack*>(4), 0, aio); |
| EXPECT_EQ(0, cras_iodev_set_node_plugged_called); |
| |
| // Simulate jack plug event. |
| cras_alsa_jack_get_mixer_input_ret = inputs[1]; |
| cras_alsa_jack_get_name_ret_value = jack_name; |
| jack_input_plug_event(reinterpret_cast<struct cras_alsa_jack*>(4), 0, aio); |
| EXPECT_EQ(1, cras_iodev_set_node_plugged_called); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| EXPECT_EQ(2, cras_alsa_jack_list_add_jack_for_section_called); |
| EXPECT_EQ(2, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(2, cras_iodev_add_node_called); |
| EXPECT_EQ(2, ucm_get_dma_period_for_dev_called); |
| EXPECT_EQ(0, aio->dma_period_set_microsecs); |
| |
| aio->handle = (snd_pcm_t*)0x24; |
| |
| ResetStubData(); |
| rc = alsa_iodev_set_active_node(iodev, aio->base.nodes->next, 1); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, alsa_mixer_set_capture_dBFS_called); |
| EXPECT_EQ(inputs[1], alsa_mixer_set_capture_dBFS_input); |
| EXPECT_EQ(0, alsa_mixer_set_capture_dBFS_value); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(1, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(1, ucm_set_enabled_called); |
| EXPECT_EQ(1, alsa_mixer_set_capture_mute_called); |
| ASSERT_EQ(DEFAULT_CAPTURE_VOLUME_DBFS - intrinsic_sensitivity, |
| iodev->active_node->capture_gain); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, InputNoControlsUCM) { |
| struct alsa_io* aio; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| |
| // Node without controls or jacks. |
| section = ucm_section_create(INTERNAL_MICROPHONE, "hw:0,1", 1, -1, |
| CRAS_STREAM_INPUT, NULL, NULL); |
| // Device index doesn't match. |
| EXPECT_EQ(-22, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| section->dev_idx = 0; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(1, cras_alsa_jack_list_add_jack_for_section_called); |
| EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(1, cras_iodev_add_node_called); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(0, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(1, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, InputFromJackUCM) { |
| struct alsa_io* aio; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Headset Jack"; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| |
| // Node without controls or jacks. |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(1); |
| section = ucm_section_create(MIC, "hw:0,1", 0, -1, CRAS_STREAM_INPUT, |
| jack_name, "hctl"); |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| EXPECT_EQ(1, cras_alsa_mixer_get_control_for_section_called); |
| EXPECT_EQ(1, cras_iodev_add_node_called); |
| EXPECT_EQ(1, cras_alsa_jack_list_add_jack_for_section_called); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and make first node active. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| EXPECT_EQ(0, cras_alsa_mixer_get_control_name_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_EQ(1, cras_alsa_jack_enable_ucm_called); |
| EXPECT_EQ(0, ucm_set_enabled_called); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaOutputNode, AutoUnplugOutputNode) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct mixer_control* outputs[2]; |
| const struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| |
| ResetStubData(); |
| outputs[0] = reinterpret_cast<struct mixer_control*>(5); |
| outputs[1] = reinterpret_cast<struct mixer_control*>(6); |
| |
| cras_alsa_mixer_list_outputs_outputs = outputs; |
| cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs); |
| |
| cras_alsa_mixer_get_control_name_values[outputs[0]] = INTERNAL_SPEAKER; |
| cras_alsa_mixer_get_control_name_values[outputs[1]] = HEADPHONE; |
| auto_unplug_output_node_ret = 1; |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(3, cras_card_config_get_volume_curve_for_control_called); |
| EXPECT_EQ(1, cras_alsa_mixer_list_outputs_called); |
| EXPECT_EQ(2, cras_alsa_mixer_get_control_name_called); |
| |
| // Assert that the the internal speaker is plugged and other nodes aren't. |
| ASSERT_NE(aio->base.nodes, (void*)NULL); |
| EXPECT_EQ(aio->base.nodes->plugged, 1); |
| ASSERT_NE(aio->base.nodes->next, (void*)NULL); |
| EXPECT_EQ(aio->base.nodes->next->plugged, 0); |
| |
| // Plug headphone jack |
| cras_alsa_jack_get_name_ret_value = "Headphone Jack"; |
| is_utf8_string_ret_value = 1; |
| cras_alsa_jack_get_mixer_output_ret = outputs[1]; |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| |
| // Assert internal speaker is auto unplugged |
| EXPECT_EQ(aio->base.nodes->plugged, 0); |
| EXPECT_EQ(aio->base.nodes->next->plugged, 1); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaOutputNode, AutoUnplugInputNode) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct mixer_control* inputs[2]; |
| const struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| |
| ResetStubData(); |
| inputs[0] = reinterpret_cast<struct mixer_control*>(5); |
| inputs[1] = reinterpret_cast<struct mixer_control*>(6); |
| |
| cras_alsa_mixer_list_inputs_outputs = inputs; |
| cras_alsa_mixer_list_inputs_outputs_length = ARRAY_SIZE(inputs); |
| |
| cras_alsa_mixer_get_control_name_values[inputs[0]] = INTERNAL_MICROPHONE; |
| cras_alsa_mixer_get_control_name_values[inputs[1]] = MIC; |
| auto_unplug_input_node_ret = 1; |
| |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| EXPECT_EQ(1, cras_alsa_mixer_list_inputs_called); |
| EXPECT_EQ(2, cras_alsa_mixer_get_control_name_called); |
| |
| // Assert that the the internal speaker is plugged and other nodes aren't. |
| ASSERT_NE(aio->base.nodes, (void*)NULL); |
| EXPECT_EQ(aio->base.nodes->plugged, 1); |
| ASSERT_NE(aio->base.nodes->next, (void*)NULL); |
| EXPECT_EQ(aio->base.nodes->next->plugged, 0); |
| |
| // Plug headphone jack |
| cras_alsa_jack_get_name_ret_value = "Mic Jack"; |
| is_utf8_string_ret_value = 1; |
| cras_alsa_jack_get_mixer_input_ret = inputs[1]; |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| |
| // Assert internal speaker is auto unplugged |
| EXPECT_EQ(aio->base.nodes->plugged, 0); |
| EXPECT_EQ(aio->base.nodes->next->plugged, 1); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| TEST(AlsaLoopback, InitializePlayback) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Alsa Loopback"; |
| struct mixer_control* outputs[1]; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| outputs[0] = reinterpret_cast<struct mixer_control*>(3); |
| cras_alsa_mixer_list_outputs_outputs = outputs; |
| cras_alsa_mixer_list_outputs_outputs_length = ARRAY_SIZE(outputs); |
| cras_alsa_mixer_get_control_name_values[outputs[0]] = LOOPBACK_PLAYBACK; |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| |
| // Add node. |
| section = ucm_section_create(LOOPBACK_PLAYBACK, "hw:0,1", 0, -1, |
| CRAS_STREAM_OUTPUT, jack_name, NULL); |
| ucm_section_set_mixer_name(section, LOOPBACK_PLAYBACK); |
| cras_alsa_jack_list_add_jack_for_section_result_jack = NULL; |
| cras_alsa_mixer_get_control_for_section_return_value = outputs[0]; |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and check the loopback playback node is plugged as |
| // the active node. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_PLAYBACK, aio->alsa_stream); |
| ASSERT_NE(aio->base.active_node, (void*)NULL); |
| EXPECT_STREQ(LOOPBACK_PLAYBACK, aio->base.active_node->name); |
| EXPECT_EQ(1, aio->base.active_node->plugged); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaLoopback, InitializeCapture) { |
| struct alsa_io* aio; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| struct cras_iodev* iodev; |
| static const char* jack_name = "TestCard - Alsa Loopback"; |
| struct ucm_section* section; |
| |
| ResetStubData(); |
| |
| // Create the IO device. |
| iodev = alsa_iodev_create_with_default_parameters( |
| 1, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_INPUT); |
| ASSERT_NE(iodev, (void*)NULL); |
| aio = reinterpret_cast<struct alsa_io*>(iodev); |
| |
| // Node without controls or jacks. |
| cras_alsa_jack_list_add_jack_for_section_result_jack = |
| reinterpret_cast<struct cras_alsa_jack*>(1); |
| section = ucm_section_create(LOOPBACK_CAPTURE, "hw:0,1", 0, -1, |
| CRAS_STREAM_INPUT, jack_name, NULL); |
| ASSERT_EQ(0, alsa_iodev_ucm_add_nodes_and_jacks(iodev, section)); |
| ucm_section_free_list(section); |
| |
| // Complete initialization, and check the loopback capture node is plugged as |
| // the active node. |
| alsa_iodev_ucm_complete_init(iodev); |
| EXPECT_EQ(SND_PCM_STREAM_CAPTURE, aio->alsa_stream); |
| ASSERT_NE(aio->base.active_node, (void*)NULL); |
| EXPECT_STREQ(LOOPBACK_CAPTURE, aio->base.active_node->name); |
| EXPECT_EQ(1, aio->base.active_node->plugged); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaInitNode, SetNodeInitialState) { |
| struct cras_ionode node; |
| struct cras_iodev dev; |
| |
| memset(&dev, 0, sizeof(dev)); |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Unknown"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(0, node.plugged_time.tv_sec); |
| ASSERT_EQ(CRAS_NODE_TYPE_UNKNOWN, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, INTERNAL_SPEAKER); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_GT(node.plugged_time.tv_sec, 0); |
| ASSERT_EQ(CRAS_NODE_TYPE_INTERNAL_SPEAKER, node.type); |
| ASSERT_EQ(NODE_POSITION_INTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, INTERNAL_MICROPHONE); |
| dev.direction = CRAS_STREAM_INPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_GT(node.plugged_time.tv_sec, 0); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_INTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, HDMI); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(0, node.plugged_time.tv_sec); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "IEC958"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "HDMI Jack"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Something HDMI Jack"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, HEADPHONE); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HEADPHONE, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Headphone Jack"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HEADPHONE, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, MIC); |
| dev.direction = CRAS_STREAM_INPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Front Mic"); |
| dev.direction = CRAS_STREAM_INPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_FRONT, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Rear Mic"); |
| dev.direction = CRAS_STREAM_INPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_REAR, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Mic Jack"); |
| dev.direction = CRAS_STREAM_INPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Unknown"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_USB); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_USB, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| dev.direction = CRAS_STREAM_INPUT; |
| strcpy(node.name, "DAISY-I2S Mic Jack"); |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_MIC, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| // Node name is changed to "MIC". |
| ASSERT_EQ(0, strcmp(node.name, MIC)); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| dev.direction = CRAS_STREAM_OUTPUT; |
| strcpy(node.name, "DAISY-I2S Headphone Jack"); |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(0, node.plugged); |
| ASSERT_EQ(CRAS_NODE_TYPE_HEADPHONE, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| // Node name is changed to "Headphone". |
| ASSERT_EQ(0, strcmp(node.name, HEADPHONE)); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, INTERNAL_SPEAKER); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_USB); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_GT(node.plugged_time.tv_sec, 0); |
| ASSERT_EQ(CRAS_NODE_TYPE_USB, node.type); |
| ASSERT_EQ(NODE_POSITION_EXTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Haptic"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_GT(node.plugged_time.tv_sec, 0); |
| ASSERT_EQ(CRAS_NODE_TYPE_HAPTIC, node.type); |
| ASSERT_EQ(NODE_POSITION_INTERNAL, node.position); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Rumbler"); |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(1, node.plugged); |
| ASSERT_GT(node.plugged_time.tv_sec, 0); |
| ASSERT_EQ(CRAS_NODE_TYPE_HAPTIC, node.type); |
| ASSERT_EQ(NODE_POSITION_INTERNAL, node.position); |
| } |
| |
| TEST(AlsaInitNode, SetNodeInitialStateDropInvalidUTF8NodeName) { |
| struct cras_ionode node; |
| struct cras_iodev dev; |
| |
| memset(&dev, 0, sizeof(dev)); |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Something USB"); |
| // 0xfe can not appear in a valid UTF-8 string. |
| node.name[0] = 0xfe; |
| is_utf8_string_ret_value = 0; |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_USB); |
| ASSERT_EQ(CRAS_NODE_TYPE_USB, node.type); |
| ASSERT_STREQ(USB, node.name); |
| |
| memset(&node, 0, sizeof(node)); |
| node.dev = &dev; |
| strcpy(node.name, "Something HDMI Jack"); |
| // 0xfe can not appear in a valid UTF-8 string. |
| node.name[0] = 0xfe; |
| is_utf8_string_ret_value = 0; |
| dev.direction = CRAS_STREAM_OUTPUT; |
| set_node_initial_state(&node, ALSA_CARD_TYPE_INTERNAL); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, node.type); |
| ASSERT_STREQ(HDMI, node.name); |
| } |
| |
| TEST(AlsaIoInit, HDMIJackUpdateInvalidUTF8MonitorName) { |
| struct alsa_io* aio; |
| struct cras_alsa_mixer* const fake_mixer = (struct cras_alsa_mixer*)2; |
| struct cras_use_case_mgr* const fake_ucm = (struct cras_use_case_mgr*)3; |
| const struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| |
| ResetStubData(); |
| aio = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, fake_ucm, |
| CRAS_STREAM_OUTPUT); |
| ASSERT_EQ(0, alsa_iodev_legacy_complete_init((struct cras_iodev*)aio)); |
| |
| // Prepare the stub data such that the jack will be identified as an |
| // HDMI jack, and thus the callback creates an HDMI node. |
| cras_alsa_jack_get_name_ret_value = "HDMI Jack"; |
| // Set the jack name updated from monitor to be an invalid UTF8 string. |
| cras_alsa_jack_update_monitor_fake_name = "\xfeomething"; |
| is_utf8_string_ret_value = 0; |
| |
| // Add the jack node. |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| |
| EXPECT_EQ(2, cras_alsa_jack_get_name_called); |
| ASSERT_EQ(CRAS_NODE_TYPE_HDMI, aio->base.nodes->next->type); |
| // The node name should be "HDMI". |
| ASSERT_STREQ(HDMI, aio->base.nodes->next->name); |
| |
| alsa_iodev_destroy((struct cras_iodev*)aio); |
| } |
| |
| // Test thread add/rm stream, open_alsa, and iodev config. |
| class AlsaVolumeMuteSuite : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| ResetStubData(); |
| output_control_ = reinterpret_cast<struct mixer_control*>(10); |
| cras_alsa_mixer_list_outputs_outputs = &output_control_; |
| cras_alsa_mixer_list_outputs_outputs_length = 1; |
| cras_alsa_mixer_get_control_name_values[output_control_] = INTERNAL_SPEAKER; |
| cras_alsa_mixer_list_outputs_outputs_length = 1; |
| aio_output_ = (struct alsa_io*)alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 1, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| alsa_iodev_legacy_complete_init((struct cras_iodev*)aio_output_); |
| EXPECT_EQ(2, cras_card_config_get_volume_curve_for_control_called); |
| |
| struct cras_ionode* node; |
| int count = 0; |
| DL_FOREACH (aio_output_->base.nodes, node) { printf("node %d \n", count); } |
| aio_output_->base.direction = CRAS_STREAM_OUTPUT; |
| fmt_.frame_rate = 44100; |
| fmt_.num_channels = 2; |
| fmt_.format = SND_PCM_FORMAT_S16_LE; |
| aio_output_->base.format = &fmt_; |
| cras_alsa_get_avail_frames_ret = -1; |
| } |
| |
| virtual void TearDown() { |
| alsa_iodev_destroy((struct cras_iodev*)aio_output_); |
| cras_alsa_get_avail_frames_ret = 0; |
| } |
| |
| struct mixer_control* output_control_; |
| struct alsa_io* aio_output_; |
| struct cras_audio_format fmt_; |
| }; |
| |
| TEST_F(AlsaVolumeMuteSuite, GetDefaultVolumeCurve) { |
| int rc; |
| struct cras_audio_format* fmt; |
| |
| fmt = (struct cras_audio_format*)malloc(sizeof(*fmt)); |
| memcpy(fmt, &fmt_, sizeof(fmt_)); |
| aio_output_->base.format = fmt; |
| aio_output_->handle = (snd_pcm_t*)0x24; |
| |
| rc = aio_output_->base.configure_dev(&aio_output_->base); |
| ASSERT_EQ(0, rc); |
| EXPECT_EQ(&default_curve, fake_get_dBFS_volume_curve_val); |
| |
| aio_output_->base.set_volume(&aio_output_->base); |
| EXPECT_EQ(&default_curve, fake_get_dBFS_volume_curve_val); |
| free(fmt); |
| } |
| |
| TEST_F(AlsaVolumeMuteSuite, GetVolumeCurveFromNode) { |
| int rc; |
| struct cras_audio_format* fmt; |
| struct cras_alsa_jack* jack = (struct cras_alsa_jack*)4; |
| struct cras_ionode* node; |
| struct cras_volume_curve hp_curve = { |
| .get_dBFS = fake_get_dBFS, |
| }; |
| |
| // Headphone jack plugged and has its own volume curve. |
| cras_alsa_jack_get_mixer_output_ret = NULL; |
| cras_alsa_jack_get_name_ret_value = HEADPHONE; |
| cras_card_config_get_volume_curve_vals[HEADPHONE] = &hp_curve; |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(1, cras_alsa_jack_update_node_type_called); |
| EXPECT_EQ(3, cras_card_config_get_volume_curve_for_control_called); |
| |
| // These settings should be placed after plugging jacks to make it safer. |
| // If is HDMI jack, plug event will trigger update_max_supported_channels() |
| // and do open_dev() and close_dev() once. close_dev() will perform alsa_io |
| // cleanup. |
| // Headphone jack won't trigger, but we still place here due to coherence. |
| fmt = (struct cras_audio_format*)malloc(sizeof(*fmt)); |
| memcpy(fmt, &fmt_, sizeof(fmt_)); |
| aio_output_->base.format = fmt; |
| aio_output_->handle = (snd_pcm_t*)0x24; |
| |
| // Switch to node 'Headphone'. |
| node = aio_output_->base.nodes->next; |
| aio_output_->base.active_node = node; |
| |
| rc = aio_output_->base.configure_dev(&aio_output_->base); |
| ASSERT_EQ(0, rc); |
| EXPECT_EQ(&hp_curve, fake_get_dBFS_volume_curve_val); |
| |
| aio_output_->base.set_volume(&aio_output_->base); |
| EXPECT_EQ(&hp_curve, fake_get_dBFS_volume_curve_val); |
| free(fmt); |
| } |
| |
| TEST_F(AlsaVolumeMuteSuite, SetVolume) { |
| int rc; |
| struct cras_audio_format* fmt; |
| const size_t fake_system_volume = 55; |
| const size_t fake_system_volume_dB = (fake_system_volume - 100) * 100; |
| |
| fmt = (struct cras_audio_format*)malloc(sizeof(*fmt)); |
| memcpy(fmt, &fmt_, sizeof(fmt_)); |
| aio_output_->base.format = fmt; |
| aio_output_->handle = (snd_pcm_t*)0x24; |
| |
| sys_get_volume_return_value = fake_system_volume; |
| rc = aio_output_->base.configure_dev(&aio_output_->base); |
| ASSERT_EQ(0, rc); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(fake_system_volume_dB, alsa_mixer_set_dBFS_value); |
| |
| alsa_mixer_set_dBFS_called = 0; |
| alsa_mixer_set_dBFS_value = 0; |
| sys_get_volume_return_value = 50; |
| sys_get_volume_called = 0; |
| aio_output_->base.set_volume(&aio_output_->base); |
| EXPECT_EQ(1, sys_get_volume_called); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(-5000, alsa_mixer_set_dBFS_value); |
| EXPECT_EQ(output_control_, alsa_mixer_set_dBFS_output); |
| |
| alsa_mixer_set_dBFS_called = 0; |
| alsa_mixer_set_dBFS_value = 0; |
| sys_get_volume_return_value = 0; |
| sys_get_volume_called = 0; |
| aio_output_->base.set_volume(&aio_output_->base); |
| EXPECT_EQ(1, sys_get_volume_called); |
| EXPECT_EQ(1, alsa_mixer_set_dBFS_called); |
| EXPECT_EQ(-10000, alsa_mixer_set_dBFS_value); |
| |
| sys_get_volume_return_value = 80; |
| aio_output_->base.active_node->volume = 90; |
| aio_output_->base.set_volume(&aio_output_->base); |
| EXPECT_EQ(-3000, alsa_mixer_set_dBFS_value); |
| |
| // close the dev. |
| rc = aio_output_->base.close_dev(&aio_output_->base); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ((void*)NULL, aio_output_->handle); |
| |
| free(fmt); |
| } |
| |
| TEST_F(AlsaVolumeMuteSuite, SetMute) { |
| int muted; |
| |
| aio_output_->handle = (snd_pcm_t*)0x24; |
| |
| // Test mute. |
| ResetStubData(); |
| muted = 1; |
| |
| sys_get_mute_return_value = muted; |
| |
| aio_output_->base.set_mute(&aio_output_->base); |
| |
| EXPECT_EQ(1, sys_get_mute_called); |
| EXPECT_EQ(1, alsa_mixer_set_mute_called); |
| EXPECT_EQ(muted, alsa_mixer_set_mute_value); |
| EXPECT_EQ(output_control_, alsa_mixer_set_mute_output); |
| |
| // Test unmute. |
| ResetStubData(); |
| muted = 0; |
| |
| sys_get_mute_return_value = muted; |
| |
| aio_output_->base.set_mute(&aio_output_->base); |
| |
| EXPECT_EQ(1, sys_get_mute_called); |
| EXPECT_EQ(1, alsa_mixer_set_mute_called); |
| EXPECT_EQ(muted, alsa_mixer_set_mute_value); |
| EXPECT_EQ(output_control_, alsa_mixer_set_mute_output); |
| } |
| |
| // Test free run. |
| class AlsaFreeRunTestSuite : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| ResetStubData(); |
| memset(&aio, 0, sizeof(aio)); |
| fmt_.format = SND_PCM_FORMAT_S16_LE; |
| fmt_.frame_rate = 48000; |
| fmt_.num_channels = 2; |
| aio.base.frames_queued = frames_queued; |
| aio.base.output_underrun = alsa_output_underrun; |
| aio.base.direction = CRAS_STREAM_OUTPUT; |
| aio.base.format = &fmt_; |
| aio.base.buffer_size = BUFFER_SIZE; |
| aio.base.min_cb_level = 240; |
| aio.base.min_buffer_level = 0; |
| aio.filled_zeros_for_draining = 0; |
| cras_alsa_mmap_begin_buffer = (uint8_t*)calloc( |
| BUFFER_SIZE * 2 * 2, sizeof(*cras_alsa_mmap_begin_buffer)); |
| memset(cras_alsa_mmap_begin_buffer, 0xff, |
| sizeof(*cras_alsa_mmap_begin_buffer)); |
| } |
| |
| virtual void TearDown() { free(cras_alsa_mmap_begin_buffer); } |
| |
| struct alsa_io aio; |
| struct cras_audio_format fmt_; |
| }; |
| |
| TEST_F(AlsaFreeRunTestSuite, FillWholeBufferWithZeros) { |
| int rc; |
| int16_t* zeros; |
| |
| rc = fill_whole_buffer_with_zeros(&aio.base); |
| |
| EXPECT_EQ(0, rc); |
| zeros = (int16_t*)calloc(BUFFER_SIZE * 2, sizeof(*zeros)); |
| EXPECT_EQ(0, memcmp(zeros, cras_alsa_mmap_begin_buffer, BUFFER_SIZE * 2 * 2)); |
| |
| free(zeros); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunAlreadyFreeRunning) { |
| int rc; |
| |
| // Device is in free run state, no need to fill zeros or fill whole buffer. |
| aio.free_running = 1; |
| |
| rc = no_stream(&aio.base, 1); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(0, cras_alsa_mmap_get_whole_buffer_called); |
| EXPECT_EQ(0, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(0, cras_iodev_fill_odev_zeros_frames); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunNotDrainedYetNeedToFillZeros) { |
| int rc, real_hw_level; |
| struct timespec hw_tstamp; |
| int fill_zeros_duration = 50; |
| // Device is not in free run state. There are still valid samples to play. |
| // In cras_alsa_io.c, we defined there are 50ms zeros to be filled. |
| real_hw_level = 200; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| |
| rc = aio.base.frames_queued(&aio.base, &hw_tstamp); |
| EXPECT_EQ(200, rc); |
| |
| rc = no_stream(&aio.base, 1); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(0, cras_alsa_mmap_get_whole_buffer_called); |
| EXPECT_EQ(1, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(fmt_.frame_rate / 1000 * fill_zeros_duration, |
| cras_iodev_fill_odev_zeros_frames); |
| EXPECT_EQ(fmt_.frame_rate / 1000 * fill_zeros_duration, |
| aio.filled_zeros_for_draining); |
| EXPECT_EQ(0, aio.free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunNotDrainedYetFillZerosExceedBuffer) { |
| int rc, real_hw_level; |
| |
| // Device is not in free run state. There are still valid samples to play. |
| // If frames avail is smaller than 50ms(48 * 50 = 2400 zeros), only fill |
| // zeros until buffer size. |
| real_hw_level = 7000; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| |
| rc = no_stream(&aio.base, 1); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(0, cras_alsa_mmap_get_whole_buffer_called); |
| EXPECT_EQ(1, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(cras_alsa_get_avail_frames_avail, |
| cras_iodev_fill_odev_zeros_frames); |
| EXPECT_EQ(cras_alsa_get_avail_frames_avail, aio.filled_zeros_for_draining); |
| EXPECT_EQ(0, aio.free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunDrained) { |
| int rc, real_hw_level; |
| |
| // Device is not in free run state. There are still valid samples to play. |
| // The number of valid samples is less than filled zeros. |
| // Should enter free run state and fill whole buffer with zeros. |
| real_hw_level = 40; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| aio.filled_zeros_for_draining = 100; |
| |
| rc = no_stream(&aio.base, 1); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_mmap_get_whole_buffer_called); |
| EXPECT_EQ(0, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(1, aio.free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunNoSamples) { |
| int rc, real_hw_level; |
| |
| // Device is not in free run state. There is no sample to play. |
| // Should enter free run state and fill whole buffer with zeros. |
| real_hw_level = 0; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| |
| rc = no_stream(&aio.base, 1); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_mmap_get_whole_buffer_called); |
| EXPECT_EQ(0, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(1, aio.free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, IsFreeRunning) { |
| aio.free_running = 1; |
| EXPECT_EQ(1, is_free_running(&aio.base)); |
| |
| aio.free_running = 0; |
| EXPECT_EQ(0, is_free_running(&aio.base)); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, LeaveFreeRunNotInFreeRunMoreRemain) { |
| int rc, real_hw_level; |
| |
| // Compare min_buffer_level + min_cb_level with valid samples left. |
| // 240 + 512 < 900 - 100, so we will get 900 - 100 in appl_ptr_ahead. |
| |
| aio.free_running = 0; |
| aio.filled_zeros_for_draining = 100; |
| aio.base.min_buffer_level = 512; |
| real_hw_level = 900; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| |
| rc = no_stream(&aio.base, 0); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_resume_appl_ptr_called); |
| EXPECT_EQ(800, cras_alsa_resume_appl_ptr_ahead); |
| EXPECT_EQ(0, cras_iodev_fill_odev_zeros_frames); |
| EXPECT_EQ(0, aio.free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| EXPECT_EQ(1, cras_iodev_reset_rate_estimator_called); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, LeaveFreeRunNotInFreeRunLessRemain) { |
| int rc, real_hw_level; |
| |
| // Compare min_buffer_level + min_cb_level with valid samples left. |
| // 240 + 256 > 400 - 500, so we will get 240 + 256 in appl_ptr_ahead. |
| // And it will fill 240 + 256 - 400 = 96 zeros frames into device. |
| |
| aio.free_running = 0; |
| aio.filled_zeros_for_draining = 500; |
| aio.base.min_buffer_level = 256; |
| real_hw_level = 400; |
| cras_alsa_get_avail_frames_avail = BUFFER_SIZE - real_hw_level; |
| |
| rc = no_stream(&aio.base, 0); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_resume_appl_ptr_called); |
| EXPECT_EQ(aio.base.min_buffer_level + aio.base.min_cb_level, |
| cras_alsa_resume_appl_ptr_ahead); |
| EXPECT_EQ(96, cras_iodev_fill_odev_zeros_frames); |
| EXPECT_EQ(0, aio.free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| EXPECT_EQ(1, cras_iodev_reset_rate_estimator_called); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, LeaveFreeRunInFreeRun) { |
| int rc; |
| |
| aio.free_running = 1; |
| aio.filled_zeros_for_draining = 100; |
| aio.base.min_buffer_level = 512; |
| |
| rc = no_stream(&aio.base, 0); |
| |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, cras_alsa_resume_appl_ptr_called); |
| EXPECT_EQ(aio.base.min_buffer_level + aio.base.min_cb_level, |
| cras_alsa_resume_appl_ptr_ahead); |
| EXPECT_EQ(0, aio.free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| EXPECT_EQ(1, cras_iodev_reset_rate_estimator_called); |
| } |
| |
| // Reuse AlsaFreeRunTestSuite for output underrun handling because they are |
| // similar. |
| TEST_F(AlsaFreeRunTestSuite, OutputUnderrun) { |
| int rc; |
| int16_t* zeros; |
| snd_pcm_uframes_t offset; |
| |
| // Ask alsa_io to handle output underrun. |
| rc = alsa_output_underrun(&aio.base); |
| EXPECT_EQ(0, rc); |
| |
| // mmap buffer should be filled with zeros. |
| zeros = (int16_t*)calloc(BUFFER_SIZE * 2, sizeof(*zeros)); |
| EXPECT_EQ(0, memcmp(zeros, cras_alsa_mmap_begin_buffer, BUFFER_SIZE * 2 * 2)); |
| |
| // appl_ptr should be moved to min_buffer_level + 1.5 * min_cb_level ahead of |
| // hw_ptr. |
| offset = aio.base.min_buffer_level + aio.base.min_cb_level + |
| aio.base.min_cb_level / 2; |
| EXPECT_EQ(1, cras_alsa_resume_appl_ptr_called); |
| EXPECT_EQ(offset, cras_alsa_resume_appl_ptr_ahead); |
| |
| free(zeros); |
| } |
| |
| TEST(AlsaHotwordNode, HotwordTriggeredSendMessage) { |
| struct cras_iodev* iodev; |
| struct cras_audio_format format; |
| struct alsa_input_node alsa_node; |
| struct cras_ionode* node = &alsa_node.base; |
| int rc; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_INPUT); |
| format.frame_rate = 16000; |
| format.num_channels = 1; |
| cras_iodev_set_format(iodev, &format); |
| |
| memset(&alsa_node, 0, sizeof(alsa_node)); |
| node->dev = iodev; |
| strcpy(node->name, HOTWORD_DEV); |
| set_node_initial_state(node, ALSA_CARD_TYPE_INTERNAL); |
| EXPECT_EQ(CRAS_NODE_TYPE_HOTWORD, node->type); |
| |
| iodev->active_node = node; |
| iodev->open_dev(iodev); |
| rc = iodev->configure_dev(iodev); |
| free(fake_format); |
| ASSERT_EQ(0, rc); |
| |
| ASSERT_NE(reinterpret_cast<thread_callback>(NULL), audio_thread_cb); |
| audio_thread_cb(audio_thread_cb_data, POLLIN); |
| EXPECT_EQ(1, hotword_send_triggered_msg_called); |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaGetValidFrames, GetValidFramesNormalState) { |
| struct cras_iodev* iodev; |
| struct alsa_io* aio; |
| struct timespec tstamp; |
| int rc; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| aio = (struct alsa_io*)iodev; |
| |
| aio->free_running = 0; |
| aio->filled_zeros_for_draining = 200; |
| cras_alsa_get_avail_frames_avail = iodev->buffer_size - 500; |
| cras_alsa_get_avail_frames_ret = 0; |
| clock_gettime_retspec.tv_sec = 123; |
| clock_gettime_retspec.tv_nsec = 321; |
| rc = iodev->get_valid_frames(iodev, &tstamp); |
| EXPECT_EQ(rc, 300); |
| EXPECT_EQ(tstamp.tv_sec, clock_gettime_retspec.tv_sec); |
| EXPECT_EQ(tstamp.tv_nsec, clock_gettime_retspec.tv_nsec); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaGetValidFrames, GetValidFramesFreeRunning) { |
| struct cras_iodev* iodev; |
| struct alsa_io* aio; |
| struct timespec tstamp; |
| int rc; |
| |
| ResetStubData(); |
| iodev = alsa_iodev_create_with_default_parameters( |
| 0, NULL, ALSA_CARD_TYPE_INTERNAL, 0, fake_mixer, fake_config, NULL, |
| CRAS_STREAM_OUTPUT); |
| aio = (struct alsa_io*)iodev; |
| |
| aio->free_running = 1; |
| clock_gettime_retspec.tv_sec = 123; |
| clock_gettime_retspec.tv_nsec = 321; |
| rc = iodev->get_valid_frames(iodev, &tstamp); |
| EXPECT_EQ(rc, 0); |
| EXPECT_EQ(tstamp.tv_sec, clock_gettime_retspec.tv_sec); |
| EXPECT_EQ(tstamp.tv_nsec, clock_gettime_retspec.tv_nsec); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| openlog(NULL, LOG_PERROR, LOG_USER); |
| return RUN_ALL_TESTS(); |
| } |
| |
| // Stubs |
| |
| extern "C" { |
| |
| // From iodev. |
| int cras_iodev_list_add_output(struct cras_iodev* output) { |
| return 0; |
| } |
| int cras_iodev_list_rm_output(struct cras_iodev* dev) { |
| return 0; |
| } |
| |
| int cras_iodev_list_add_input(struct cras_iodev* input) { |
| return 0; |
| } |
| int cras_iodev_list_rm_input(struct cras_iodev* dev) { |
| return 0; |
| } |
| |
| char* cras_iodev_list_get_hotword_models(cras_node_id_t node_id) { |
| return NULL; |
| } |
| |
| int cras_iodev_list_set_hotword_model(cras_node_id_t node_id, |
| const char* model_name) { |
| return 0; |
| } |
| |
| int cras_iodev_list_suspend_hotword_streams() { |
| return 0; |
| } |
| |
| int cras_iodev_list_resume_hotword_stream() { |
| return 0; |
| } |
| |
| struct audio_thread* cras_iodev_list_get_audio_thread() { |
| return NULL; |
| } |
| |
| // From alsa helper. |
| int cras_alsa_set_channel_map(snd_pcm_t* handle, |
| struct cras_audio_format* fmt) { |
| return 0; |
| } |
| int cras_alsa_get_channel_map(snd_pcm_t* handle, |
| struct cras_audio_format* fmt) { |
| return 0; |
| } |
| int cras_alsa_pcm_open(snd_pcm_t** handle, |
| const char* dev, |
| snd_pcm_stream_t stream) { |
| *handle = (snd_pcm_t*)0x24; |
| cras_alsa_open_called++; |
| return 0; |
| } |
| int cras_alsa_pcm_close(snd_pcm_t* handle) { |
| return 0; |
| } |
| int cras_alsa_pcm_start(snd_pcm_t* handle) { |
| cras_alsa_start_called++; |
| return 0; |
| } |
| int cras_alsa_pcm_drain(snd_pcm_t* handle) { |
| return 0; |
| } |
| int cras_alsa_fill_properties(snd_pcm_t* handle, |
| size_t** rates, |
| size_t** channel_counts, |
| snd_pcm_format_t** formats) { |
| *rates = (size_t*)malloc(sizeof(**rates) * 3); |
| (*rates)[0] = 44100; |
| (*rates)[1] = 48000; |
| (*rates)[2] = 0; |
| |
| if (cras_alsa_support_8_channels) { // Support up to 8 channels. |
| *channel_counts = (size_t*)malloc(sizeof(**channel_counts) * 6); |
| (*channel_counts)[0] = 6; |
| (*channel_counts)[1] = 4; |
| (*channel_counts)[2] = 2; |
| (*channel_counts)[3] = 1; |
| (*channel_counts)[4] = 8; |
| (*channel_counts)[5] = 0; |
| } else { // Support 2 channels only. |
| *channel_counts = (size_t*)malloc(sizeof(**channel_counts) * 2); |
| (*channel_counts)[0] = 2; |
| (*channel_counts)[1] = 0; |
| } |
| |
| *formats = (snd_pcm_format_t*)malloc(sizeof(**formats) * 2); |
| (*formats)[0] = SND_PCM_FORMAT_S16_LE; |
| (*formats)[1] = (snd_pcm_format_t)0; |
| |
| cras_alsa_fill_properties_called++; |
| return 0; |
| } |
| int cras_alsa_set_hwparams(snd_pcm_t* handle, |
| struct cras_audio_format* format, |
| snd_pcm_uframes_t* buffer_size, |
| int period_wakeup, |
| unsigned int dma_period_time) { |
| return 0; |
| } |
| int cras_alsa_set_swparams(snd_pcm_t* handle) { |
| return 0; |
| } |
| int cras_alsa_get_avail_frames(snd_pcm_t* handle, |
| snd_pcm_uframes_t buf_size, |
| snd_pcm_uframes_t severe_underrun_frames, |
| const char* dev_name, |
| snd_pcm_uframes_t* used, |
| struct timespec* tstamp) { |
| *used = cras_alsa_get_avail_frames_avail; |
| clock_gettime(CLOCK_MONOTONIC_RAW, tstamp); |
| return cras_alsa_get_avail_frames_ret; |
| } |
| int cras_alsa_get_delay_frames(snd_pcm_t* handle, |
| snd_pcm_uframes_t buf_size, |
| snd_pcm_sframes_t* delay) { |
| *delay = 0; |
| return 0; |
| } |
| int cras_alsa_mmap_begin(snd_pcm_t* handle, |
| unsigned int format_bytes, |
| uint8_t** dst, |
| snd_pcm_uframes_t* offset, |
| snd_pcm_uframes_t* frames) { |
| *dst = cras_alsa_mmap_begin_buffer; |
| *frames = cras_alsa_mmap_begin_frames; |
| return 0; |
| } |
| int cras_alsa_mmap_commit(snd_pcm_t* handle, |
| snd_pcm_uframes_t offset, |
| snd_pcm_uframes_t frames) { |
| return 0; |
| } |
| int cras_alsa_attempt_resume(snd_pcm_t* handle) { |
| cras_alsa_attempt_resume_called++; |
| return 0; |
| } |
| |
| // ALSA stubs. |
| int snd_pcm_format_physical_width(snd_pcm_format_t format) { |
| return 16; |
| } |
| |
| snd_pcm_state_t snd_pcm_state(snd_pcm_t* handle) { |
| return snd_pcm_state_ret; |
| } |
| |
| const char* snd_strerror(int errnum) { |
| return "Alsa Error in UT"; |
| } |
| |
| struct mixer_control* cras_alsa_mixer_get_control_for_section( |
| struct cras_alsa_mixer* cras_mixer, |
| const struct ucm_section* section) { |
| cras_alsa_mixer_get_control_for_section_called++; |
| return cras_alsa_mixer_get_control_for_section_return_value; |
| } |
| |
| const char* cras_alsa_mixer_get_control_name( |
| const struct mixer_control* control) { |
| ControlNameMap::iterator it; |
| cras_alsa_mixer_get_control_name_called++; |
| it = cras_alsa_mixer_get_control_name_values.find(control); |
| if (it == cras_alsa_mixer_get_control_name_values.end()) |
| return ""; |
| return it->second.c_str(); |
| } |
| |
| // From system_state. |
| size_t cras_system_get_volume() { |
| sys_get_volume_called++; |
| return sys_get_volume_return_value; |
| } |
| |
| int cras_system_get_mute() { |
| sys_get_mute_called++; |
| return sys_get_mute_return_value; |
| } |
| |
| int cras_system_get_capture_mute() { |
| sys_get_capture_mute_called++; |
| return sys_get_capture_mute_return_value; |
| } |
| |
| void cras_system_set_volume_limits(long min, long max) { |
| sys_set_volume_limits_called++; |
| } |
| |
| bool cras_system_get_noise_cancellation_enabled() { |
| return false; |
| } |
| |
| // From cras_alsa_mixer. |
| void cras_alsa_mixer_set_dBFS(struct cras_alsa_mixer* m, |
| long dB_level, |
| struct mixer_control* output) { |
| alsa_mixer_set_dBFS_called++; |
| alsa_mixer_set_dBFS_value = dB_level; |
| alsa_mixer_set_dBFS_output = output; |
| } |
| |
| void cras_alsa_mixer_set_mute(struct cras_alsa_mixer* cras_mixer, |
| int muted, |
| struct mixer_control* mixer_output) { |
| alsa_mixer_set_mute_called++; |
| alsa_mixer_set_mute_value = muted; |
| alsa_mixer_set_mute_output = mixer_output; |
| } |
| |
| long cras_alsa_mixer_get_dB_range(struct cras_alsa_mixer* cras_mixer) { |
| alsa_mixer_get_dB_range_called++; |
| return alsa_mixer_get_dB_range_value; |
| } |
| |
| long cras_alsa_mixer_get_output_dB_range(struct mixer_control* mixer_output) { |
| alsa_mixer_get_output_dB_range_called++; |
| return alsa_mixer_get_output_dB_range_value; |
| } |
| |
| void cras_alsa_mixer_set_capture_dBFS(struct cras_alsa_mixer* m, |
| long dB_level, |
| struct mixer_control* mixer_input) { |
| alsa_mixer_set_capture_dBFS_called++; |
| alsa_mixer_set_capture_dBFS_value = dB_level; |
| alsa_mixer_set_capture_dBFS_input = mixer_input; |
| } |
| |
| void cras_alsa_mixer_set_capture_mute(struct cras_alsa_mixer* m, |
| int mute, |
| struct mixer_control* mixer_input) { |
| alsa_mixer_set_capture_mute_called++; |
| alsa_mixer_set_capture_mute_value = mute; |
| alsa_mixer_set_capture_mute_input = mixer_input; |
| } |
| |
| void cras_alsa_mixer_list_outputs(struct cras_alsa_mixer* cras_mixer, |
| cras_alsa_mixer_control_callback cb, |
| void* callback_arg) { |
| cras_alsa_mixer_list_outputs_called++; |
| for (size_t i = 0; i < cras_alsa_mixer_list_outputs_outputs_length; i++) { |
| cb(cras_alsa_mixer_list_outputs_outputs[i], callback_arg); |
| } |
| } |
| |
| void cras_alsa_mixer_list_inputs(struct cras_alsa_mixer* cras_mixer, |
| cras_alsa_mixer_control_callback cb, |
| void* callback_arg) { |
| cras_alsa_mixer_list_inputs_called++; |
| for (size_t i = 0; i < cras_alsa_mixer_list_inputs_outputs_length; i++) { |
| cb(cras_alsa_mixer_list_inputs_outputs[i], callback_arg); |
| } |
| } |
| |
| int cras_alsa_mixer_set_output_active_state(struct mixer_control* output, |
| int active) { |
| cras_alsa_mixer_set_output_active_state_called++; |
| cras_alsa_mixer_set_output_active_state_outputs.push_back(output); |
| cras_alsa_mixer_set_output_active_state_values.push_back(active); |
| return 0; |
| } |
| |
| void cras_volume_curve_destroy(struct cras_volume_curve* curve) {} |
| |
| long cras_alsa_mixer_get_minimum_capture_gain( |
| struct cras_alsa_mixer* cmix, |
| struct mixer_control* mixer_input) { |
| cras_alsa_mixer_get_minimum_capture_gain_called++; |
| cras_alsa_mixer_get_minimum_capture_gain_mixer_input = mixer_input; |
| return cras_alsa_mixer_get_minimum_capture_gain_ret_value; |
| } |
| |
| long cras_alsa_mixer_get_maximum_capture_gain( |
| struct cras_alsa_mixer* cmix, |
| struct mixer_control* mixer_input) { |
| cras_alsa_mixer_get_maximum_capture_gain_called++; |
| cras_alsa_mixer_get_maximum_capture_gain_mixer_input = mixer_input; |
| return cras_alsa_mixer_get_maximum_capture_gain_ret_value; |
| } |
| |
| int cras_alsa_mixer_has_main_volume(const struct cras_alsa_mixer* cras_mixer) { |
| return 1; |
| } |
| |
| int cras_alsa_mixer_has_volume(const struct mixer_control* mixer_control) { |
| return 1; |
| } |
| |
| // From cras_alsa_jack |
| struct cras_alsa_jack_list* cras_alsa_jack_list_create( |
| unsigned int card_index, |
| const char* card_name, |
| unsigned int device_index, |
| int check_gpio_jack, |
| struct cras_alsa_mixer* mixer, |
| struct cras_use_case_mgr* ucm, |
| snd_hctl_t* hctl, |
| enum CRAS_STREAM_DIRECTION direction, |
| jack_state_change_callback* cb, |
| void* cb_data) { |
| cras_alsa_jack_list_create_called++; |
| cras_alsa_jack_list_create_cb = cb; |
| cras_alsa_jack_list_create_cb_data = cb_data; |
| return (struct cras_alsa_jack_list*)0xfee; |
| } |
| |
| int cras_alsa_jack_list_find_jacks_by_name_matching( |
| struct cras_alsa_jack_list* jack_list) { |
| cras_alsa_jack_list_find_jacks_by_name_matching_called++; |
| return 0; |
| } |
| |
| int cras_alsa_jack_list_add_jack_for_section( |
| struct cras_alsa_jack_list* jack_list, |
| struct ucm_section* ucm_section, |
| struct cras_alsa_jack** result_jack) { |
| cras_alsa_jack_list_add_jack_for_section_called++; |
| if (result_jack) |
| *result_jack = cras_alsa_jack_list_add_jack_for_section_result_jack; |
| return 0; |
| } |
| |
| void cras_alsa_jack_list_destroy(struct cras_alsa_jack_list* jack_list) { |
| cras_alsa_jack_list_destroy_called++; |
| } |
| |
| int cras_alsa_jack_list_has_hctl_jacks(struct cras_alsa_jack_list* jack_list) { |
| return cras_alsa_jack_list_has_hctl_jacks_return_val; |
| } |
| |
| void cras_alsa_jack_list_report(const struct cras_alsa_jack_list* jack_list) {} |
| |
| void cras_alsa_jack_enable_ucm(const struct cras_alsa_jack* jack, int enable) { |
| cras_alsa_jack_enable_ucm_called++; |
| } |
| |
| const char* cras_alsa_jack_get_name(const struct cras_alsa_jack* jack) { |
| cras_alsa_jack_get_name_called++; |
| return cras_alsa_jack_get_name_ret_value; |
| } |
| |
| const char* ucm_get_dsp_name_for_dev(struct cras_use_case_mgr* mgr, |
| const char* dev) { |
| DspNameMap::iterator it; |
| ucm_get_dsp_name_for_dev_called++; |
| if (!dev) |
| return NULL; |
| it = ucm_get_dsp_name_for_dev_values.find(dev); |
| if (it == ucm_get_dsp_name_for_dev_values.end()) |
| return NULL; |
| return strdup(it->second.c_str()); |
| } |
| |
| struct mixer_control* cras_alsa_jack_get_mixer_output( |
| const struct cras_alsa_jack* jack) { |
| return cras_alsa_jack_get_mixer_output_ret; |
| } |
| |
| struct mixer_control* cras_alsa_jack_get_mixer_input( |
| const struct cras_alsa_jack* jack) { |
| return cras_alsa_jack_get_mixer_input_ret; |
| } |
| |
| int ucm_set_enabled(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| int enabled) { |
| ucm_set_enabled_called++; |
| return 0; |
| } |
| |
| char* ucm_get_flag(struct cras_use_case_mgr* mgr, const char* flag_name) { |
| if ((!strcmp(flag_name, "AutoUnplugInputNode") && |
| auto_unplug_input_node_ret) || |
| (!strcmp(flag_name, "AutoUnplugOutputNode") && |
| auto_unplug_output_node_ret)) { |
| char* ret = (char*)malloc(8); |
| snprintf(ret, 8, "%s", "1"); |
| return ret; |
| } |
| |
| return NULL; |
| } |
| |
| int ucm_swap_mode_exists(struct cras_use_case_mgr* mgr) { |
| return ucm_swap_mode_exists_ret_value; |
| } |
| |
| int ucm_enable_swap_mode(struct cras_use_case_mgr* mgr, |
| const char* node_name, |
| int enable) { |
| ucm_enable_swap_mode_called++; |
| return ucm_enable_swap_mode_ret_value; |
| } |
| |
| int ucm_get_min_buffer_level(struct cras_use_case_mgr* mgr, |
| unsigned int* level) { |
| *level = 0; |
| return 0; |
| } |
| |
| unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr* mgr) { |
| return 0; |
| } |
| |
| char* ucm_get_hotword_models(struct cras_use_case_mgr* mgr) { |
| return NULL; |
| } |
| |
| int ucm_set_hotword_model(struct cras_use_case_mgr* mgr, const char* model) { |
| return 0; |
| } |
| |
| unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr* mgr, |
| const char* dev) { |
| ucm_get_dma_period_for_dev_called++; |
| return ucm_get_dma_period_for_dev_ret; |
| } |
| |
| int ucm_get_sample_rate_for_dev(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| enum CRAS_STREAM_DIRECTION direction) { |
| return -EINVAL; |
| } |
| |
| int ucm_get_capture_chmap_for_dev(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| int8_t* channel_layout) { |
| return -EINVAL; |
| } |
| |
| int ucm_get_preempt_hotword(struct cras_use_case_mgr* mgr, const char* dev) { |
| return 0; |
| } |
| |
| int ucm_get_channels_for_dev(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| enum CRAS_STREAM_DIRECTION direction, |
| size_t* channels) { |
| return -EINVAL; |
| } |
| |
| int ucm_node_noise_cancellation_exists(struct cras_use_case_mgr* mgr, |
| const char* node_name) { |
| return 0; |
| } |
| |
| int ucm_enable_node_noise_cancellation(struct cras_use_case_mgr* mgr, |
| const char* node_name, |
| int enable) { |
| return 0; |
| } |
| |
| struct cras_volume_curve* cras_volume_curve_create_default() { |
| return &default_curve; |
| } |
| |
| struct cras_volume_curve* cras_card_config_get_volume_curve_for_control( |
| const struct cras_card_config* card_config, |
| const char* control_name) { |
| VolCurveMap::iterator it; |
| cras_card_config_get_volume_curve_for_control_called++; |
| if (!control_name) |
| return NULL; |
| it = cras_card_config_get_volume_curve_vals.find(control_name); |
| if (it == cras_card_config_get_volume_curve_vals.end()) |
| return NULL; |
| return it->second; |
| } |
| |
| void cras_iodev_free_format(struct cras_iodev* iodev) {} |
| |
| int cras_iodev_set_format(struct cras_iodev* iodev, |
| const struct cras_audio_format* fmt) { |
| fake_format = (struct cras_audio_format*)calloc(1, sizeof(cras_audio_format)); |
| // Copy the content of format from fmt into format of iodev. |
| memcpy(fake_format, fmt, sizeof(cras_audio_format)); |
| iodev->format = fake_format; |
| return 0; |
| } |
| |
| struct audio_thread* audio_thread_create() { |
| return reinterpret_cast<audio_thread*>(0x323); |
| } |
| |
| void audio_thread_destroy(audio_thread* thread) {} |
| |
| void cras_iodev_update_dsp(struct cras_iodev* iodev) { |
| cras_iodev_update_dsp_called++; |
| cras_iodev_update_dsp_name = iodev->dsp_name ?: ""; |
| } |
| |
| void cras_iodev_set_node_plugged(struct cras_ionode* ionode, int plugged) { |
| cras_iodev_set_node_plugged_called++; |
| cras_iodev_set_node_plugged_ionode = ionode; |
| cras_iodev_set_node_plugged_value = plugged; |
| if (ionode) |
| ionode->plugged = plugged; |
| } |
| |
| void cras_iodev_add_node(struct cras_iodev* iodev, struct cras_ionode* node) { |
| cras_iodev_add_node_called++; |
| DL_APPEND(iodev->nodes, node); |
| } |
| |
| void cras_iodev_rm_node(struct cras_iodev* iodev, struct cras_ionode* node) { |
| DL_DELETE(iodev->nodes, node); |
| } |
| |
| void cras_iodev_set_active_node(struct cras_iodev* iodev, |
| struct cras_ionode* node) { |
| iodev->active_node = node; |
| } |
| |
| void cras_iodev_free_resources(struct cras_iodev* iodev) { |
| cras_iodev_free_resources_called++; |
| } |
| |
| void cras_alsa_jack_update_monitor_name(const struct cras_alsa_jack* jack, |
| char* name_buf, |
| unsigned int buf_size) { |
| if (cras_alsa_jack_update_monitor_fake_name) |
| strcpy(name_buf, cras_alsa_jack_update_monitor_fake_name); |
| } |
| |
| void cras_alsa_jack_update_node_type(const struct cras_alsa_jack* jack, |
| enum CRAS_NODE_TYPE* type) { |
| cras_alsa_jack_update_node_type_called++; |
| } |
| |
| const char* cras_alsa_jack_get_ucm_device(const struct cras_alsa_jack* jack) { |
| return NULL; |
| } |
| |
| void ucm_disable_all_hotword_models(struct cras_use_case_mgr* mgr) {} |
| |
| int ucm_enable_hotword_model(struct cras_use_case_mgr* mgr) { |
| return 0; |
| } |
| |
| int ucm_get_default_node_gain(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| long* gain) { |
| if (ucm_get_default_node_gain_values.find(dev) == |
| ucm_get_default_node_gain_values.end()) |
| return 1; |
| |
| *gain = ucm_get_default_node_gain_values[dev]; |
| return 0; |
| } |
| |
| int ucm_get_intrinsic_sensitivity(struct cras_use_case_mgr* mgr, |
| const char* dev, |
| long* vol) { |
| if (ucm_get_intrinsic_sensitivity_values.find(dev) == |
| ucm_get_intrinsic_sensitivity_values.end()) |
| return 1; |
| |
| *vol = ucm_get_intrinsic_sensitivity_values[dev]; |
| return 0; |
| } |
| |
| void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {} |
| |
| void cras_iodev_free_audio_area(struct cras_iodev* iodev) {} |
| |
| int cras_iodev_reset_rate_estimator(const struct cras_iodev* iodev) { |
| cras_iodev_reset_rate_estimator_called++; |
| return 0; |
| } |
| |
| int cras_iodev_frames_queued(struct cras_iodev* iodev, |
| struct timespec* tstamp) { |
| clock_gettime(CLOCK_MONOTONIC_RAW, tstamp); |
| return cras_iodev_frames_queued_ret; |
| } |
| |
| int cras_iodev_buffer_avail(struct cras_iodev* iodev, unsigned hw_level) { |
| return cras_iodev_buffer_avail_ret; |
| } |
| |
| int cras_iodev_fill_odev_zeros(struct cras_iodev* odev, unsigned int frames) { |
| cras_iodev_fill_odev_zeros_called++; |
| cras_iodev_fill_odev_zeros_frames = frames; |
| return 0; |
| } |
| |
| void cras_audio_area_config_buf_pointers(struct cras_audio_area* area, |
| const struct cras_audio_format* fmt, |
| uint8_t* base_buffer) {} |
| |
| void audio_thread_add_events_callback(int fd, |
| thread_callback cb, |
| void* data, |
| int events) { |
| audio_thread_cb = cb; |
| audio_thread_cb_data = data; |
| } |
| |
| void audio_thread_rm_callback(int fd) {} |
| |
| int audio_thread_rm_callback_sync(struct audio_thread* thread, int fd) { |
| return 0; |
| } |
| |
| int cras_hotword_send_triggered_msg() { |
| hotword_send_triggered_msg_called++; |
| return 0; |
| } |
| |
| int snd_pcm_poll_descriptors_count(snd_pcm_t* pcm) { |
| return 1; |
| } |
| |
| int snd_pcm_poll_descriptors(snd_pcm_t* pcm, |
| struct pollfd* pfds, |
| unsigned int space) { |
| if (space >= 1) { |
| pfds[0].events = POLLIN; |
| pfds[0].fd = 99; |
| } |
| return 0; |
| } |
| |
| int is_utf8_string(const char* string) { |
| return is_utf8_string_ret_value; |
| } |
| |
| int cras_alsa_mmap_get_whole_buffer(snd_pcm_t* handle, uint8_t** dst) { |
| snd_pcm_uframes_t offset, frames; |
| |
| cras_alsa_mmap_get_whole_buffer_called++; |
| return cras_alsa_mmap_begin(handle, 0, dst, &offset, &frames); |
| } |
| |
| int cras_alsa_resume_appl_ptr(snd_pcm_t* handle, snd_pcm_uframes_t ahead) { |
| cras_alsa_resume_appl_ptr_called++; |
| cras_alsa_resume_appl_ptr_ahead = ahead; |
| return 0; |
| } |
| |
| int cras_iodev_default_no_stream_playback(struct cras_iodev* odev, int enable) { |
| return 0; |
| } |
| |
| int cras_iodev_output_underrun(struct cras_iodev* odev, |
| unsigned int hw_level, |
| unsigned int frames_written) { |
| return odev->output_underrun(odev); |
| } |
| |
| enum CRAS_IODEV_STATE cras_iodev_state(const struct cras_iodev* iodev) { |
| return iodev->state; |
| } |
| |
| int cras_iodev_dsp_set_swap_mode_for_node(struct cras_iodev* iodev, |
| struct cras_ionode* node, |
| int enable) { |
| cras_iodev_dsp_set_swap_mode_for_node_called++; |
| return 0; |
| } |
| |
| struct cras_ramp* cras_ramp_create() { |
| return (struct cras_ramp*)0x1; |
| } |
| |
| // From librt. |
| int clock_gettime(clockid_t clk_id, struct timespec* tp) { |
| tp->tv_sec = clock_gettime_retspec.tv_sec; |
| tp->tv_nsec = clock_gettime_retspec.tv_nsec; |
| return 0; |
| } |
| |
| } // extern "C" |