Home | History | Annotate | Download | only in tests
      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 
      9 extern "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 8
     24 #define MAX_A2DP_WRITE_CALLS 4
     25 
     26 static struct cras_bt_transport *fake_transport;
     27 static cras_audio_format format;
     28 static size_t cras_bt_device_append_iodev_called;
     29 static size_t cras_bt_device_rm_iodev_called;
     30 static size_t cras_iodev_add_node_called;
     31 static size_t cras_iodev_rm_node_called;
     32 static size_t cras_iodev_set_active_node_called;
     33 static size_t cras_bt_transport_acquire_called;
     34 static size_t cras_bt_transport_configuration_called;
     35 static size_t cras_bt_transport_release_called;
     36 static size_t init_a2dp_called;
     37 static int init_a2dp_return_val;
     38 static size_t destroy_a2dp_called;
     39 static size_t drain_a2dp_called;
     40 static size_t a2dp_block_size_called;
     41 static size_t a2dp_queued_frames_val;
     42 static size_t cras_iodev_free_format_called;
     43 static size_t cras_iodev_free_resources_called;
     44 static int pcm_buf_size_val[MAX_A2DP_ENCODE_CALLS];
     45 static unsigned int a2dp_encode_processed_bytes_val[MAX_A2DP_ENCODE_CALLS];
     46 static unsigned int a2dp_encode_index;
     47 static int a2dp_write_return_val[MAX_A2DP_WRITE_CALLS];
     48 static unsigned int a2dp_write_index;
     49 static cras_audio_area *dummy_audio_area;
     50 static thread_callback write_callback;
     51 static void *write_callback_data;
     52 static const char *fake_device_name = "fake device name";
     53 static const char *cras_bt_device_name_ret;
     54 static unsigned int cras_bt_transport_write_mtu_ret;
     55 
     56 void 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 
     89 int 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 
     99 namespace {
    100 
    101 static struct timespec time_now;
    102 class A2dpIodev: public testing::Test {
    103   protected:
    104     virtual void SetUp() {
    105       ResetStubData();
    106       atlog = (audio_thread_event_log *)calloc(
    107           1,
    108           sizeof(audio_thread_event_log));
    109     }
    110 
    111     virtual void TearDown() {
    112       free(dummy_audio_area);
    113       dummy_audio_area = NULL;
    114       free(atlog);
    115     }
    116 };
    117 
    118 TEST_F(A2dpIodev, InitializeA2dpIodev) {
    119   struct cras_iodev *iodev;
    120 
    121   cras_bt_device_name_ret = NULL;
    122   iodev = a2dp_iodev_create(fake_transport);
    123 
    124   ASSERT_NE(iodev, (void *)NULL);
    125   ASSERT_EQ(iodev->direction, CRAS_STREAM_OUTPUT);
    126   ASSERT_EQ(1, cras_bt_transport_configuration_called);
    127   ASSERT_EQ(1, init_a2dp_called);
    128   ASSERT_EQ(1, cras_bt_device_append_iodev_called);
    129   ASSERT_EQ(1, cras_iodev_add_node_called);
    130   ASSERT_EQ(1, cras_iodev_set_active_node_called);
    131 
    132   /* Assert iodev name matches the object path when bt device doesn't
    133    * have its readable name populated. */
    134   ASSERT_STREQ(FAKE_OBJECT_PATH, iodev->info.name);
    135 
    136   a2dp_iodev_destroy(iodev);
    137 
    138   ASSERT_EQ(1, cras_bt_device_rm_iodev_called);
    139   ASSERT_EQ(1, cras_iodev_rm_node_called);
    140   ASSERT_EQ(1, destroy_a2dp_called);
    141   ASSERT_EQ(1, cras_iodev_free_resources_called);
    142 
    143   cras_bt_device_name_ret = fake_device_name;
    144   /* Assert iodev name matches the bt device's name */
    145   iodev = a2dp_iodev_create(fake_transport);
    146   ASSERT_STREQ(fake_device_name, iodev->info.name);
    147 
    148   a2dp_iodev_destroy(iodev);
    149 }
    150 
    151 TEST_F(A2dpIodev, InitializeFail) {
    152   struct cras_iodev *iodev;
    153 
    154   init_a2dp_return_val = -1;
    155   iodev = a2dp_iodev_create(fake_transport);
    156 
    157   ASSERT_EQ(iodev, (void *)NULL);
    158   ASSERT_EQ(1, cras_bt_transport_configuration_called);
    159   ASSERT_EQ(1, init_a2dp_called);
    160   ASSERT_EQ(0, cras_bt_device_append_iodev_called);
    161   ASSERT_EQ(0, cras_iodev_add_node_called);
    162   ASSERT_EQ(0, cras_iodev_set_active_node_called);
    163   ASSERT_EQ(0, cras_iodev_rm_node_called);
    164 }
    165 
    166 TEST_F(A2dpIodev, OpenIodev) {
    167   struct cras_iodev *iodev;
    168 
    169   iodev = a2dp_iodev_create(fake_transport);
    170 
    171   iodev_set_format(iodev, &format);
    172   iodev->configure_dev(iodev);
    173 
    174   ASSERT_EQ(1, cras_bt_transport_acquire_called);
    175 
    176   iodev->close_dev(iodev);
    177   ASSERT_EQ(1, cras_bt_transport_release_called);
    178   ASSERT_EQ(1, drain_a2dp_called);
    179   ASSERT_EQ(1, cras_iodev_free_format_called);
    180 
    181   a2dp_iodev_destroy(iodev);
    182 }
    183 
    184 TEST_F(A2dpIodev, GetPutBuffer) {
    185   struct cras_iodev *iodev;
    186   struct cras_audio_area *area1, *area2, *area3;
    187   uint8_t *area1_buf;
    188   unsigned frames;
    189 
    190   iodev = a2dp_iodev_create(fake_transport);
    191 
    192   iodev_set_format(iodev, &format);
    193   iodev->configure_dev(iodev);
    194   ASSERT_NE(write_callback, (void *)NULL);
    195 
    196   frames = 256;
    197   iodev->get_buffer(iodev, &area1, &frames);
    198   ASSERT_EQ(256, frames);
    199   ASSERT_EQ(256, area1->frames);
    200   area1_buf = area1->channels[0].buf;
    201 
    202   /* Test 100 frames(400 bytes) put and all processed. */
    203   a2dp_encode_processed_bytes_val[0] = 4096 * 4;
    204   a2dp_encode_processed_bytes_val[1] = 400;
    205   a2dp_write_index = 0;
    206   a2dp_write_return_val[0] = -EAGAIN;
    207   a2dp_write_return_val[1] = 400;
    208   iodev->put_buffer(iodev, 100);
    209   write_callback(write_callback_data);
    210   // Start with 4k frames.
    211   EXPECT_EQ(4096, pcm_buf_size_val[0]);
    212   EXPECT_EQ(400, pcm_buf_size_val[1]);
    213 
    214   iodev->get_buffer(iodev, &area2, &frames);
    215   ASSERT_EQ(256, frames);
    216   ASSERT_EQ(256, area2->frames);
    217 
    218   /* Assert buf2 points to the same position as buf1 */
    219   ASSERT_EQ(400, area2->channels[0].buf - area1_buf);
    220 
    221   /* Test 100 frames(400 bytes) put, only 360 bytes processed,
    222    * 40 bytes left in pcm buffer.
    223    */
    224   a2dp_encode_index = 0;
    225   a2dp_encode_processed_bytes_val[0] = 360;
    226   a2dp_encode_processed_bytes_val[1] = 0;
    227   a2dp_write_index = 0;
    228   a2dp_write_return_val[0] = 360;
    229   a2dp_write_return_val[1] = 0;
    230   iodev->put_buffer(iodev, 100);
    231   write_callback(write_callback_data);
    232   EXPECT_EQ(400, pcm_buf_size_val[0]);
    233   ASSERT_EQ(40, pcm_buf_size_val[1]);
    234 
    235   iodev->get_buffer(iodev, &area3, &frames);
    236 
    237   /* Existing buffer not completed processed, assert new buffer starts from
    238    * current write pointer.
    239    */
    240   ASSERT_EQ(256, frames);
    241   EXPECT_EQ(800, area3->channels[0].buf - area1_buf);
    242 
    243   iodev->close_dev(iodev);
    244   a2dp_iodev_destroy(iodev);
    245 }
    246 
    247 TEST_F(A2dpIodev, FramesQueued) {
    248   struct cras_iodev *iodev;
    249   struct cras_audio_area *area;
    250   struct timespec tstamp;
    251   unsigned frames;
    252 
    253   iodev = a2dp_iodev_create(fake_transport);
    254 
    255   iodev_set_format(iodev, &format);
    256   time_now.tv_sec = 0;
    257   time_now.tv_nsec = 0;
    258   iodev->configure_dev(iodev);
    259   ASSERT_NE(write_callback, (void *)NULL);
    260 
    261   frames = 256;
    262   iodev->get_buffer(iodev, &area, &frames);
    263   ASSERT_EQ(256, frames);
    264   ASSERT_EQ(256, area->frames);
    265 
    266   /* Put 100 frames, proccessed 400 bytes to a2dp buffer.
    267    * Assume 200 bytes written out, queued 50 frames in a2dp buffer.
    268    */
    269   a2dp_encode_processed_bytes_val[0] = 400;
    270   a2dp_encode_processed_bytes_val[1] = 0;
    271   a2dp_write_return_val[0] = 200;
    272   a2dp_write_return_val[1] = -EAGAIN;
    273   a2dp_queued_frames_val = 50;
    274   time_now.tv_sec = 0;
    275   time_now.tv_nsec = 1000000;
    276   iodev->put_buffer(iodev, 300);
    277   write_callback(write_callback_data);
    278   EXPECT_EQ(350, iodev->frames_queued(iodev, &tstamp));
    279   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
    280   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
    281 
    282   /* After writing another 200 frames, check for correct buffer level. */
    283   time_now.tv_sec = 0;
    284   time_now.tv_nsec = 2000000;
    285   a2dp_encode_index = 0;
    286   a2dp_write_index = 0;
    287   a2dp_encode_processed_bytes_val[0] = 800;
    288   write_callback(write_callback_data);
    289   /* 1000000 nsec has passed, estimated queued frames adjusted by 44 */
    290   EXPECT_EQ(256, iodev->frames_queued(iodev, &tstamp));
    291   EXPECT_EQ(1200, pcm_buf_size_val[0]);
    292   EXPECT_EQ(400, pcm_buf_size_val[1]);
    293   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
    294   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
    295 
    296   /* Queued frames and new put buffer are all written */
    297   a2dp_encode_processed_bytes_val[0] = 400;
    298   a2dp_encode_processed_bytes_val[1] = 0;
    299   a2dp_encode_index = 0;
    300   a2dp_write_return_val[0] = 400;
    301   a2dp_write_return_val[1] = -EAGAIN;
    302   a2dp_write_index = 0;
    303 
    304   /* Add wnother 200 samples, get back to the original level. */
    305   time_now.tv_sec = 0;
    306   time_now.tv_nsec = 50000000;
    307   a2dp_encode_processed_bytes_val[0] = 600;
    308   iodev->put_buffer(iodev, 200);
    309   EXPECT_EQ(1200, pcm_buf_size_val[0]);
    310   EXPECT_EQ(200, iodev->frames_queued(iodev, &tstamp));
    311   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
    312   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
    313   iodev->close_dev(iodev);
    314   a2dp_iodev_destroy(iodev);
    315 }
    316 
    317 TEST_F(A2dpIodev, FlushAtLowBufferLevel) {
    318   struct cras_iodev *iodev;
    319   struct cras_audio_area *area;
    320   struct timespec tstamp;
    321   unsigned frames;
    322 
    323   iodev = a2dp_iodev_create(fake_transport);
    324 
    325   iodev_set_format(iodev, &format);
    326   time_now.tv_sec = 0;
    327   time_now.tv_nsec = 0;
    328   iodev->configure_dev(iodev);
    329   ASSERT_NE(write_callback, (void *)NULL);
    330 
    331   ASSERT_EQ(iodev->min_buffer_level, 400);
    332 
    333   frames = 700;
    334   iodev->get_buffer(iodev, &area, &frames);
    335   ASSERT_EQ(700, frames);
    336   ASSERT_EQ(700, area->frames);
    337 
    338   /* Fake 111 frames in pre-fill*/
    339   a2dp_encode_processed_bytes_val[0] = 111;
    340   a2dp_write_return_val[0] = -EAGAIN;
    341 
    342   /* First call to a2dp_encode() processed 800 bytes. */
    343   a2dp_encode_processed_bytes_val[1] = 800;
    344   a2dp_encode_processed_bytes_val[2] = 0;
    345   a2dp_write_return_val[1] = 200;
    346 
    347   /* put_buffer shouldn't trigger the 2nd call to a2dp_encode() because
    348    * buffer is low. Fake some data to make sure this test case will fail
    349    * when a2dp_encode() called twice.
    350    */
    351   a2dp_encode_processed_bytes_val[3] = 800;
    352   a2dp_encode_processed_bytes_val[4] = 0;
    353   a2dp_write_return_val[2] = -EAGAIN;
    354 
    355   time_now.tv_nsec = 10000000;
    356   iodev->put_buffer(iodev, 700);
    357 
    358   time_now.tv_nsec = 20000000;
    359   EXPECT_EQ(500, iodev->frames_queued(iodev, &tstamp));
    360   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
    361   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
    362   iodev->close_dev(iodev);
    363   a2dp_iodev_destroy(iodev);
    364 }
    365 
    366 } // namespace
    367 
    368 int main(int argc, char **argv) {
    369   ::testing::InitGoogleTest(&argc, argv);
    370   return RUN_ALL_TESTS();
    371 }
    372 
    373 extern "C" {
    374 
    375 int cras_bt_transport_configuration(const struct cras_bt_transport *transport,
    376                                     void *configuration, int len)
    377 {
    378   cras_bt_transport_configuration_called++;
    379   return 0;
    380 }
    381 
    382 int cras_bt_transport_acquire(struct cras_bt_transport *transport)
    383 {
    384   cras_bt_transport_acquire_called++;
    385   return 0;
    386 }
    387 
    388 int cras_bt_transport_release(struct cras_bt_transport *transport,
    389     unsigned int blocking)
    390 {
    391   cras_bt_transport_release_called++;
    392   return 0;
    393 }
    394 
    395 int cras_bt_transport_fd(const struct cras_bt_transport *transport)
    396 {
    397   return 0;
    398 }
    399 
    400 const char *cras_bt_transport_object_path(
    401 		const struct cras_bt_transport *transport)
    402 {
    403   return FAKE_OBJECT_PATH;
    404 }
    405 
    406 uint16_t cras_bt_transport_write_mtu(const struct cras_bt_transport *transport)
    407 {
    408   return cras_bt_transport_write_mtu_ret;
    409 }
    410 
    411 int cras_bt_transport_set_volume(struct cras_bt_transport *transport,
    412     uint16_t volume)
    413 {
    414   return 0;
    415 }
    416 
    417 void cras_iodev_free_format(struct cras_iodev *iodev)
    418 {
    419   cras_iodev_free_format_called++;
    420 }
    421 
    422 void cras_iodev_free_resources(struct cras_iodev *iodev)
    423 {
    424   cras_iodev_free_resources_called++;
    425 }
    426 
    427 // Cras iodev
    428 void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node)
    429 {
    430   cras_iodev_add_node_called++;
    431   iodev->nodes = node;
    432 }
    433 
    434 void cras_iodev_rm_node(struct cras_iodev *iodev, struct cras_ionode *node)
    435 {
    436   cras_iodev_rm_node_called++;
    437   iodev->nodes = NULL;
    438 }
    439 
    440 void cras_iodev_set_active_node(struct cras_iodev *iodev,
    441 				struct cras_ionode *node)
    442 {
    443   cras_iodev_set_active_node_called++;
    444   iodev->active_node = node;
    445 }
    446 
    447 // From cras_bt_transport
    448 struct cras_bt_device *cras_bt_transport_device(
    449 	const struct cras_bt_transport *transport)
    450 {
    451   return reinterpret_cast<struct cras_bt_device *>(0x456);;
    452 }
    453 
    454 enum cras_bt_device_profile cras_bt_transport_profile(
    455   const struct cras_bt_transport *transport)
    456 {
    457   return CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE;
    458 }
    459 
    460 // From cras_bt_device
    461 const char *cras_bt_device_name(const struct cras_bt_device *device)
    462 {
    463   return cras_bt_device_name_ret;
    464 }
    465 
    466 const char *cras_bt_device_object_path(const struct cras_bt_device *device) {
    467   return "/org/bluez/hci0/dev_1A_2B_3C_4D_5E_6F";
    468 }
    469 
    470 void cras_bt_device_append_iodev(struct cras_bt_device *device,
    471                                  struct cras_iodev *iodev,
    472                                  enum cras_bt_device_profile profile)
    473 {
    474   cras_bt_device_append_iodev_called++;
    475 }
    476 
    477 void cras_bt_device_rm_iodev(struct cras_bt_device *device,
    478                              struct cras_iodev *iodev)
    479 {
    480   cras_bt_device_rm_iodev_called++;
    481 }
    482 
    483 int cras_bt_device_get_use_hardware_volume(struct cras_bt_device *device)
    484 {
    485   return 0;
    486 }
    487 
    488 int cras_bt_device_cancel_suspend(struct cras_bt_device *device)
    489 {
    490   return 0;
    491 }
    492 
    493 int cras_bt_device_schedule_suspend(struct cras_bt_device *device,
    494                                     unsigned int msec)
    495 {
    496   return 0;
    497 }
    498 
    499 int init_a2dp(struct a2dp_info *a2dp, a2dp_sbc_t *sbc)
    500 {
    501   init_a2dp_called++;
    502   return init_a2dp_return_val;
    503 }
    504 
    505 void destroy_a2dp(struct a2dp_info *a2dp)
    506 {
    507   destroy_a2dp_called++;
    508 }
    509 
    510 int a2dp_codesize(struct a2dp_info *a2dp)
    511 {
    512   return 512;
    513 }
    514 
    515 int a2dp_block_size(struct a2dp_info *a2dp, int encoded_bytes)
    516 {
    517   a2dp_block_size_called++;
    518 
    519   // Assumes a2dp block size is 1:1 before/after encode.
    520   return encoded_bytes;
    521 }
    522 
    523 int a2dp_queued_frames(struct a2dp_info *a2dp)
    524 {
    525   return a2dp_queued_frames_val;
    526 }
    527 
    528 void a2dp_drain(struct a2dp_info *a2dp)
    529 {
    530   drain_a2dp_called++;
    531 }
    532 
    533 int a2dp_encode(struct a2dp_info *a2dp, const void *pcm_buf, int pcm_buf_size,
    534                 int format_bytes, size_t link_mtu) {
    535   unsigned int processed;
    536 
    537   if (a2dp_encode_index == MAX_A2DP_ENCODE_CALLS)
    538     return 0;
    539   processed = a2dp_encode_processed_bytes_val[a2dp_encode_index];
    540   pcm_buf_size_val[a2dp_encode_index] = pcm_buf_size;
    541   a2dp_encode_index++;
    542   return processed;
    543 }
    544 
    545 int a2dp_write(struct a2dp_info *a2dp, int stream_fd, size_t link_mtu) {
    546   return a2dp_write_return_val[a2dp_write_index++];;
    547 }
    548 
    549 int clock_gettime(clockid_t clk_id, struct timespec *tp) {
    550   *tp = time_now;
    551   return 0;
    552 }
    553 
    554 void cras_iodev_init_audio_area(struct cras_iodev *iodev,
    555                                 int num_channels) {
    556   iodev->area = dummy_audio_area;
    557 }
    558 
    559 void cras_iodev_free_audio_area(struct cras_iodev *iodev) {
    560 }
    561 
    562 void cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
    563 					 const struct cras_audio_format *fmt,
    564 					 uint8_t *base_buffer)
    565 {
    566   dummy_audio_area->channels[0].buf = base_buffer;
    567 }
    568 
    569 struct audio_thread *cras_iodev_list_get_audio_thread()
    570 {
    571   return NULL;
    572 }
    573 // From audio_thread
    574 struct audio_thread_event_log *atlog;
    575 
    576 void audio_thread_add_write_callback(int fd, thread_callback cb, void *data) {
    577   write_callback = cb;
    578   write_callback_data = data;
    579 }
    580 
    581 int audio_thread_rm_callback_sync(struct audio_thread *thread, int fd) {
    582   return 0;
    583 }
    584 
    585 void audio_thread_enable_callback(int fd, int enabled) {
    586 }
    587 
    588 }
    589