| // 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 <map> |
| #include <stdio.h> |
| #include <syslog.h> |
| #include <vector> |
| |
| extern "C" { |
| |
| #include "cras_iodev.h" |
| #include "cras_shm.h" |
| #include "cras_system_state.h" |
| #include "cras_types.h" |
| #include "cras_alsa_mixer.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 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 sys_get_capture_gain_called; |
| static long sys_get_capture_gain_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 sys_set_capture_gain_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_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_attr_ionode; |
| static size_t cras_iodev_set_node_attr_called; |
| static enum ionode_attr cras_iodev_set_node_attr_attr; |
| static int cras_iodev_set_node_attr_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; |
| static size_t ucm_get_dsp_name_default_called; |
| static const char *ucm_get_dsp_name_default_value; |
| static size_t cras_alsa_jack_get_dsp_name_called; |
| static const char *cras_alsa_jack_get_dsp_name_value; |
| 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 int ucm_get_min_software_gain_called; |
| static int ucm_get_min_software_gain_ret_value; |
| static long ucm_get_min_software_gain_value; |
| static int ucm_get_max_software_gain_called; |
| static int ucm_get_max_software_gain_ret_value; |
| static long ucm_get_max_software_gain_value; |
| static long cras_system_set_capture_gain_limits_set_value[2]; |
| 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 int ucm_get_enable_htimestamp_flag_ret; |
| 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 thread_callback audio_thread_cb; |
| static void *audio_thread_cb_data; |
| static int hotword_send_triggered_msg_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; |
| sys_get_volume_called = 0; |
| sys_get_capture_gain_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; |
| sys_set_capture_gain_limits_called = 0; |
| sys_get_capture_gain_return_value = 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_attr_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_default_called = 0; |
| ucm_get_dsp_name_default_value = NULL; |
| cras_alsa_jack_get_dsp_name_called = 0; |
| cras_alsa_jack_get_dsp_name_value = NULL; |
| 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; |
| ucm_get_min_software_gain_called = 0; |
| ucm_get_min_software_gain_ret_value = -1; |
| ucm_get_min_software_gain_value = 0; |
| ucm_get_max_software_gain_called = 0; |
| ucm_get_max_software_gain_ret_value = -1; |
| ucm_get_max_software_gain_value = 0; |
| cras_card_config_get_volume_curve_for_control_called = 0; |
| cras_card_config_get_volume_curve_vals.clear(); |
| cras_system_set_capture_gain_limits_set_value[0] = -1; |
| cras_system_set_capture_gain_limits_set_value[1] = -1; |
| 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; |
| ucm_get_enable_htimestamp_flag_ret = 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(); |
| } |
| |
| 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_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); |
| EXPECT_EQ(0, 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(0, ucm_get_dsp_name_default_called); |
| EXPECT_EQ(NULL, 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 *)output_should_wake, (void *)aio->base.output_should_wake); |
| 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("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 *)output_should_wake, (void *)aio->base.output_should_wake); |
| 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 *)output_should_wake, (void *)aio->base.output_should_wake); |
| 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 Mic", 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 *)output_should_wake, (void *)aio->base.output_should_wake); |
| 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_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(1, cras_iodev_set_node_attr_value); |
| 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_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(1, cras_iodev_set_node_attr_value); |
| 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)); |
| 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->is_free_running = 1; |
| aio->filled_zeros_for_draining = 512; |
| 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, 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_attr_called); |
| EXPECT_EQ(0, aio->is_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_attr_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_attr_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_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(1, cras_iodev_set_node_attr_value); |
| 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, UseSoftwareGain) { |
| struct cras_iodev *iodev; |
| struct cras_use_case_mgr * const fake_ucm = (struct cras_use_case_mgr*)3; |
| |
| /* MaxSoftwareGain is specified in UCM */ |
| ResetStubData(); |
| ucm_get_min_software_gain_ret_value = 1; |
| ucm_get_min_software_gain_value = 1; |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| 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)); |
| EXPECT_EQ(1, iodev->active_node->software_volume_needed); |
| EXPECT_EQ(DEFAULT_MIN_CAPTURE_GAIN, iodev->active_node->min_software_gain); |
| EXPECT_EQ(2000, iodev->active_node->max_software_gain); |
| ASSERT_EQ(1, sys_set_capture_gain_limits_called); |
| /* The gain range is [DEFAULT_MIN_CAPTURE_GAIN, maximum software gain]. */ |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[0], |
| DEFAULT_MIN_CAPTURE_GAIN); |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[1], 2000); |
| |
| alsa_iodev_destroy(iodev); |
| |
| /* MaxSoftwareGain and MinSoftwareGain are specified in UCM. */ |
| ResetStubData(); |
| ucm_get_min_software_gain_ret_value = 0; |
| ucm_get_min_software_gain_value = 1000; |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| 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)); |
| EXPECT_EQ(1, iodev->active_node->software_volume_needed); |
| EXPECT_EQ(1000, iodev->active_node->min_software_gain); |
| EXPECT_EQ(2000, iodev->active_node->max_software_gain); |
| ASSERT_EQ(1, sys_set_capture_gain_limits_called); |
| /* The gain range is [minimum software gain, maximum software gain]. */ |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[0], 1000); |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[1], 2000); |
| |
| alsa_iodev_destroy(iodev); |
| |
| /* MinSoftwareGain is larger than MaxSoftwareGain in UCM. */ |
| ResetStubData(); |
| ucm_get_min_software_gain_ret_value = 0; |
| ucm_get_min_software_gain_value = 3000; |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| 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)); |
| EXPECT_EQ(1, iodev->active_node->software_volume_needed); |
| EXPECT_EQ(DEFAULT_MIN_CAPTURE_GAIN, iodev->active_node->min_software_gain); |
| EXPECT_EQ(2000, iodev->active_node->max_software_gain); |
| ASSERT_EQ(1, sys_set_capture_gain_limits_called); |
| /* The gain range is [DEFAULT_MIN_CAPTURE_GAIN, maximum software gain]. */ |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[0], |
| DEFAULT_MIN_CAPTURE_GAIN); |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[1], 2000); |
| |
| alsa_iodev_destroy(iodev); |
| |
| /* MaxSoftwareGain is not specified in UCM. */ |
| ResetStubData(); |
| ucm_get_max_software_gain_ret_value = 1; |
| ucm_get_max_software_gain_value = 1; |
| cras_alsa_mixer_get_minimum_capture_gain_ret_value = -500; |
| cras_alsa_mixer_get_maximum_capture_gain_ret_value = 500; |
| 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)); |
| EXPECT_EQ(0, iodev->active_node->software_volume_needed); |
| EXPECT_EQ(0, iodev->active_node->max_software_gain); |
| ASSERT_EQ(1, sys_set_capture_gain_limits_called); |
| /* The gain range is reported by controls. */ |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[0], -500); |
| ASSERT_EQ(cras_system_set_capture_gain_limits_set_value[1], 500); |
| |
| alsa_iodev_destroy(iodev); |
| } |
| |
| TEST(AlsaIoInit, SoftwareGainWithDefaultNodeGain) { |
| struct cras_iodev *iodev; |
| struct cras_use_case_mgr * const fake_ucm = (struct cras_use_case_mgr*)3; |
| long system_gain = 500; |
| long default_node_gain = -1000; |
| |
| ResetStubData(); |
| |
| // Use software gain. |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| |
| // Set default node gain to -1000 * 0.01 dB. |
| ucm_get_default_node_gain_values["Internal Mic"] = 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)); |
| |
| // Gain on node is 300 * 0.01 dB. |
| iodev->active_node->capture_gain = default_node_gain; |
| |
| // cras_iodev will call cras_iodev_adjust_active_node_gain to get gain for |
| // software gain. |
| ASSERT_EQ(system_gain + default_node_gain, |
| cras_iodev_adjust_active_node_gain(iodev, system_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); |
| EXPECT_EQ(0, 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_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(1, cras_iodev_set_node_attr_value); |
| cras_alsa_jack_list_create_cb(NULL, 0, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(2, cras_iodev_set_node_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(0, cras_iodev_set_node_attr_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); |
| EXPECT_EQ(0, 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_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(1, cras_iodev_set_node_attr_value); |
| cras_alsa_jack_list_create_cb(NULL, 0, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(2, cras_iodev_set_node_attr_called); |
| EXPECT_EQ(IONODE_ATTR_PLUGGED, cras_iodev_set_node_attr_attr); |
| EXPECT_EQ(0, cras_iodev_set_node_attr_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); |
| EXPECT_EQ(0, 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, sys_set_capture_gain_limits_called); |
| EXPECT_EQ(1, sys_get_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 system_gain = 2000; |
| long default_node_gain = -1000; |
| |
| ResetStubData(); |
| // Set default node gain to -1000 * 0.01 dB. |
| ucm_get_default_node_gain_values["Internal Mic"] = 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); |
| // System gain is set to 2000 * 0.01 dB. |
| sys_get_capture_gain_return_value = system_gain; |
| |
| iodev->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| // Hardware gain is set to (2000 - 1000) * 0.01 dB. |
| EXPECT_EQ(system_gain + default_node_gain, 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(); |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| |
| 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); |
| |
| /* System gain is set to 1000 * 0.01 dB */ |
| sys_get_capture_gain_return_value = 1000; |
| |
| 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->open_dev(iodev); |
| iodev->configure_dev(iodev); |
| iodev->close_dev(iodev); |
| |
| /* Hardware gain is set to 1000 * 0.01 dB as got from system capture gain.*/ |
| EXPECT_EQ(1000, alsa_mixer_set_capture_dBFS_value); |
| |
| 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(); |
| ucm_get_dsp_name_default_value = "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_default_called); |
| EXPECT_EQ(1, cras_alsa_jack_get_dsp_name_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; |
| |
| ResetStubData(); |
| ucm_get_dsp_name_default_value = "default_dsp"; |
| cras_alsa_jack_get_dsp_name_value = "override_dsp"; |
| 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_default_called); |
| EXPECT_EQ(1, cras_alsa_jack_get_dsp_name_called); |
| EXPECT_EQ(1, cras_iodev_update_dsp_called); |
| EXPECT_STREQ("default_dsp", cras_iodev_update_dsp_name); |
| |
| // Add the jack node. |
| cras_alsa_jack_list_create_cb(jack, 1, cras_alsa_jack_list_create_cb_data); |
| EXPECT_EQ(1, ucm_get_dsp_name_default_called); |
| |
| // Mark the jack node as active. |
| alsa_iodev_set_active_node(&aio->base, aio->base.nodes->next, 1); |
| EXPECT_EQ(2, cras_alsa_jack_get_dsp_name_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(1, ucm_get_dsp_name_default_called); |
| EXPECT_EQ(3, cras_alsa_jack_get_dsp_name_called); |
| EXPECT_EQ(3, cras_iodev_update_dsp_called); |
| EXPECT_STREQ("default_dsp", 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 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(2, 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", 0, 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", 0, 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_attr_ionode->name, "Headphone"); |
| |
| jack_output_plug_event(reinterpret_cast<struct cras_alsa_jack *>(20), 0, aio); |
| EXPECT_STREQ(cras_iodev_set_node_attr_ionode->name, "Line Out"); |
| |
| 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, 0, 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", 0, 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_attr_called); |
| |
| // Complete initialization, and make first node active. |
| 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); |
| |
| 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(2, 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_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_attr_called); |
| |
| 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, 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", 0, 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; |
| |
| 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 Mic"; |
| 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]; |
| ucm_get_max_software_gain_ret_value = -1; |
| section = ucm_section_create(INTERNAL_MICROPHONE, 0, 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; |
| ucm_get_max_software_gain_ret_value = 0; |
| ucm_get_max_software_gain_value = 2000; |
| 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", 0, 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 unkonwn 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_attr_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_attr_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(1, sys_set_capture_gain_limits_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, sys_set_capture_gain_limits_called); |
| EXPECT_EQ(1, alsa_mixer_set_capture_mute_called); |
| EXPECT_EQ(1, iodev->active_node->software_volume_needed); |
| EXPECT_EQ(2000, iodev->active_node->max_software_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, 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", 0, 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(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, "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 Mic"); |
| 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, "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_] = "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, |
| }; |
| |
| 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; |
| |
| // 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); |
| |
| // 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; |
| |
| aio_output_->num_underruns = 3; // Something non-zero. |
| 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.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.is_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; |
| // Device is not in free run state. There are still valid samples to play. |
| // The number of valid samples is less than min_cb_level * 2. |
| // Need to fill zeros targeting min_cb_level * 2 = 480. |
| // The number of zeros to be filled is 480 - 200 = 280. |
| 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(280, cras_iodev_fill_odev_zeros_frames); |
| EXPECT_EQ(280, aio.filled_zeros_for_draining); |
| EXPECT_EQ(0, aio.is_free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, EnterFreeRunNotDrainedYetNoNeedToFillZeros) { |
| 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 more than min_cb_level * 2. |
| // No need to fill zeros. |
| real_hw_level = 500; |
| 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(0, cras_iodev_fill_odev_zeros_called); |
| EXPECT_EQ(0, aio.is_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.is_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.is_free_running); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, OutputShouldWake) { |
| |
| aio.is_free_running = 1; |
| |
| EXPECT_EQ(0, output_should_wake(&aio.base)); |
| |
| aio.is_free_running = 0; |
| aio.base.state = CRAS_IODEV_STATE_NO_STREAM_RUN; |
| EXPECT_EQ(1, output_should_wake(&aio.base)); |
| |
| aio.base.state = CRAS_IODEV_STATE_NORMAL_RUN; |
| EXPECT_EQ(1, output_should_wake(&aio.base)); |
| |
| aio.base.state = CRAS_IODEV_STATE_OPEN; |
| EXPECT_EQ(0, output_should_wake(&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.is_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.is_free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| } |
| |
| 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.is_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.is_free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| } |
| |
| TEST_F(AlsaFreeRunTestSuite, LeaveFreeRunInFreeRun) { |
| int rc; |
| |
| aio.is_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.is_free_running); |
| EXPECT_EQ(0, aio.filled_zeros_for_draining); |
| } |
| |
| // Reuse AlsaFreeRunTestSuite for output underrun handling because they are |
| // similar. |
| TEST_F(AlsaFreeRunTestSuite, OutputUnderrun) { |
| int rc; |
| int16_t *zeros; |
| |
| aio.num_underruns = 0; |
| |
| // Ask alsa_io to handle output underrun. |
| rc = alsa_output_underrun(&aio.base); |
| EXPECT_EQ(0, rc); |
| EXPECT_EQ(1, aio.num_underruns); |
| |
| // 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 + min_cb_level ahead of |
| // hw_ptr. |
| 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); |
| |
| 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, "Wake on Voice"); |
| 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); |
| EXPECT_EQ(1, hotword_send_triggered_msg_called); |
| 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; |
| *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, int *enable_htimestamp) |
| { |
| 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; |
| } |
| |
| long cras_system_get_capture_gain() |
| { |
| sys_get_capture_gain_called++; |
| return sys_get_capture_gain_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++; |
| } |
| |
| void cras_system_set_capture_gain_limits(long min, long max) |
| { |
| cras_system_set_capture_gain_limits_set_value[0] = min; |
| cras_system_set_capture_gain_limits_set_value[1] = max; |
| sys_set_capture_gain_limits_called++; |
| } |
| |
| // 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 *cras_alsa_jack_get_dsp_name(const struct cras_alsa_jack *jack) |
| { |
| cras_alsa_jack_get_dsp_name_called++; |
| return jack ? cras_alsa_jack_get_dsp_name_value : NULL; |
| } |
| |
| const char *ucm_get_dsp_name_default(struct cras_use_case_mgr *mgr, |
| int direction) |
| { |
| ucm_get_dsp_name_default_called++; |
| if (ucm_get_dsp_name_default_value) |
| return strdup(ucm_get_dsp_name_default_value); |
| else |
| return NULL; |
| } |
| |
| 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; |
| } |
| |
| char *ucm_get_mic_positions(struct cras_use_case_mgr *mgr) { |
| 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_enable_htimestamp_flag(struct cras_use_case_mgr *mgr) |
| { |
| return ucm_get_enable_htimestamp_flag_ret; |
| } |
| |
| unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr *mgr) |
| { |
| return 0; |
| } |
| |
| int ucm_get_min_software_gain(struct cras_use_case_mgr *mgr, const char *dev, |
| long *gain) |
| { |
| ucm_get_min_software_gain_called++; |
| *gain = ucm_get_min_software_gain_value; |
| return ucm_get_min_software_gain_ret_value; |
| } |
| |
| int ucm_get_max_software_gain(struct cras_use_case_mgr *mgr, const char *dev, |
| long *gain) |
| { |
| ucm_get_max_software_gain_called++; |
| *gain = ucm_get_max_software_gain_value; |
| return ucm_get_max_software_gain_ret_value; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| int cras_iodev_set_node_attr(struct cras_ionode *ionode, |
| enum ionode_attr attr, int value) |
| { |
| cras_iodev_set_node_attr_called++; |
| cras_iodev_set_node_attr_ionode = ionode; |
| cras_iodev_set_node_attr_attr = attr; |
| cras_iodev_set_node_attr_value = value; |
| if (ionode && (attr == IONODE_ATTR_PLUGGED)) |
| ionode->plugged = value; |
| return 0; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| 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) |
| { |
| 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_callback(int fd, thread_callback cb, void *data) |
| { |
| 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; |
| } |
| |
| 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; |
| } |
| |
| } |