blob: ee013cf3f811a676167d595acc0e18795bd377ea [file] [log] [blame]
// 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_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"