普通文本  |  272行  |  7.41 KB

// Copyright 2018 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 <stdio.h>
#include <gtest/gtest.h>

extern "C" {
#include "cras_apm_list.h"
#include "cras_audio_area.h"
#include "cras_dsp_pipeline.h"
#include "cras_iodev.h"
#include "cras_iodev_list.h"
#include "cras_types.h"
#include "float_buffer.h"
#include "webrtc_apm.h"
}

namespace {

static void *stream_ptr = reinterpret_cast<void *>(0x123);
static void *dev_ptr = reinterpret_cast<void *>(0x345);
static void *dev_ptr2 = reinterpret_cast<void *>(0x678);
static struct cras_apm_list *list;
static struct cras_audio_area fake_audio_area;
static unsigned int dsp_util_interleave_frames;
static unsigned int webrtc_apm_process_stream_f_called;
static unsigned int webrtc_apm_process_reverse_stream_f_called;
static device_enabled_callback_t device_enabled_callback_val;
static struct ext_dsp_module *ext_dsp_module_value;
static struct cras_iodev fake_iodev;


TEST(ApmList, ApmListCreate) {
  list = cras_apm_list_create(stream_ptr, 0);
  EXPECT_EQ((void *)NULL, list);

  list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
  EXPECT_NE((void *)NULL, list);
  EXPECT_EQ(APM_ECHO_CANCELLATION, cras_apm_list_get_effects(list));

  cras_apm_list_destroy(list);
}

TEST(ApmList, AddRemoveApm) {
  struct cras_audio_format fmt;

  fmt.num_channels = 2;
  fmt.frame_rate = 48000;
  fmt.format = SND_PCM_FORMAT_S16_LE;

  list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
  EXPECT_NE((void *)NULL, list);

  EXPECT_NE((void *)NULL, cras_apm_list_add(list, dev_ptr, &fmt));
  EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr2));

  EXPECT_NE((void *)NULL, cras_apm_list_add(list, dev_ptr2, &fmt));
  EXPECT_NE((void *)NULL, cras_apm_list_get(list, dev_ptr));

  cras_apm_list_remove(list, dev_ptr);
  EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr));
  EXPECT_NE((void *)NULL, cras_apm_list_get(list, dev_ptr2));

  cras_apm_list_remove(list, dev_ptr2);
  EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr2));

  cras_apm_list_destroy(list);
}

TEST(ApmList, ApmProcessForwardBuffer) {
  struct cras_apm *apm;
  struct cras_audio_format fmt;
  struct cras_audio_area *area;
  struct float_buffer *buf;

  fmt.num_channels = 2;
  fmt.frame_rate = 48000;
  fmt.format = SND_PCM_FORMAT_S16_LE;

  list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
  EXPECT_NE((void *)NULL, list);

  apm = cras_apm_list_add(list, dev_ptr, &fmt);

  buf = float_buffer_create(500, 2);
  float_buffer_written(buf, 300);
  webrtc_apm_process_stream_f_called = 0;
  cras_apm_list_process(apm, buf, 0);
  EXPECT_EQ(0, webrtc_apm_process_stream_f_called);

  area = cras_apm_list_get_processed(apm);
  EXPECT_EQ(0, area->frames);

  float_buffer_reset(buf);
  float_buffer_written(buf, 200);
  cras_apm_list_process(apm, buf, 0);
  area = cras_apm_list_get_processed(apm);
  EXPECT_EQ(1, webrtc_apm_process_stream_f_called);
  EXPECT_EQ(480, dsp_util_interleave_frames);
  EXPECT_EQ(480, area->frames);

  /* Put some processed frames. Another apm_list process will not call
   * into webrtc_apm because the processed buffer is not yet empty.
   */
  cras_apm_list_put_processed(apm, 200);
  float_buffer_reset(buf);
  float_buffer_written(buf, 500);
  cras_apm_list_process(apm, buf, 0);
  EXPECT_EQ(1, webrtc_apm_process_stream_f_called);

  /* Put another 280 processed frames, so it's now ready for webrtc_apm
   * to process another chunk of 480 frames (10ms) data.
   */
  cras_apm_list_put_processed(apm, 280);
  cras_apm_list_process(apm, buf, 0);
  EXPECT_EQ(2, webrtc_apm_process_stream_f_called);

  float_buffer_destroy(&buf);
  cras_apm_list_destroy(list);
}

