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 <stdlib.h>
      7 #include <gtest/gtest.h>
      8 
      9 extern "C" {
     10 #include "cras_audio_area.h"
     11 #include "cras_iodev.h"
     12 #include "cras_iodev_list.h"
     13 #include "cras_loopback_iodev.h"
     14 #include "cras_shm.h"
     15 #include "cras_types.h"
     16 #include "dev_stream.h"
     17 #include "utlist.h"
     18 }
     19 
     20 namespace {
     21 
     22 static const unsigned int kBufferFrames = 16384;
     23 static const unsigned int kFrameBytes = 4;
     24 static const unsigned int kBufferSize = kBufferFrames * kFrameBytes;
     25 
     26 static struct timespec time_now;
     27 static cras_audio_area *dummy_audio_area;
     28 static loopback_hook_t loop_hook;
     29 static void *loop_hook_cb_data;
     30 static struct cras_iodev *enabled_dev;
     31 static unsigned int cras_iodev_list_add_input_called;
     32 static unsigned int cras_iodev_list_rm_input_called;
     33 static unsigned int cras_iodev_list_set_device_enabled_callback_called;
     34 static device_enabled_callback_t device_enabled_callback_cb;
     35 static device_disabled_callback_t device_disabled_callback_cb;
     36 static void *device_enabled_callback_cb_data;
     37 
     38 class LoopBackTestSuite : public testing::Test{
     39   protected:
     40     virtual void SetUp() {
     41       dummy_audio_area = (cras_audio_area*)calloc(
     42           1, sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2);
     43       for (unsigned int i = 0; i < kBufferSize; i++) {
     44         buf_[i] = rand();
     45       }
     46       fmt_.frame_rate = 48000;
     47       fmt_.num_channels = 2;
     48       fmt_.format = SND_PCM_FORMAT_S16_LE;
     49 
     50       loop_in_ = loopback_iodev_create(LOOPBACK_POST_MIX_PRE_DSP);
     51       EXPECT_EQ(1, cras_iodev_list_add_input_called);
     52       loop_in_->format = &fmt_;
     53 
     54       loop_hook = NULL;
     55       cras_iodev_list_add_input_called = 0;
     56       cras_iodev_list_rm_input_called = 0;
     57       cras_iodev_list_set_device_enabled_callback_called = 0;
     58     }
     59 
     60     virtual void TearDown() {
     61       loopback_iodev_destroy(loop_in_);
     62       EXPECT_EQ(1, cras_iodev_list_rm_input_called);
     63       EXPECT_EQ(NULL, device_enabled_callback_cb);
     64       EXPECT_EQ(NULL, device_disabled_callback_cb);
     65       free(dummy_audio_area);
     66     }
     67 
     68     uint8_t buf_[kBufferSize];
     69     struct cras_audio_format fmt_;
     70     struct cras_iodev *loop_in_;
     71 };
     72 
     73 TEST_F(LoopBackTestSuite, InstallLoopHook) {
     74   struct cras_iodev iodev;
     75   struct timespec tstamp;
     76 
     77   iodev.direction = CRAS_STREAM_OUTPUT;
     78   iodev.format = &fmt_;
     79   iodev.ext_format = &fmt_;
     80   iodev.streams = NULL;
     81   enabled_dev = &iodev;
     82 
     83   // Open loopback devices.
     84   EXPECT_EQ(0, loop_in_->configure_dev(loop_in_));
     85   EXPECT_EQ(1, cras_iodev_list_set_device_enabled_callback_called);
     86 
     87   // Signal an output device is enabled.
     88   device_enabled_callback_cb(&iodev, device_enabled_callback_cb_data);
     89 
     90   // Expect that a hook was added to the iodev
     91   ASSERT_NE(reinterpret_cast<loopback_hook_t>(NULL), loop_hook);
     92 
     93   // Check zero frames queued.
     94   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
     95 
     96   // Close loopback devices.
     97   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
     98   EXPECT_EQ(reinterpret_cast<loopback_hook_t>(NULL), loop_hook);
     99 }
    100 
    101 // Test how loopback works if there isn't any output devices open.
    102 TEST_F(LoopBackTestSuite, OpenIdleSystem) {
    103   cras_audio_area *area;
    104   unsigned int nread = 1024;
    105   struct timespec tstamp;
    106   int rc;
    107 
    108   // No active output device.
    109   enabled_dev = NULL;
    110   time_now.tv_sec = 100;
    111   time_now.tv_nsec = 0;
    112 
    113   EXPECT_EQ(0, loop_in_->configure_dev(loop_in_));
    114   EXPECT_EQ(1, cras_iodev_list_set_device_enabled_callback_called);
    115 
    116   // Should be 480 samples after 480/frame rate seconds
    117   time_now.tv_nsec += 480 * 1e9 / 48000;
    118   EXPECT_EQ(480, loop_in_->frames_queued(loop_in_, &tstamp));
    119 
    120   // Verify frames from loopback record.
    121   loop_in_->get_buffer(loop_in_, &area, &nread);
    122   EXPECT_EQ(480, nread);
    123   memset(buf_, 0, nread * kFrameBytes);
    124   rc = memcmp(area->channels[0].buf, buf_, nread * kFrameBytes);
    125   EXPECT_EQ(0, rc);
    126   loop_in_->put_buffer(loop_in_, nread);
    127 
    128   // Check zero frames queued.
    129   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
    130 
    131   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
    132 }
    133 
    134 TEST_F(LoopBackTestSuite, SimpleLoopback) {
    135   cras_audio_area *area;
    136   unsigned int nframes = 1024;
    137   unsigned int nread = 1024;
    138   int rc;
    139   struct cras_iodev iodev;
    140   struct dev_stream stream;
    141   struct timespec tstamp;
    142 
    143   iodev.streams = &stream;
    144   enabled_dev = &iodev;
    145 
    146   loop_in_->configure_dev(loop_in_);
    147   ASSERT_NE(reinterpret_cast<void *>(NULL), loop_hook);
    148 
    149   // Loopback callback for the hook.
    150   loop_hook(buf_, nframes, &fmt_, loop_hook_cb_data);
    151 
    152   // Verify frames from loopback record.
    153   loop_in_->get_buffer(loop_in_, &area, &nread);
    154   EXPECT_EQ(nframes, nread);
    155   rc = memcmp(area->channels[0].buf, buf_, nframes * kFrameBytes);
    156   EXPECT_EQ(0, rc);
    157   loop_in_->put_buffer(loop_in_, nread);
    158 
    159   // Check zero frames queued.
    160   EXPECT_EQ(0, loop_in_->frames_queued(loop_in_, &tstamp));
    161 
    162   EXPECT_EQ(0, loop_in_->close_dev(loop_in_));
    163 }
    164 
    165 // TODO(chinyue): Test closing last iodev while streaming loopback data.
    166 
    167 /* Stubs */
    168 extern "C" {
    169 
    170 void cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
    171                                          const struct cras_audio_format *fmt,
    172                                          uint8_t *base_buffer)
    173 {
    174   dummy_audio_area->channels[0].buf = base_buffer;
    175 }
    176 
    177 void cras_iodev_free_audio_area(struct cras_iodev *iodev)
    178 {
    179 }
    180 
    181 void cras_iodev_free_format(struct cras_iodev *iodev)
    182 {
    183 }
    184 
    185 void cras_iodev_init_audio_area(struct cras_iodev *iodev, int num_channels)
    186 {
    187   iodev->area = dummy_audio_area;
    188 }
    189 
    190 void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node)
    191 {
    192   DL_APPEND(iodev->nodes, node);
    193 }
    194 
    195 void cras_iodev_set_active_node(struct cras_iodev *iodev,
    196                                 struct cras_ionode *node)
    197 {
    198 }
    199 
    200 void cras_iodev_register_pre_dsp_hook(struct cras_iodev *iodev,
    201 				      loopback_hook_t loop_cb,
    202 				      void *cb_data)
    203 {
    204   loop_hook = loop_cb;
    205   loop_hook_cb_data = cb_data;
    206 }
    207 
    208 void cras_iodev_register_post_dsp_hook(struct cras_iodev *iodev,
    209 				       loopback_hook_t loop_cb,
    210 				       void *cb_data)
    211 {
    212   loop_hook = loop_cb;
    213   loop_hook_cb_data = cb_data;
    214 }
    215 
    216 int cras_iodev_list_add_input(struct cras_iodev *input)
    217 {
    218   cras_iodev_list_add_input_called++;
    219   return 0;
    220 }
    221 
    222 int cras_iodev_list_rm_input(struct cras_iodev *input)
    223 {
    224   cras_iodev_list_rm_input_called++;
    225   return 0;
    226 }
    227 
    228 int cras_iodev_list_set_device_enabled_callback(
    229     device_enabled_callback_t enabled_cb,
    230     device_disabled_callback_t disabled_cb,
    231     void *cb_data)
    232 {
    233   cras_iodev_list_set_device_enabled_callback_called++;
    234   device_enabled_callback_cb = enabled_cb;
    235   device_disabled_callback_cb = disabled_cb;
    236   device_enabled_callback_cb_data = cb_data;
    237   return 0;
    238 }
    239 
    240 int clock_gettime(clockid_t clk_id, struct timespec *tp) {
    241   *tp = time_now;
    242   return 0;
    243 }
    244 
    245 struct cras_iodev *cras_iodev_list_get_first_enabled_iodev(
    246     enum CRAS_STREAM_DIRECTION direction)
    247 {
    248   return enabled_dev;
    249 }
    250 
    251 }  // extern "C"
    252 
    253 }  //  namespace
    254 
    255 int main(int argc, char **argv) {
    256   ::testing::InitGoogleTest(&argc, argv);
    257   return RUN_ALL_TESTS();
    258 }
    259