| // Copyright (c) 2014 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> |
| |
| extern "C" { |
| |
| // To test static functions. |
| #include "cras_bt_io.c" |
| #include "utlist.h" |
| } |
| |
| static struct cras_bt_device* fake_device = |
| reinterpret_cast<struct cras_bt_device*>(0x123); |
| static unsigned int cras_iodev_add_node_called; |
| static unsigned int cras_iodev_rm_node_called; |
| static unsigned int cras_iodev_free_format_called; |
| static unsigned int cras_iodev_free_resources_called; |
| static unsigned int cras_iodev_set_active_node_called; |
| static unsigned int cras_iodev_list_add_output_called; |
| static unsigned int cras_iodev_list_rm_output_called; |
| static unsigned int cras_iodev_list_add_input_called; |
| static unsigned int cras_iodev_list_rm_input_called; |
| static unsigned int cras_bt_device_set_active_profile_called; |
| static unsigned int cras_bt_device_set_active_profile_val; |
| static int cras_bt_device_get_active_profile_ret; |
| static int cras_bt_device_switch_profile_enable_dev_called; |
| static int cras_bt_device_switch_profile_called; |
| static int cras_bt_device_can_switch_to_a2dp_ret; |
| static int cras_bt_device_has_a2dp_ret; |
| static int is_utf8_string_ret_value; |
| |
| void ResetStubData() { |
| cras_iodev_add_node_called = 0; |
| cras_iodev_rm_node_called = 0; |
| cras_iodev_free_format_called = 0; |
| cras_iodev_free_resources_called = 0; |
| cras_iodev_set_active_node_called = 0; |
| cras_iodev_list_add_output_called = 0; |
| cras_iodev_list_rm_output_called = 0; |
| cras_iodev_list_add_input_called = 0; |
| cras_iodev_list_rm_input_called = 0; |
| cras_bt_device_set_active_profile_called = 0; |
| cras_bt_device_set_active_profile_val = 0; |
| cras_bt_device_get_active_profile_ret = 0; |
| cras_bt_device_switch_profile_enable_dev_called = 0; |
| cras_bt_device_switch_profile_called = 0; |
| cras_bt_device_can_switch_to_a2dp_ret = 0; |
| cras_bt_device_has_a2dp_ret = 0; |
| is_utf8_string_ret_value = 1; |
| } |
| |
| namespace { |
| |
| class BtIoBasicSuite : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| ResetStubData(); |
| SetUpIodev(&iodev_, CRAS_STREAM_OUTPUT); |
| SetUpIodev(&iodev2_, CRAS_STREAM_OUTPUT); |
| iodev_.active_node = &node_; |
| iodev2_.active_node = &node2_; |
| |
| update_supported_formats_called_ = 0; |
| frames_queued_called_ = 0; |
| delay_frames_called_ = 0; |
| get_buffer_called_ = 0; |
| put_buffer_called_ = 0; |
| configure_dev_called_ = 0; |
| close_dev_called_ = 0; |
| } |
| |
| virtual void TearDown() {} |
| |
| static void SetUpIodev(struct cras_iodev* d, enum CRAS_STREAM_DIRECTION dir) { |
| d->direction = dir; |
| d->update_supported_formats = update_supported_formats; |
| d->frames_queued = frames_queued; |
| d->delay_frames = delay_frames; |
| d->get_buffer = get_buffer; |
| d->put_buffer = put_buffer; |
| d->configure_dev = configure_dev; |
| d->close_dev = close_dev; |
| d->supported_rates = NULL; |
| d->supported_channel_counts = NULL; |
| d->supported_formats = NULL; |
| } |
| |
| // Stub functions for the iodev structure. |
| static int update_supported_formats(struct cras_iodev* iodev) { |
| free(iodev->supported_rates); |
| free(iodev->supported_channel_counts); |
| free(iodev->supported_formats); |
| iodev->supported_rates = |
| (size_t*)calloc(2, sizeof(*iodev->supported_rates)); |
| iodev->supported_rates[0] = 48000; |
| iodev->supported_rates[1] = 0; |
| iodev->supported_channel_counts = |
| (size_t*)calloc(2, sizeof(*iodev->supported_channel_counts)); |
| iodev->supported_channel_counts[0] = 2; |
| iodev->supported_channel_counts[1] = 0; |
| iodev->supported_formats = |
| (snd_pcm_format_t*)calloc(2, sizeof(*iodev->supported_formats)); |
| iodev->supported_formats[0] = SND_PCM_FORMAT_S16_LE; |
| iodev->supported_formats[1] = (snd_pcm_format_t)0; |
| update_supported_formats_called_++; |
| return 0; |
| } |
| static int frames_queued(const cras_iodev* iodev, struct timespec* tstamp) { |
| frames_queued_called_++; |
| return 0; |
| } |
| static int delay_frames(const cras_iodev* iodev) { |
| delay_frames_called_++; |
| return 0; |
| } |
| static int get_buffer(cras_iodev* iodev, |
| struct cras_audio_area** area, |
| unsigned int* num) { |
| get_buffer_called_++; |
| return 0; |
| } |
| static int put_buffer(cras_iodev* iodev, unsigned int num) { |
| put_buffer_called_++; |
| return 0; |
| } |
| static int configure_dev(cras_iodev* iodev) { |
| configure_dev_called_++; |
| return 0; |
| } |
| static int close_dev(cras_iodev* iodev) { |
| free(iodev->format); |
| iodev->format = NULL; |
| close_dev_called_++; |
| return 0; |
| } |
| |
| static struct cras_iodev* bt_iodev; |
| static struct cras_iodev iodev_; |
| static struct cras_iodev iodev2_; |
| static struct cras_ionode node_; |
| static struct cras_ionode node2_; |
| static unsigned int update_supported_formats_called_; |
| static unsigned int frames_queued_called_; |
| static unsigned int delay_frames_called_; |
| static unsigned int get_buffer_called_; |
| static unsigned int put_buffer_called_; |
| static unsigned int configure_dev_called_; |
| static unsigned int close_dev_called_; |
| }; |
| |
| struct cras_iodev* BtIoBasicSuite::bt_iodev; |
| struct cras_iodev BtIoBasicSuite::iodev_; |
| struct cras_iodev BtIoBasicSuite::iodev2_; |
| struct cras_ionode BtIoBasicSuite::node_; |
| struct cras_ionode BtIoBasicSuite::node2_; |
| unsigned int BtIoBasicSuite::update_supported_formats_called_; |
| unsigned int BtIoBasicSuite::frames_queued_called_; |
| unsigned int BtIoBasicSuite::delay_frames_called_; |
| unsigned int BtIoBasicSuite::get_buffer_called_; |
| unsigned int BtIoBasicSuite::put_buffer_called_; |
| unsigned int BtIoBasicSuite::configure_dev_called_; |
| unsigned int BtIoBasicSuite::close_dev_called_; |
| |
| TEST_F(BtIoBasicSuite, CreateBtIo) { |
| struct cras_audio_area* fake_area; |
| struct cras_audio_format fake_fmt; |
| struct timespec tstamp; |
| unsigned fr; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| EXPECT_NE((void*)NULL, bt_iodev); |
| EXPECT_EQ(&iodev_, active_profile_dev(bt_iodev)); |
| EXPECT_EQ(1, cras_iodev_list_add_output_called); |
| bt_iodev->open_dev(bt_iodev); |
| bt_iodev->format = &fake_fmt; |
| bt_iodev->update_supported_formats(bt_iodev); |
| EXPECT_EQ(1, update_supported_formats_called_); |
| |
| bt_iodev->state = CRAS_IODEV_STATE_OPEN; |
| bt_iodev->configure_dev(bt_iodev); |
| EXPECT_EQ(1, configure_dev_called_); |
| bt_iodev->frames_queued(bt_iodev, &tstamp); |
| EXPECT_EQ(1, frames_queued_called_); |
| bt_iodev->get_buffer(bt_iodev, &fake_area, &fr); |
| EXPECT_EQ(1, get_buffer_called_); |
| bt_iodev->put_buffer(bt_iodev, fr); |
| EXPECT_EQ(1, put_buffer_called_); |
| bt_iodev->close_dev(bt_iodev); |
| EXPECT_EQ(1, close_dev_called_); |
| EXPECT_EQ(1, cras_iodev_free_format_called); |
| cras_bt_io_destroy(bt_iodev); |
| EXPECT_EQ(1, cras_iodev_free_resources_called); |
| EXPECT_EQ(1, cras_iodev_list_rm_output_called); |
| |
| free(iodev_.supported_rates); |
| free(iodev_.supported_channel_counts); |
| free(iodev_.supported_formats); |
| } |
| |
| TEST_F(BtIoBasicSuite, SwitchProfileOnOpenDevForInputDev) { |
| ResetStubData(); |
| iodev_.direction = CRAS_STREAM_INPUT; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| |
| cras_bt_device_get_active_profile_ret = CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE; |
| bt_iodev->open_dev(bt_iodev); |
| |
| EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY | |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY, |
| cras_bt_device_set_active_profile_val); |
| EXPECT_EQ(1, cras_bt_device_switch_profile_enable_dev_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, NoSwitchProfileOnOpenDevForInputDevAlreadyOnHfp) { |
| ResetStubData(); |
| iodev_.direction = CRAS_STREAM_INPUT; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| |
| /* No need to switch profile if already on HFP. */ |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY; |
| bt_iodev->open_dev(bt_iodev); |
| |
| EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, SwitchProfileOnCloseInputDev) { |
| ResetStubData(); |
| iodev_.direction = CRAS_STREAM_INPUT; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| bt_iodev->state = CRAS_IODEV_STATE_OPEN; |
| |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY | |
| CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY; |
| cras_bt_device_has_a2dp_ret = 1; |
| bt_iodev->close_dev(bt_iodev); |
| |
| EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE, |
| cras_bt_device_set_active_profile_val); |
| EXPECT_EQ(1, cras_bt_device_switch_profile_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, NoSwitchProfileOnCloseInputDevNoSupportA2dp) { |
| ResetStubData(); |
| iodev_.direction = CRAS_STREAM_INPUT; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| bt_iodev->state = CRAS_IODEV_STATE_OPEN; |
| |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY | |
| CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY; |
| cras_bt_device_has_a2dp_ret = 0; |
| bt_iodev->close_dev(bt_iodev); |
| |
| EXPECT_EQ(0, cras_bt_device_switch_profile_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, NoSwitchProfileOnCloseInputDevInCloseState) { |
| ResetStubData(); |
| iodev_.direction = CRAS_STREAM_INPUT; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| bt_iodev->state = CRAS_IODEV_STATE_CLOSE; |
| |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY | |
| CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY; |
| cras_bt_device_has_a2dp_ret = 1; |
| bt_iodev->close_dev(bt_iodev); |
| |
| EXPECT_EQ(0, cras_bt_device_switch_profile_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, SwitchProfileOnAppendA2dpDev) { |
| ResetStubData(); |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| |
| cras_bt_device_can_switch_to_a2dp_ret = 1; |
| cras_bt_io_append(bt_iodev, &iodev2_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| |
| EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE, |
| cras_bt_device_set_active_profile_val); |
| EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called); |
| EXPECT_EQ(1, cras_bt_device_switch_profile_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, NoSwitchProfileOnAppendHfpDev) { |
| ResetStubData(); |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| |
| cras_bt_device_can_switch_to_a2dp_ret = 1; |
| cras_bt_io_append(bt_iodev, &iodev2_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| |
| EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, CreateSetDeviceActiveProfileToA2DP) { |
| ResetStubData(); |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY; |
| cras_bt_device_can_switch_to_a2dp_ret = 1; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| |
| EXPECT_EQ(1, cras_bt_device_set_active_profile_called); |
| EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE, |
| cras_bt_device_set_active_profile_val); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, CreateNoSetDeviceActiveProfileToA2DP) { |
| ResetStubData(); |
| cras_bt_device_get_active_profile_ret = |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY; |
| cras_bt_device_can_switch_to_a2dp_ret = 0; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| |
| EXPECT_EQ(0, cras_bt_device_set_active_profile_called); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, CreateSetDeviceActiveProfileToHFP) { |
| ResetStubData(); |
| cras_bt_device_get_active_profile_ret = 0; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); |
| |
| EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY | |
| CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY, |
| cras_bt_device_set_active_profile_val); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| TEST_F(BtIoBasicSuite, CreateDeviceWithInvalidUTF8Name) { |
| ResetStubData(); |
| strcpy(iodev_.info.name, "Something BT"); |
| iodev_.info.name[0] = 0xfe; |
| is_utf8_string_ret_value = 0; |
| bt_iodev = cras_bt_io_create(fake_device, &iodev_, |
| CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); |
| |
| ASSERT_STREQ("BLUETOOTH", bt_iodev->active_node->name); |
| cras_bt_io_destroy(bt_iodev); |
| } |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |
| |
| extern "C" { |
| |
| // Cras iodev |
| 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) { |
| cras_iodev_rm_node_called++; |
| DL_DELETE(iodev->nodes, node); |
| } |
| |
| void cras_iodev_free_format(struct cras_iodev* iodev) { |
| cras_iodev_free_format_called++; |
| } |
| |
| void cras_iodev_set_active_node(struct cras_iodev* iodev, |
| struct cras_ionode* node) { |
| cras_iodev_set_active_node_called++; |
| iodev->active_node = node; |
| } |
| |
| int cras_iodev_set_node_attr(struct cras_ionode* ionode, |
| enum ionode_attr attr, |
| int value) { |
| return 0; |
| } |
| |
| void cras_iodev_free_resources(struct cras_iodev* iodev) { |
| cras_iodev_free_resources_called++; |
| } |
| |
| // From iodev list. |
| int cras_iodev_list_add_output(struct cras_iodev* output) { |
| cras_iodev_list_add_output_called++; |
| return 0; |
| } |
| |
| int cras_iodev_list_rm_output(struct cras_iodev* dev) { |
| cras_iodev_list_rm_output_called++; |
| return 0; |
| } |
| |
| int cras_iodev_list_add_input(struct cras_iodev* output) { |
| cras_iodev_list_add_input_called++; |
| return 0; |
| } |
| |
| int cras_iodev_list_rm_input(struct cras_iodev* dev) { |
| cras_iodev_list_rm_input_called++; |
| return 0; |
| } |
| |
| // From bt device |
| unsigned int cras_bt_device_get_active_profile( |
| const struct cras_bt_device* device) { |
| return cras_bt_device_get_active_profile_ret; |
| } |
| |
| void cras_bt_device_set_active_profile(struct cras_bt_device* device, |
| unsigned int profile) { |
| cras_bt_device_set_active_profile_called++; |
| cras_bt_device_set_active_profile_val = profile; |
| } |
| |
| int cras_bt_device_has_a2dp(struct cras_bt_device* device) { |
| return cras_bt_device_has_a2dp_ret; |
| } |
| |
| int cras_bt_device_can_switch_to_a2dp(struct cras_bt_device* device) { |
| return cras_bt_device_can_switch_to_a2dp_ret; |
| } |
| |
| int cras_bt_device_switch_profile(struct cras_bt_device* device, |
| struct cras_iodev* bt_iodev) { |
| cras_bt_device_switch_profile_called++; |
| return 0; |
| } |
| |
| int cras_bt_device_switch_profile_enable_dev(struct cras_bt_device* device, |
| struct cras_iodev* bt_iodev) { |
| cras_bt_device_switch_profile_enable_dev_called++; |
| return 0; |
| } |
| |
| const char* cras_bt_device_object_path(const struct cras_bt_device* device) { |
| return "/fake/object/path"; |
| } |
| |
| int cras_bt_device_get_stable_id(const struct cras_bt_device* device) { |
| return 123; |
| } |
| |
| int cras_bt_device_get_use_hardware_volume(struct cras_bt_device* device) { |
| return 1; |
| } |
| |
| int is_utf8_string(const char* string) { |
| return is_utf8_string_ret_value; |
| } |
| |
| int cras_iodev_default_no_stream_playback(struct cras_iodev* odev, int enable) { |
| return 0; |
| } |
| |
| int cras_iodev_frames_queued(struct cras_iodev* iodev, |
| struct timespec* hw_tstamp) { |
| return 0; |
| } |
| |
| unsigned int cras_iodev_default_frames_to_play_in_sleep( |
| struct cras_iodev* odev, |
| unsigned int* hw_level, |
| struct timespec* hw_tstamp) { |
| return 0; |
| } |
| |
| int hfp_iodev_is_hsp(struct cras_iodev* iodev) { |
| return 0; |
| } |
| |
| } // extern "C" |