TEST(ApmList, ApmProcessReverseData) {
  struct cras_apm *apm;
  struct cras_audio_format fmt;
  struct float_buffer *buf;
  float *const *rp;
  unsigned int nread;
  struct cras_iodev fake_iodev;

  fmt.num_channels = 2;
  fmt.frame_rate = 48000;
  fmt.format = SND_PCM_FORMAT_S16_LE;

  fake_iodev.direction = CRAS_STREAM_OUTPUT;
  device_enabled_callback_val = NULL;
  ext_dsp_module_value = NULL;
  webrtc_apm_process_reverse_stream_f_called = 0;

  cras_apm_list_init("");
  EXPECT_NE((void *)NULL, device_enabled_callback_val);

  device_enabled_callback_val(&fake_iodev, NULL);
  EXPECT_NE((void *)NULL, ext_dsp_module_value);
  EXPECT_NE((void *)NULL, ext_dsp_module_value->ports);

  buf = float_buffer_create(500, 2);
  float_buffer_written(buf, 500);
  nread = 500;
  rp = float_buffer_read_pointer(buf, 0, &nread);

  for (int i = 0; i < buf->num_channels; i++)
    ext_dsp_module_value->ports[i] = rp[i];

  ext_dsp_module_value->configure(ext_dsp_module_value,
                                  800, 2, 48000);
  ext_dsp_module_value->run(ext_dsp_module_value, 500);
  EXPECT_EQ(0, webrtc_apm_process_reverse_stream_f_called);

  list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
  EXPECT_NE((void *)NULL, list);

  apm = cras_apm_list_add(list, dev_ptr, &fmt);

  ext_dsp_module_value->run(ext_dsp_module_value, 250);
  EXPECT_EQ(0, webrtc_apm_process_reverse_stream_f_called);

  ext_dsp_module_value->run(ext_dsp_module_value, 250);
  EXPECT_EQ(1, webrtc_apm_process_reverse_stream_f_called);

  float_buffer_destroy(&buf);
  cras_apm_list_deinit();
}

extern "C" {
int cras_iodev_list_set_device_enabled_callback(
		device_enabled_callback_t enabled_cb,
		device_disabled_callback_t disabled_cb,
		void *cb_data)
{
  device_enabled_callback_val = enabled_cb;
  return 0;
}
struct cras_iodev *cras_iodev_list_get_first_enabled_iodev(
	enum CRAS_STREAM_DIRECTION direction)
{
  return &fake_iodev;
}
void cras_iodev_set_ext_dsp_module(struct cras_iodev *iodev,
				   struct ext_dsp_module *ext)
{
  ext_dsp_module_value = ext;
}
struct cras_audio_area *cras_audio_area_create(int num_channels)
{
  return &fake_audio_area;
}

void cras_audio_area_destroy(struct cras_audio_area *area)
{
}
void cras_audio_area_config_channels(struct cras_audio_area *area,
				     const struct cras_audio_format *fmt)
{
}
void cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
					 const struct cras_audio_format *fmt,
					 uint8_t *base_buffer)
{
}
void dsp_util_interleave(float *const *input, int16_t *output, int channels,
			 snd_pcm_format_t format, int frames)
{
  dsp_util_interleave_frames = frames;
}
struct aec_config *aec_config_get(const char *device_config_dir)
{
  return NULL;
}
void aec_config_dump(struct aec_config *config)
{
}
struct apm_config *apm_config_get(const char *device_config_dir)
{
  return NULL;
}
void apm_config_dump(struct apm_config *config)
{
}
webrtc_apm webrtc_apm_create(unsigned int num_channels,
			     unsigned int frame_rate,
			     struct aec_config *aec_config,
                             struct apm_config *apm_config)
{
  return reinterpret_cast<webrtc_apm>(0x11);
}
void webrtc_apm_destroy(webrtc_apm apm)
{
  return;
}
int webrtc_apm_process_stream_f(webrtc_apm ptr,
				int num_channels,
				int rate,
				float *const *data)
{
  webrtc_apm_process_stream_f_called++;
  return 0;
}

int webrtc_apm_process_reverse_stream_f(
		webrtc_apm ptr,
		int num_channels, int rate,
		float *const *data)
{
  webrtc_apm_process_reverse_stream_f_called++;
  return 0;
}
int webrtc_apm_aec_dump(webrtc_apm ptr, void** work_queue,
                        int start, FILE *handle)
{
  return 0;
}

} // extern "C"
} // namespace


int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}