a2dp_iodev_unittest.cc revision 5c890457a82d673cd0ab619d6b506a1fbea630eb
1// Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stdio.h> 6#include <stdint.h> 7#include <gtest/gtest.h> 8 9extern "C" { 10 11#include "a2dp-codecs.h" 12#include "cras_audio_area.h" 13#include "audio_thread.h" 14#include "audio_thread_log.h" 15#include "cras_bt_transport.h" 16#include "cras_iodev.h" 17 18#include "cras_a2dp_iodev.h" 19} 20 21#define FAKE_OBJECT_PATH "/fake/obj/path" 22 23#define MAX_A2DP_ENCODE_CALLS 2 24#define MAX_A2DP_WRITE_CALLS 4 25 26static struct cras_bt_transport *fake_transport; 27static cras_audio_format format; 28static size_t cras_bt_device_append_iodev_called; 29static size_t cras_bt_device_rm_iodev_called; 30static size_t cras_iodev_add_node_called; 31static size_t cras_iodev_rm_node_called; 32static size_t cras_iodev_set_active_node_called; 33static size_t cras_bt_transport_acquire_called; 34static size_t cras_bt_transport_configuration_called; 35static size_t cras_bt_transport_release_called; 36static size_t init_a2dp_called; 37static int init_a2dp_return_val; 38static size_t destroy_a2dp_called; 39static size_t drain_a2dp_called; 40static size_t a2dp_block_size_called; 41static size_t a2dp_queued_frames_val; 42static size_t cras_iodev_free_format_called; 43static size_t cras_iodev_free_resources_called; 44static int pcm_buf_size_val[MAX_A2DP_ENCODE_CALLS]; 45static unsigned int a2dp_encode_processed_bytes_val[MAX_A2DP_ENCODE_CALLS]; 46static unsigned int a2dp_encode_index; 47static int a2dp_write_return_val[MAX_A2DP_WRITE_CALLS]; 48static unsigned int a2dp_write_index; 49static cras_audio_area *dummy_audio_area; 50static thread_callback write_callback; 51static void *write_callback_data; 52static const char *fake_device_name = "fake device name"; 53static const char *cras_bt_device_name_ret; 54static unsigned int cras_bt_transport_write_mtu_ret; 55 56void ResetStubData() { 57 cras_bt_device_append_iodev_called = 0; 58 cras_bt_device_rm_iodev_called = 0; 59 cras_iodev_add_node_called = 0; 60 cras_iodev_rm_node_called = 0; 61 cras_iodev_set_active_node_called = 0; 62 cras_bt_transport_acquire_called = 0; 63 cras_bt_transport_configuration_called = 0; 64 cras_bt_transport_release_called = 0; 65 init_a2dp_called = 0; 66 init_a2dp_return_val = 0; 67 destroy_a2dp_called = 0; 68 drain_a2dp_called = 0; 69 a2dp_block_size_called = 0; 70 a2dp_queued_frames_val = 0; 71 cras_iodev_free_format_called = 0; 72 cras_iodev_free_resources_called = 0; 73 memset(a2dp_encode_processed_bytes_val, 0, 74 sizeof(a2dp_encode_processed_bytes_val)); 75 a2dp_encode_index = 0; 76 a2dp_write_index = 0; 77 cras_bt_transport_write_mtu_ret = 800; 78 79 fake_transport = reinterpret_cast<struct cras_bt_transport *>(0x123); 80 81 if (!dummy_audio_area) { 82 dummy_audio_area = (cras_audio_area*)calloc(1, 83 sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2); 84 } 85 86 write_callback = NULL; 87} 88 89int iodev_set_format(struct cras_iodev *iodev, 90 struct cras_audio_format *fmt) 91{ 92 fmt->format = SND_PCM_FORMAT_S16_LE; 93 fmt->num_channels = 2; 94 fmt->frame_rate = 44100; 95 iodev->format = fmt; 96 return 0; 97} 98 99namespace { 100 101static struct timespec time_now; 102 103TEST(A2dpIoInit, InitializeA2dpIodev) { 104 struct cras_iodev *iodev; 105 106 atlog = (audio_thread_event_log *)calloc(1, sizeof(audio_thread_event_log)); 107 108 ResetStubData(); 109 110 cras_bt_device_name_ret = NULL; 111 iodev = a2dp_iodev_create(fake_transport); 112 113 ASSERT_NE(iodev, (void *)NULL); 114 ASSERT_EQ(iodev->direction, CRAS_STREAM_OUTPUT); 115 ASSERT_EQ(1, cras_bt_transport_configuration_called); 116 ASSERT_EQ(1, init_a2dp_called); 117 ASSERT_EQ(1, cras_bt_device_append_iodev_called); 118 ASSERT_EQ(1, cras_iodev_add_node_called); 119 ASSERT_EQ(1, cras_iodev_set_active_node_called); 120 121 /* Assert iodev name matches the object path when bt device doesn't 122 * have its readable name populated. */ 123 ASSERT_STREQ(FAKE_OBJECT_PATH, iodev->info.name); 124 125 a2dp_iodev_destroy(iodev); 126 127 ASSERT_EQ(1, cras_bt_device_rm_iodev_called); 128 ASSERT_EQ(1, cras_iodev_rm_node_called); 129 ASSERT_EQ(1, destroy_a2dp_called); 130 ASSERT_EQ(1, cras_iodev_free_resources_called); 131 132 cras_bt_device_name_ret = fake_device_name; 133 /* Assert iodev name matches the bt device's name */ 134 iodev = a2dp_iodev_create(fake_transport); 135 ASSERT_STREQ(fake_device_name, iodev->info.name); 136 137 a2dp_iodev_destroy(iodev); 138} 139 140TEST(A2dpIoInit, InitializeFail) { 141 struct cras_iodev *iodev; 142 143 ResetStubData(); 144 145 init_a2dp_return_val = -1; 146 iodev = a2dp_iodev_create(fake_transport); 147 148 ASSERT_EQ(iodev, (void *)NULL); 149 ASSERT_EQ(1, cras_bt_transport_configuration_called); 150 ASSERT_EQ(1, init_a2dp_called); 151 ASSERT_EQ(0, cras_bt_device_append_iodev_called); 152 ASSERT_EQ(0, cras_iodev_add_node_called); 153 ASSERT_EQ(0, cras_iodev_set_active_node_called); 154 ASSERT_EQ(0, cras_iodev_rm_node_called); 155} 156 157TEST(A2dpIoInit, OpenIodev) { 158 struct cras_iodev *iodev; 159 160 ResetStubData(); 161 iodev = a2dp_iodev_create(fake_transport); 162 163 iodev_set_format(iodev, &format); 164 iodev->open_dev(iodev); 165 166 ASSERT_EQ(1, cras_bt_transport_acquire_called); 167 168 iodev->close_dev(iodev); 169 ASSERT_EQ(1, cras_bt_transport_release_called); 170 ASSERT_EQ(1, drain_a2dp_called); 171 ASSERT_EQ(1, cras_iodev_free_format_called); 172 173 a2dp_iodev_destroy(iodev); 174} 175 176TEST(A2dpIoInit, GetPutBuffer) { 177 struct cras_iodev *iodev; 178 struct cras_audio_area *area1, *area2, *area3; 179 uint8_t *area1_buf; 180 unsigned frames; 181 182 ResetStubData(); 183 iodev = a2dp_iodev_create(fake_transport); 184 185 iodev_set_format(iodev, &format); 186 iodev->open_dev(iodev); 187 ASSERT_NE(write_callback, (void *)NULL); 188 189 frames = 256; 190 iodev->get_buffer(iodev, &area1, &frames); 191 ASSERT_EQ(256, frames); 192 ASSERT_EQ(256, area1->frames); 193 area1_buf = area1->channels[0].buf; 194 195 /* Test 100 frames(400 bytes) put and all processed. */ 196 a2dp_encode_processed_bytes_val[0] = 4096 * 4; 197 a2dp_encode_processed_bytes_val[1] = 400; 198 a2dp_write_index = 0; 199 a2dp_write_return_val[0] = -EAGAIN; 200 a2dp_write_return_val[1] = 400; 201 iodev->put_buffer(iodev, 100); 202 write_callback(write_callback_data); 203 // Start with 4k frames. 204 EXPECT_EQ(4096, pcm_buf_size_val[0]); 205 EXPECT_EQ(400, pcm_buf_size_val[1]); 206 207 iodev->get_buffer(iodev, &area2, &frames); 208 ASSERT_EQ(256, frames); 209 ASSERT_EQ(256, area2->frames); 210 211 /* Assert buf2 points to the same position as buf1 */ 212 ASSERT_EQ(400, area2->channels[0].buf - area1_buf); 213 214 /* Test 100 frames(400 bytes) put, only 360 bytes processed, 215 * 40 bytes left in pcm buffer. 216 */ 217 a2dp_encode_index = 0; 218 a2dp_encode_processed_bytes_val[0] = 360; 219 a2dp_encode_processed_bytes_val[1] = 0; 220 a2dp_write_index = 0; 221 a2dp_write_return_val[0] = 360; 222 a2dp_write_return_val[1] = 0; 223 iodev->put_buffer(iodev, 100); 224 write_callback(write_callback_data); 225 EXPECT_EQ(400, pcm_buf_size_val[0]); 226 ASSERT_EQ(40, pcm_buf_size_val[1]); 227 228 iodev->get_buffer(iodev, &area3, &frames); 229 230 /* Existing buffer not completed processed, assert new buffer starts from 231 * current write pointer. 232 */ 233 ASSERT_EQ(256, frames); 234 EXPECT_EQ(800, area3->channels[0].buf - area1_buf); 235 236 a2dp_iodev_destroy(iodev); 237} 238 239TEST(A2dpIoInif, FramesQueued) { 240 struct cras_iodev *iodev; 241 struct cras_audio_area *area; 242 unsigned frames; 243 244 ResetStubData(); 245 iodev = a2dp_iodev_create(fake_transport); 246 247 iodev_set_format(iodev, &format); 248 time_now.tv_sec = 0; 249 time_now.tv_nsec = 0; 250 iodev->open_dev(iodev); 251 ASSERT_NE(write_callback, (void *)NULL); 252 253 frames = 256; 254 iodev->get_buffer(iodev, &area, &frames); 255 ASSERT_EQ(256, frames); 256 ASSERT_EQ(256, area->frames); 257 258 /* Put 100 frames, proccessed 400 bytes to a2dp buffer. 259 * Assume 200 bytes written out, queued 50 frames in a2dp buffer. 260 */ 261 a2dp_encode_processed_bytes_val[0] = 400; 262 a2dp_encode_processed_bytes_val[1] = 0; 263 a2dp_write_return_val[0] = 200; 264 a2dp_write_return_val[1] = -EAGAIN; 265 a2dp_queued_frames_val = 50; 266 time_now.tv_sec = 0; 267 time_now.tv_nsec = 1000000; 268 iodev->put_buffer(iodev, 300); 269 write_callback(write_callback_data); 270 EXPECT_EQ(350, iodev->frames_queued(iodev)); 271 272 /* After writing another 200 frames, check for correct buffer level. */ 273 time_now.tv_sec = 0; 274 time_now.tv_nsec = 2000000; 275 a2dp_encode_index = 0; 276 a2dp_write_index = 0; 277 a2dp_encode_processed_bytes_val[0] = 800; 278 write_callback(write_callback_data); 279 /* 1000000 nsec has passed, estimated queued frames adjusted by 44 */ 280 EXPECT_EQ(256, iodev->frames_queued(iodev)); 281 EXPECT_EQ(1200, pcm_buf_size_val[0]); 282 EXPECT_EQ(400, pcm_buf_size_val[1]); 283 284 /* Queued frames and new put buffer are all written */ 285 a2dp_encode_processed_bytes_val[0] = 400; 286 a2dp_encode_processed_bytes_val[1] = 0; 287 a2dp_encode_index = 0; 288 a2dp_write_return_val[0] = 400; 289 a2dp_write_return_val[1] = -EAGAIN; 290 a2dp_write_index = 0; 291 292 /* Add wnother 200 samples, get back to the original level. */ 293 time_now.tv_sec = 0; 294 time_now.tv_nsec = 50000000; 295 a2dp_encode_processed_bytes_val[0] = 600; 296 iodev->put_buffer(iodev, 200); 297 EXPECT_EQ(1200, pcm_buf_size_val[0]); 298 EXPECT_EQ(200, iodev->frames_queued(iodev)); 299} 300 301} // namespace 302 303int main(int argc, char **argv) { 304 ::testing::InitGoogleTest(&argc, argv); 305 return RUN_ALL_TESTS(); 306} 307 308extern "C" { 309 310int cras_bt_transport_configuration(const struct cras_bt_transport *transport, 311 void *configuration, int len) 312{ 313 cras_bt_transport_configuration_called++; 314 return 0; 315} 316 317int cras_bt_transport_acquire(struct cras_bt_transport *transport) 318{ 319 cras_bt_transport_acquire_called++; 320 return 0; 321} 322 323int cras_bt_transport_release(struct cras_bt_transport *transport) 324{ 325 cras_bt_transport_release_called++; 326 return 0; 327} 328 329int cras_bt_transport_fd(const struct cras_bt_transport *transport) 330{ 331 return 0; 332} 333 334const char *cras_bt_transport_object_path( 335 const struct cras_bt_transport *transport) 336{ 337 return FAKE_OBJECT_PATH; 338} 339 340uint16_t cras_bt_transport_write_mtu(const struct cras_bt_transport *transport) 341{ 342 return cras_bt_transport_write_mtu_ret; 343} 344 345 346void cras_iodev_free_format(struct cras_iodev *iodev) 347{ 348 cras_iodev_free_format_called++; 349} 350 351void cras_iodev_free_resources(struct cras_iodev *iodev) 352{ 353 cras_iodev_free_resources_called++; 354} 355 356// Cras iodev 357void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node) 358{ 359 cras_iodev_add_node_called++; 360 iodev->nodes = node; 361} 362 363void cras_iodev_rm_node(struct cras_iodev *iodev, struct cras_ionode *node) 364{ 365 cras_iodev_rm_node_called++; 366 iodev->nodes = NULL; 367} 368 369void cras_iodev_set_active_node(struct cras_iodev *iodev, 370 struct cras_ionode *node) 371{ 372 cras_iodev_set_active_node_called++; 373 iodev->active_node = node; 374} 375 376// From cras_bt_transport 377struct cras_bt_device *cras_bt_transport_device( 378 const struct cras_bt_transport *transport) 379{ 380 return reinterpret_cast<struct cras_bt_device *>(0x456);; 381} 382 383enum cras_bt_device_profile cras_bt_transport_profile( 384 const struct cras_bt_transport *transport) 385{ 386 return CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE; 387} 388 389// From cras_bt_device 390const char *cras_bt_device_name(const struct cras_bt_device *device) 391{ 392 return cras_bt_device_name_ret; 393} 394 395const char *cras_bt_device_object_path(const struct cras_bt_device *device) { 396 return "/org/bluez/hci0/dev_1A_2B_3C_4D_5E_6F"; 397} 398 399void cras_bt_device_append_iodev(struct cras_bt_device *device, 400 struct cras_iodev *iodev, 401 enum cras_bt_device_profile profile) 402{ 403 cras_bt_device_append_iodev_called++; 404} 405 406void cras_bt_device_rm_iodev(struct cras_bt_device *device, 407 struct cras_iodev *iodev) 408{ 409 cras_bt_device_rm_iodev_called++; 410} 411 412int init_a2dp(struct a2dp_info *a2dp, a2dp_sbc_t *sbc) 413{ 414 init_a2dp_called++; 415 return init_a2dp_return_val; 416} 417 418void destroy_a2dp(struct a2dp_info *a2dp) 419{ 420 destroy_a2dp_called++; 421} 422 423int a2dp_codesize(struct a2dp_info *a2dp) 424{ 425 return 512; 426} 427 428int a2dp_block_size(struct a2dp_info *a2dp, int encoded_bytes) 429{ 430 a2dp_block_size_called++; 431 432 // Assumes a2dp block size is 1:1 before/after encode. 433 return encoded_bytes; 434} 435 436int a2dp_queued_frames(struct a2dp_info *a2dp) 437{ 438 return a2dp_queued_frames_val; 439} 440 441void a2dp_drain(struct a2dp_info *a2dp) 442{ 443 drain_a2dp_called++; 444} 445 446int a2dp_encode(struct a2dp_info *a2dp, const void *pcm_buf, int pcm_buf_size, 447 int format_bytes, size_t link_mtu) { 448 unsigned int processed; 449 450 if (a2dp_encode_index == MAX_A2DP_ENCODE_CALLS) 451 return 0; 452 processed = a2dp_encode_processed_bytes_val[a2dp_encode_index]; 453 pcm_buf_size_val[a2dp_encode_index] = pcm_buf_size; 454 a2dp_encode_index++; 455 return processed; 456} 457 458int a2dp_write(struct a2dp_info *a2dp, int stream_fd, size_t link_mtu) { 459 return a2dp_write_return_val[a2dp_write_index++];; 460} 461 462int clock_gettime(clockid_t clk_id, struct timespec *tp) { 463 *tp = time_now; 464 return 0; 465} 466 467void cras_iodev_init_audio_area(struct cras_iodev *iodev, 468 int num_channels) { 469 iodev->area = dummy_audio_area; 470} 471 472void cras_iodev_free_audio_area(struct cras_iodev *iodev) { 473} 474 475void cras_audio_area_config_buf_pointers(struct cras_audio_area *area, 476 const struct cras_audio_format *fmt, 477 uint8_t *base_buffer) 478{ 479 dummy_audio_area->channels[0].buf = base_buffer; 480} 481 482// From audio_thread 483struct audio_thread_event_log *atlog; 484 485void audio_thread_add_write_callback(int fd, thread_callback cb, void *data) { 486 write_callback = cb; 487 write_callback_data = data; 488} 489 490void audio_thread_rm_callback(int fd) { 491} 492 493void audio_thread_enable_callback(int fd, int enabled) { 494} 495 496// From a2dp endpoint 497int cras_a2dp_has_suspend_timer() 498{ 499 return 0; 500} 501 502void cras_a2dp_schedule_suspend_timer(struct cras_iodev *iodev, 503 unsigned int msec) 504{ 505} 506 507void cras_a2dp_cancel_suspend_timer(struct cras_iodev *iodev) 508{ 509} 510 511} 512