Reconstruct audiotest project
Move source file into src/ and header file into include/
Also removed audiofuntest, test_tones and looptest.
Rename audiofuntest_v2 to audiofuntest.
CQ-DEPEND=CL:383311
BUG=chromium:630919
TEST=None
Change-Id: Icd9e1e744bae49ee35ccbd22e9d9f1fa2cbbe6f8
Reviewed-on: https://chromium-review.googlesource.com/381047
Commit-Ready: Shun-Hsing Ou <shunhsingou@chromium.org>
Tested-by: Shun-Hsing Ou <shunhsingou@chromium.org>
Reviewed-by: Shun-Hsing Ou <shunhsingou@chromium.org>
diff --git a/Android.mk b/Android.mk
index cd45a39..8a30aa6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,11 +11,11 @@
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
- audiofuntest_v2.cc \
- connector.cc \
- frame_generator.cc \
- evaluator.cc \
- param_config.cc
+ src/audiofuntest_v2.cc \
+ src/connector.cc \
+ src/frame_generator.cc \
+ src/evaluator.cc \
+ src/param_config.cc
LOCAL_MODULE := audiofuntest_v2
diff --git a/Makefile b/Makefile
index 52e571d..36ff011 100644
--- a/Makefile
+++ b/Makefile
@@ -4,88 +4,7 @@
include common.mk
-LDLIBS += -lm -lpthread
-
-ALSA_CFLAGS := $(shell $(PKG_CONFIG) --cflags alsa)
-ALSA_LIBS := $(shell $(PKG_CONFIG) --libs alsa)
-FFTW_CFLAGS := $(shell $(PKG_CONFIG) --cflags fftw3)
-FFTW_LIBS := $(shell $(PKG_CONFIG) --libs fftw3)
-CRAS_CFLAGS := $(shell $(PKG_CONFIG) --cflags libcras)
-CRAS_LIBS := $(shell $(PKG_CONFIG) --libs libcras)
-
-CXX_BINARY(audiofuntest): $(filter \
- alsa_client.o \
- audiofuntest.o \
- tone_generators.o \
- ,$(CXX_OBJECTS))
-CXX_BINARY(audiofuntest): \
- CPPFLAGS += $(ALSA_CFLAGS) $(FFTW_CFLAGS)
-CXX_BINARY(audiofuntest): \
- LDLIBS += $(ALSA_LIBS) $(FFTW_LIBS)
-clean: CLEAN(audiofuntest)
-all: CXX_BINARY(audiofuntest)
-
-CXX_BINARY(test_tones): $(filter \
- alsa_client.o \
- test_tones.o \
- tone_generators.o \
- ,$(CXX_OBJECTS))
-CXX_BINARY(test_tones): \
- CPPFLAGS += $(ALSA_CFLAGS)
-CXX_BINARY(test_tones): \
- LDLIBS += $(ALSA_LIBS)
-clean: CLEAN(test_tones)
-all: CXX_BINARY(test_tones)
-
-CC_BINARY(looptest): $(filter \
- libaudiodev.o \
- looptest.o \
- ,$(C_OBJECTS))
-CC_BINARY(looptest): \
- CFLAGS += $(ALSA_CFLAGS)
-CC_BINARY(looptest): \
- LDLIBS += $(ALSA_LIBS)
-clean: CLEAN(looptest)
-all: CC_BINARY(looptest)
-
-CC_BINARY(loopback_latency): $(filter \
- loopback_latency.o \
- ,$(C_OBJECTS))
-CC_BINARY(loopback_latency): \
- CFLAGS += $(ALSA_CFLAGS) $(CRAS_CFLAGS)
-CC_BINARY(loopback_latency): \
- LDLIBS += $(ALSA_LIBS) $(CRAS_LIBS)
-clean: CC_BINARY(loopback_latency)
-all: CC_BINARY(loopback_latency)
-
-CC_BINARY(cras_api_test): $(filter \
- cras_api_test.o \
- ,$(C_OBJECTS))
-CC_BINARY(cras_api_test): \
- CFLAGS += $(ALSA_CFLAGS) $(CRAS_CFLAGS)
-CC_BINARY(cras_api_test): \
- LDLIBS += $(ALSA_LIBS) $(CRAS_LIBS)
-clean: CC_BINARY(cras_api_test)
-all: CC_BINARY(cras_api_test)
-
-CC_BINARY(alsa_api_test): $(filter \
- alsa_api_test.o \
- ,$(C_OBJECTS))
-CC_BINARY(alsa_api_test): \
- CFLAGS += $(ALSA_CFLAGS)
-CC_BINARY(alsa_api_test): \
- LDLIBS += $(ALSA_LIBS)
-clean: CC_BINARY(alsa_api_test)
-all: CC_BINARY(alsa_api_test)
-
-CXX_BINARY(audiofuntest_v2): $(filter \
- audiofuntest_v2.o \
- frame_generator.o \
- connector.o \
- param_config.o \
- evaluator.o \
- ,$(CXX_OBJECTS))
-CXX_BINARY(audiofuntest_v2): \
- CPPFLAGS += -std=c++11
-clean: CLEAN(audiofuntest_v2)
-all: CXX_BINARY(audiofuntest_v2)
+all: CC_BINARY(src/loopback_latency) \
+ CC_BINARY(src/alsa_api_test) \
+ CC_BINARY(src/cras_api_test) \
+ CXX_BINARY(src/audiofuntest)
diff --git a/alsa_client.cc b/alsa_client.cc
deleted file mode 100644
index 10df892..0000000
--- a/alsa_client.cc
+++ /dev/null
@@ -1,550 +0,0 @@
-// Copyright (c) 2011 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 <set>
-#include <limits>
-
-#include "alsa_client.h"
-#include "tone_generators.h"
-
-
-namespace autotest_client {
-namespace audio {
-
-// Translates our SampleFormat type into a Alsa friendly format.
-// This is a file-local function to avoid leaking the pa_sample_format type
-// into the header.
-_snd_pcm_format SampleFormatToAlsaFormat(SampleFormat format) {
- switch (format.type()) {
- case SampleFormat::kPcmU8:
- return SND_PCM_FORMAT_U8;
-
- case SampleFormat::kPcmS16:
- return SND_PCM_FORMAT_S16_LE;
-
- case SampleFormat::kPcmS24:
- return SND_PCM_FORMAT_S24_LE;
-
- case SampleFormat::kPcmS32:
- return SND_PCM_FORMAT_S32_LE;
-
- default:
- return SND_PCM_FORMAT_UNKNOWN;
- };
-}
-
-int SampleFormatToFrameBytes(SampleFormat format, int channels) {
- switch (format.type()) {
- case SampleFormat::kPcmU8:
- return channels;
-
- case SampleFormat::kPcmS16:
- return channels * 2;
-
- case SampleFormat::kPcmS24:
- return channels * 4;
-
- case SampleFormat::kPcmS32:
- return channels * 4;
-
- default:
- return SND_PCM_FORMAT_UNKNOWN;
- };
-}
-
-template<typename T>
-double SampleToMagnitude(T sample) {
- double val = static_cast<double>(sample) / std::numeric_limits<T>::max();
- if (std::numeric_limits<T>::min() == 0) {
- val = val * 2.0 - 1.0;
- }
- return val;
-}
-
-void SampleCellToDoubleCell(void *sample_cell,
- vector<vector<double> >& double_cell,
- int num_frames,
- SampleFormat format,
- int num_channels) {
- if (format.type() == SampleFormat::kPcmU8) {
- unsigned char *ptr = static_cast<unsigned char*>(sample_cell);
- for (int n = 0; n < num_frames; n++) {
- for (int c = 0; c < num_channels; c++) {
- double_cell[c][n] = SampleToMagnitude<unsigned char>(*(ptr++));
- }
- }
-
- } else if (format.type() == SampleFormat::kPcmS16) {
- int16_t *ptr = static_cast<int16_t*>(sample_cell);
- for (int n = 0; n < num_frames; n++) {
- for (int c = 0; c < num_channels; c++) {
- double_cell[c][n] = SampleToMagnitude<int16_t>(*(ptr++));
- }
- }
-
- } else if (format.type() == SampleFormat::kPcmS24) {
- unsigned char *ptr = static_cast<unsigned char*>(sample_cell);
- for (int n = 0; n < num_frames; n++) {
- for (int c = 0; c < num_channels; c++) {
- int32_t value = 0;
- for (int i = 0; i < 3; i++) {
- value |= ((int) *(ptr++)) << (8 * i);
- }
- double_cell[c][n] = static_cast<double>(value) / (1 << 23);
- }
- }
-
- } else if (format.type() == SampleFormat::kPcmS32) {
- int32_t *ptr = static_cast<int32_t*>(sample_cell);
- for (int n = 0; n < num_frames; n++) {
- for (int c = 0; c < num_channels; c++) {
- double_cell[c][n] = SampleToMagnitude<int32_t>(*(ptr++));
- }
- }
-
- }
-}
-
-int AlsaPlaybackClient::PlaybackParam::Init(_snd_pcm* handle,
- SampleFormat format,
- int num_channels) {
- int last_error;
- FreeMemory();
- snd_pcm_uframes_t buffer_size = 0;
- snd_pcm_uframes_t period_size = 0;
- if ((last_error = snd_pcm_get_params(handle, &buffer_size,
- &period_size)) < 0) {
- return last_error;
- }
- num_frames_ = static_cast<size_t>(period_size);
- frame_bytes_ = SampleFormatToFrameBytes(format, num_channels);
- chunk_ = new char[num_frames_ * frame_bytes_];
- return 0;
-}
-
-void AlsaPlaybackClient::PlaybackParam::Print(FILE *fp) {
- fprintf(fp, " num_frames_ = %d\n", static_cast<int>(num_frames_));
- fprintf(fp, " frame_bytes_ = %d\n", frame_bytes_);
-}
-
-AlsaPlaybackClient::AlsaPlaybackClient()
- : pcm_out_handle_(NULL),
- sample_rate_(64000),
- num_channels_(2),
- format_(SampleFormat::kPcmS32),
- latency_ms_(kDefaultLatencyMs),
- state_(kCreated),
- last_error_(0),
- playback_device_("default") {
-}
-
-AlsaPlaybackClient::AlsaPlaybackClient(const std::string &playback_device)
- : pcm_out_handle_(NULL),
- sample_rate_(64000),
- num_channels_(2),
- format_(SampleFormat::kPcmS32),
- latency_ms_(kDefaultLatencyMs),
- state_(kCreated),
- last_error_(0),
- playback_device_(playback_device) {
-}
-
-AlsaPlaybackClient::~AlsaPlaybackClient() {
- if (pcm_out_handle_)
- snd_pcm_close(pcm_out_handle_);
-}
-
-bool AlsaPlaybackClient::Init(int sample_rate, SampleFormat format,
- int num_channels, std::set<int>* act_chs,
- int period_size) {
- sample_rate_ = sample_rate;
- format_ = format;
- num_channels_ = num_channels;
- active_channels_ = act_chs;
-
- /* Open pcm handle */
- if (pcm_out_handle_)
- snd_pcm_close(pcm_out_handle_);
- if ((last_error_ = snd_pcm_open(&pcm_out_handle_,
- playback_device_.c_str(),
- SND_PCM_STREAM_PLAYBACK,
- 0)) < 0) {
- pcm_out_handle_ = NULL;
- return false;
- }
-
- /* Calculate latency */
- if (period_size > 0) {
- latency_ms_ = 4000 * period_size / sample_rate;
- }
-
- /* Set format, access, num_channels, sample rate */
- char const* hwdevname = playback_device_.c_str();
- unsigned int rate_set;
- int soft_resample = 1;
- snd_pcm_hw_params_t *hwparams_;
-
- snd_pcm_hw_params_malloc(&hwparams_);
-
- if ((last_error_ = snd_pcm_hw_params_any(pcm_out_handle_, hwparams_)) < 0) {
- fprintf(stderr, "No config available for PCM device %s\n",
- hwdevname);
- goto set_hw_err;
- }
-
- if ((last_error_ = snd_pcm_hw_params_set_rate_resample(pcm_out_handle_,
- hwparams_, soft_resample)) < 0) {
- fprintf(stderr, "Resampling not available on PCM device %s\n",
- hwdevname);
- goto set_hw_err;
- }
-
- if ((last_error_ = snd_pcm_hw_params_set_access(pcm_out_handle_, hwparams_,
- SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
- fprintf(stderr, "Access type not available on PCM device %s\n",
- hwdevname);
- goto set_hw_err;
- }
-
- if ((last_error_ = snd_pcm_hw_params_set_format(pcm_out_handle_, hwparams_,
- SampleFormatToAlsaFormat(format))) < 0) {
- fprintf(stderr, "Could not set format for device %s\n", hwdevname);
- goto set_hw_err;
- }
-
- if ((last_error_ = snd_pcm_hw_params_set_channels(pcm_out_handle_, hwparams_,
- num_channels)) < 0) {
- fprintf(stderr, "Could not set channel count for device %s\n",
- hwdevname);
- goto set_hw_err;
- }
-
- rate_set = static_cast<unsigned int>(sample_rate);
- if ((last_error_ = snd_pcm_hw_params_set_rate_near(pcm_out_handle_,
- hwparams_, &rate_set, 0)) < 0) {
- fprintf(stderr, "Could not set bitrate near %u for PCM device %s\n",
- sample_rate, hwdevname);
- goto set_hw_err;
- }
-
- if (rate_set != static_cast<unsigned int>(sample_rate))
- fprintf(stderr, "Warning: Actual rate(%u) != Requested rate(%u)\n",
- rate_set,
- sample_rate);
-
- snd_pcm_hw_params_set_periods(pcm_out_handle_, hwparams_, 2, 0);
- snd_pcm_hw_params_set_period_size(pcm_out_handle_,
- hwparams_,
- period_size * num_channels,
- 0);
-
- if ((last_error_ = snd_pcm_hw_params(pcm_out_handle_, hwparams_)) < 0) {
- fprintf(stderr, "Unable to install hw params\n");
- goto set_hw_err;
- }
-
-
- /* Init playback parameter (a buffer with num_frame_ and frame_bytes) */
- if ((last_error_ = pb_param_.Init(pcm_out_handle_, format_,
- num_channels_)) < 0) {
- return false;
- }
- set_state(kReady);
-
-set_hw_err:
- if (hwparams_)
- snd_pcm_hw_params_free(hwparams_);
- return last_error_ == 0;
-}
-
-void AlsaPlaybackClient::Play(shared_ptr<CircularBuffer<char> > buffers) {
- if (state() != kReady)
- return;
-
- if ((last_error_ = snd_pcm_prepare(pcm_out_handle_)) < 0) {
- return;
- }
-
- fprintf(stderr, "Start playback recorded data\n");
-
- int num_frames = NumFrames(*buffers, format_, num_channels_);
-
- char* cell_to_read;
-
- do {
- cell_to_read = buffers->LockCellToRead();
-
- last_error_ = snd_pcm_writei(pcm_out_handle_,
- static_cast<void *>(cell_to_read),
- static_cast<snd_pcm_uframes_t>(num_frames));
- buffers->UnlockCellToRead();
- if (last_error_ < 0)
- break;
- } while (state() == kReady);
-
- // Sending latency_ms_ of silence to ensure above audio is heard. The
- // snd_pcm_drain() call takes a second or more to exit for some reason.
- int silent_chunk_count =
- 1 + sample_rate_ * latency_ms_ / 1000 / pb_param_.num_frames_;
- memset(pb_param_.chunk_, 0, pb_param_.num_frames_ * pb_param_.frame_bytes_);
- while (silent_chunk_count--) {
- last_error_ = snd_pcm_writei(
- pcm_out_handle_,
- static_cast<void *>(pb_param_.chunk_),
- static_cast<snd_pcm_uframes_t>(pb_param_.num_frames_));
- }
- set_state(kComplete);
- fprintf(stderr, "Stop playback recorded data\n");
- snd_pcm_drop(pcm_out_handle_);
-}
-
-void AlsaPlaybackClient::PlayTones() {
- if (state() != kReady)
- return;
-
-
- if ((last_error_ = snd_pcm_prepare(pcm_out_handle_)) < 0) {
- return;
- }
-
- fprintf(stderr, "Start play tone\n");
- // Run main loop until we are out of frames to generate.
- while (state() == kReady && generator_->HasMoreFrames()) {
- size_t to_write = pb_param_.num_frames_ * pb_param_.frame_bytes_;
- size_t written = to_write;
- written = generator_->GetFrames(format_, num_channels_, *active_channels_,
- pb_param_.chunk_, to_write);
-
- if (written < to_write)
- memset(pb_param_.chunk_ + written, 0, (to_write - written));
-
- last_error_ = snd_pcm_writei(
- pcm_out_handle_,
- static_cast<void *>(pb_param_.chunk_),
- static_cast<snd_pcm_uframes_t>(pb_param_.num_frames_));
- if (last_error_ < 0)
- break;
- }
-
- // Sending latency_ms_ of silence to ensure above audio is heard. The
- // snd_pcm_drain() call takes a second or more to exit for some reason.
- int silent_chunk_count =
- 1 + sample_rate_ * latency_ms_ / 1000 / pb_param_.num_frames_;
- memset(pb_param_.chunk_, 0, pb_param_.num_frames_ * pb_param_.frame_bytes_);
- while (silent_chunk_count--) {
- last_error_ = snd_pcm_writei(
- pcm_out_handle_,
- static_cast<void *>(pb_param_.chunk_),
- static_cast<snd_pcm_uframes_t>(pb_param_.num_frames_));
- }
- set_state(kComplete);
- snd_pcm_drop(pcm_out_handle_);
- fprintf(stderr, "Stop play tone\n");
-}
-
-void AlsaPlaybackClient::Print(FILE *fp) {
- fprintf(fp, "AlsaPlaybackClient::Print()\n");
- fprintf(fp, " sample_rate_ = %d\n", sample_rate_);
- fprintf(fp, " num_channels_ = %d\n", num_channels_);
- fprintf(fp, " format_ = %s\n", format_.to_string());
- fprintf(fp, " latency_ms_ = %u\n", latency_ms_);
- fprintf(fp, " buffersize = %.1fms\n",
- 1e3 * pb_param_.num_frames_ / sample_rate_);
- fprintf(fp, " pb_param_ = {\n");
- pb_param_.Print(fp);
- fprintf(fp, " }\n");
-}
-
-AlsaCaptureClient::AlsaCaptureClient()
- : pcm_capture_handle_(NULL),
- sample_rate_(64000),
- num_channels_(2),
- format_(SampleFormat::kPcmS32),
- latency_ms_(kDefaultLatencyMs),
- state_(kCreated),
- last_error_(0),
- capture_device_("default") {
-}
-
-AlsaCaptureClient::AlsaCaptureClient(const std::string &capture_device)
- : pcm_capture_handle_(NULL),
- sample_rate_(64000),
- num_channels_(2),
- format_(SampleFormat::kPcmS32),
- latency_ms_(kDefaultLatencyMs),
- state_(kCreated),
- last_error_(0),
- capture_device_(capture_device) {
-}
-
-AlsaCaptureClient::~AlsaCaptureClient() {
- if (pcm_capture_handle_)
- snd_pcm_close(pcm_capture_handle_);
- if (hwparams_)
- snd_pcm_hw_params_free(hwparams_);
-}
-
-bool AlsaCaptureClient::Init(int sample_rate, SampleFormat format,
- int num_channels, int buffer_count,
- int period_size) {
-
- sample_rate_ = sample_rate;
- format_ = format;
- num_channels_ = num_channels;
- hwparams_ = NULL;
- /* Create cpature device handle */
- if (pcm_capture_handle_)
- snd_pcm_close(pcm_capture_handle_);
-
- last_error_ = snd_pcm_open(&pcm_capture_handle_,
- capture_device_.c_str(),
- SND_PCM_STREAM_CAPTURE, 0);
- if (last_error_ < 0) {
- pcm_capture_handle_ = NULL;
- return false;
- }
-
- /* Calculate latency */
- if (period_size > 0) {
- latency_ms_ = 4000 * period_size / sample_rate;
- }
-
- /* Set format, access, num_channels, sample rate, period, resample */
- char const* hwdevname = capture_device_.c_str();
-
- unsigned int rate_set;
-
- snd_pcm_hw_params_malloc(&hwparams_);
-
- if (snd_pcm_hw_params_any(pcm_capture_handle_, hwparams_) < 0) {
- fprintf(stderr, "No config available for PCM device %s\n",
- hwdevname);
- return false;
- }
-
- int soft_resample = 1;
- if (snd_pcm_hw_params_set_rate_resample(pcm_capture_handle_, hwparams_,
- soft_resample) < 0) {
- fprintf(stderr, "Resampling not available on PCM device %s\n",
- hwdevname);
- return false;
- }
-
- if (snd_pcm_hw_params_set_access(pcm_capture_handle_, hwparams_,
- SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- fprintf(stderr, "Access type not available on PCM device %s\n",
- hwdevname);
- return false;
- }
-
- if (snd_pcm_hw_params_set_format(pcm_capture_handle_, hwparams_,
- SampleFormatToAlsaFormat(format)) < 0) {
- fprintf(stderr, "Could not set format for device %s\n", hwdevname);
- return false;
- }
-
- if (snd_pcm_hw_params_set_channels(pcm_capture_handle_, hwparams_,
- num_channels) < 0) {
- fprintf(stderr, "Could not set channel count for device %s\n",
- hwdevname);
- return false;
- }
-
- rate_set = static_cast<unsigned int>(sample_rate);
- if (snd_pcm_hw_params_set_rate_near(pcm_capture_handle_,
- hwparams_,
- &rate_set,
- 0) < 0) {
- fprintf(stderr, "Could not set bitrate near %u for PCM device %s\n",
- sample_rate, hwdevname);
- return false;
- }
-
- if (rate_set != static_cast<unsigned int>(sample_rate))
- fprintf(stderr, "Warning: Actual rate(%u) != Requested rate(%u)\n",
- rate_set,
- sample_rate);
-
- snd_pcm_hw_params_set_periods(pcm_capture_handle_, hwparams_, 3, 0);
- snd_pcm_hw_params_set_period_size(pcm_capture_handle_,
- hwparams_,
- period_size * num_channels,
- 0);
-
- if (snd_pcm_hw_params(pcm_capture_handle_, hwparams_) < 0) {
- fprintf(stderr, "Unable to install hw params\n");
- return false;
- }
-
- set_state(kReady);
-
- /* Setup circular buffer */
- snd_pcm_uframes_t actual_buffer_size = 0;
- snd_pcm_uframes_t actual_period_size = 0;
- if ((last_error_ = snd_pcm_get_params(
- pcm_capture_handle_, &actual_buffer_size, &actual_period_size)) < 0) {
- return false;
- }
- circular_buffer_.reset(
- new CircularBuffer<char>(buffer_count,
- actual_period_size * SampleFormatToFrameBytes(format, num_channels)));
- return true;
-}
-
-
-int AlsaCaptureClient::Capture() {
- ssize_t completed;
- int res;
- size_t num_frames = NumFrames(*circular_buffer_, format_, num_channels_);
-
- if (state() != kReady)
- return 1;
- if ((last_error_ = snd_pcm_prepare(pcm_capture_handle_)) < 0) {
- return 2;
- }
-
- fprintf(stderr, "Start capturing data\n");
- // Keep capturing until state() is not kReady
- res = snd_pcm_prepare(pcm_capture_handle_);
- if (res < 0) {
- fprintf(stderr, "Prepare error: %s", snd_strerror(res));
- return 3;
- }
- char* cell_to_write;
- while (state() == kReady) {
- snd_pcm_wait(pcm_capture_handle_, 100);
-
- cell_to_write = circular_buffer_->LockCellToWrite();
- completed = snd_pcm_readi(pcm_capture_handle_,
- cell_to_write,
- num_frames);
- circular_buffer_->UnlockCellToWrite();
-
- if (completed < 0) {
- fprintf(stderr, "I/O error in %s: %s, %lu\n",
- snd_pcm_stream_name(SND_PCM_STREAM_CAPTURE),
- snd_strerror(completed),
- (long unsigned int)completed);
- return 4;
- }
- }
- fprintf(stderr, "Stop capturing data\n");
- snd_pcm_drop(pcm_capture_handle_);
- return 0;
-}
-
-void AlsaCaptureClient::Print(FILE *fp) {
- fprintf(fp, "AlsaCaptureClient::Print()\n");
- fprintf(fp, " sample_rate_ = %d\n", sample_rate_);
- fprintf(fp, " num_channels_ = %d\n", num_channels_);
- fprintf(fp, " format_ = %s\n", format_.to_string());
- fprintf(fp, " latency_ms_ = %u\n", latency_ms_);
- fprintf(fp, " circular_buffer_:{\n");
- circular_buffer_->Print(fp);
- fprintf(fp, " }\n");
-}
-
-} // namespace audio
-} // namespace autotest_client
diff --git a/alsa_client.h b/alsa_client.h
deleted file mode 100644
index 449d6e5..0000000
--- a/alsa_client.h
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (c) 2010 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.
-
-#ifndef AUTOTEST_CLIENT_SITE_TESTS_AUDIO_ALSA_CLIENT_H_
-#define AUTOTEST_CLIENT_SITE_TESTS_AUDIO_ALSA_CLIENT_H_
-
-#include <alsa/asoundlib.h>
-#include <cstdio>
-#include <set>
-#include <string>
-#include <tr1/memory>
-#include <vector>
-
-#include "common.h"
-
-using std::tr1::shared_ptr;
-using std::vector;
-
-// Alsa API forward declares.
-struct _snd_pcm;
-
-namespace autotest_client {
-namespace audio {
-
-class FrameGenerator;
-
-_snd_pcm_format SampleFormatToAlsaFormat(SampleFormat format);
-
-/* Calculate number of bytes per frame given format and channels */
-int SampleFormatToFrameBytes(SampleFormat format, int channels);
-
-/*
- * Convert a sample cell (size = num_frames) into double cell.
- * If there are two channels, the sample will be averaged
- */
-void SampleCellToDoubleCell(void *sample_cell,
- vector<vector<double> >& double_cell,
- int num_frames, SampleFormat format,
- int num_channels);
-
-/*
- * Maintain a circular buffer of type T, which has a vector of <count> cells.
- * Each cell contains a vector of T with size <size>. Whenever LockCellToWrite()
- * is called, the corresponding cell is locked and the pointer to T is returned.
- * After the data was written to the cell, UnlockCellToWrite() should be called
- * which will release the mutex and signal pthread_cond_t so any blocking
- * LockCellToRead() can proceed.
- * At anytime the internal <write_index_> is strictly less than <read_index_>
- * indicating there is data to read. Otherwise LockCellToRead() will block until
- * write_index_ is increased and UnlockCellToWrite() is called.
- */
-template<typename T>
-class CircularBuffer {
- public:
- CircularBuffer(int count, int size)
- : buffer_count_(count),
- buffer_size_(size),
- write_index_(0),
- read_index_(0) {
- cell_.resize(count);
- data_.resize(count * size);
- for (int i = 0; i < count; ++i) {
- cell_[i] = data_.data() + i * size;
- }
- mutexes_.resize(count);
- has_data_.resize(count);
- for (int i = 0; i < count; ++i) {
- pthread_mutex_init(&mutexes_[i], NULL);
- pthread_cond_init(&has_data_[i], NULL);
- }
- }
-
- ~CircularBuffer() {}
-
- /* Lock mutex, return cell pointer
- * MUST call UnlockCellToWrite(); after work is done.
- */
- T* LockCellToWrite(int *index = NULL) {
- if (index) *index = write_index_;
- pthread_mutex_lock(&mutexes_[write_index_]);
- return cell_[write_index_];
- }
-
- /* Unlock mutex, release mutex and signal for has_data_ */
- void UnlockCellToWrite() {
- int last = write_index_;
- write_index_ = (write_index_ + 1) % buffer_count_;
- pthread_cond_signal(&has_data_[last]);
- pthread_mutex_unlock(&mutexes_[last]);
- }
-
- /* Lock mutex and return cell pointer.
- * MUST call UnlockCellToRead(); after work is done.
- */
- T* LockCellToRead(int *index = NULL) {
- if (index) *index = read_index_;
- pthread_mutex_lock(&mutexes_[read_index_]);
- while (read_index_ == write_index_) {
- pthread_cond_wait(&has_data_[read_index_], &mutexes_[read_index_]);
- }
- return cell_[read_index_];
- }
-
- /* Unlock mutex and increment read_index_. */
- void UnlockCellToRead() {
- int last = read_index_;
- read_index_ = (read_index_ + 1) % buffer_count_;
- pthread_mutex_unlock(&mutexes_[last]);
- }
-
- void Print(FILE *fp) {
- fprintf(fp, " buffer_count_ = %d\n", buffer_count_);
- fprintf(fp, " buffer_size_ = %d\n", buffer_size_);
- fprintf(fp, " write_index_ = %d\n", write_index_);
- fprintf(fp, " read_index_ = %d\n", read_index_);
- }
- int Count() { return buffer_count_; }
- int Size() { return buffer_size_; }
-
- private:
- int buffer_count_;
- int buffer_size_;
- int write_index_, read_index_;
- vector<T*> cell_;
- vector<T> data_;
- vector<pthread_mutex_t> mutexes_;
- vector<pthread_cond_t> has_data_;
-};
-
-inline size_t NumFrames(CircularBuffer<char> &buffers,
- SampleFormat format,
- int num_channels) {
- return buffers.Size() / SampleFormatToFrameBytes(format, num_channels);
-}
-
-class AlsaPlaybackClient {
- public:
- enum State {
- kCreated,
- kFailed,
- kTerminated,
- kReady,
- kComplete,
- };
-
- class PlaybackParam {
- friend class AlsaPlaybackClient;
- PlaybackParam() : chunk_(NULL), num_frames_(0), frame_bytes_(0) {}
- void FreeMemory() {
- if (chunk_) delete [] chunk_;
- chunk_ = NULL;
- }
- ~PlaybackParam() { FreeMemory(); }
- int Init(_snd_pcm* handle, SampleFormat format, int num_channels);
- void Print(FILE *fp);
-
- char *chunk_;
- size_t num_frames_;
- int frame_bytes_;
- };
-
- AlsaPlaybackClient();
- AlsaPlaybackClient(const std::string &playback_device);
- virtual ~AlsaPlaybackClient();
-
- virtual void Print(FILE *fp);
- void SetPlayObj(FrameGenerator* gen) { generator_ = gen; }
- FrameGenerator* PlayObj() { return generator_; }
-
- virtual bool Init(int sample_rate,
- SampleFormat format,
- int num_channels,
- std::set<int>* act_chs,
- int period_size = 0);
- virtual void PlayTones();
- virtual void Play(shared_ptr<CircularBuffer<char> > buffers);
-
- // Trivial accessors/mutators.
- virtual void set_state(State state) { state_ = state; }
- virtual State state() const { return state_; }
- virtual int last_error() const { return last_error_; }
- virtual int SampRate() const { return sample_rate_; }
- virtual int NumChannel() const { return num_channels_; }
- virtual SampleFormat Format() const { return format_; }
- virtual std::set<int>* ActiveChannels() const { return active_channels_; }
-
- private:
- static const unsigned kDefaultLatencyMs = 50;
-
- // Callback signaling completion of flushing of a stream.
- //static void StreamFlushed(int success, void* userdata);
-
- _snd_pcm* pcm_out_handle_;
- int sample_rate_;
- int num_channels_;
- SampleFormat format_;
- unsigned int latency_ms_;
- PlaybackParam pb_param_;
- std::set<int>* active_channels_;
-
- // Our abstracted version of the connection state.
- State state_;
-
- // The last error reported by Alsa. Useful for debugging.
- int last_error_;
-
- // The playback device to open.
- std::string playback_device_;
-
- // snd_pcm_set_params() argument when PlayThreadEntry() calls PlayTones()
- FrameGenerator* generator_;
-
-};
-
-
-class AlsaCaptureClient {
- public:
- enum State {
- kCreated,
- kFailed,
- kTerminated,
- kReady,
- kComplete,
- };
-
- AlsaCaptureClient();
- AlsaCaptureClient(const std::string &capture_device);
- virtual ~AlsaCaptureClient();
-
- virtual bool Init(int sample_rate, SampleFormat format, int num_channels,
- int buffer_count, int period_size = 0);
- virtual void Print(FILE *fp);
-
- virtual int Capture();
-
- // Trivial accessors/mutators.
- virtual snd_pcm_hw_params_t *get_hw_params() const { return hwparams_; }
- virtual void set_state(State state) { state_ = state; }
- virtual State state() const { return state_; }
- virtual int last_error() const { return last_error_; }
- virtual int SampRate() const { return sample_rate_; }
- virtual int NumChannel() const { return num_channels_; }
- virtual SampleFormat Format() const { return format_; }
- virtual shared_ptr<CircularBuffer<char> > Buffer() const {
- return circular_buffer_;
- }
-
- private:
- static const unsigned kDefaultLatencyMs = 50;
-
- // Callback signaling completion of flushing of a stream.
- //static void StreamFlushed(int success, void* userdata);
-
- _snd_pcm* pcm_capture_handle_;
- snd_pcm_hw_params_t *hwparams_;
- unsigned int sample_rate_;
- int num_channels_;
- SampleFormat format_;
- unsigned int latency_ms_;
-
- // Our abstracted version of the connection state.
- State state_;
-
- // The last error reported by Alsa. Useful for debugging.
- int last_error_;
-
- // The playback device to open.
- std::string capture_device_;
-
- // Circular buffer to write captured data
- shared_ptr<CircularBuffer<char> > circular_buffer_;
-
-};
-
-
-} // namespace audio
-} // namespace autotest_client
-
-#endif // AUTOTEST_CLIENT_SITE_TESTS_AUDIO_ALSA_CLIENT_H_
diff --git a/audiofuntest.cc b/audiofuntest.cc
deleted file mode 100644
index eb5827a..0000000
--- a/audiofuntest.cc
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright (c) 2011 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 <getopt.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include <set>
-#include <string>
-
-#include <fftw3.h>
-#include <alsa/asoundlib.h>
-
-#include "common.h"
-#include "alsa_client.h"
-#include "tone_generators.h"
-
-/*
- * The number of upper and lower frequency
- * bins around the center frequncy for matched filter
- */
-const int lo_bandwidth = 3;
-const int hi_bandwidth = 3;
-
-using autotest_client::audio::AlsaPlaybackClient;
-using autotest_client::audio::AlsaCaptureClient;
-using autotest_client::audio::SampleFormat;
-using autotest_client::audio::CircularBuffer;
-using autotest_client::audio::MultiToneGenerator;
-using autotest_client::audio::AudioFunTestConfig;
-using std::vector;
-
-#ifndef max
-template <typename T>
-T max(T a, T b) { return a > b ? a : b; }
-#endif
-
-#ifndef min
-template <typename T>
-T min(T a, T b) { return a < b ? a : b; }
-#endif
-
-static struct option long_options[] = {
- {"playback-device", 1, NULL, 'o'},
- {"capture-device", 1, NULL, 'i'},
- {"tone-length", 1, NULL, 'l'},
- {"format", 1, NULL, 'f'},
- {"sample-rate", 1, NULL, 'r'},
- {"start-volume", 1, NULL, 's'},
- {"end-volume", 1, NULL, 'e'},
- {"channels", 1, NULL, 'c'},
- {"active-channels", 1, NULL, 'a'},
- {"fftsize", 1, NULL, 'n'},
- {"help", 0, NULL, 'h'},
- {"verbose", 0, NULL, 'v'}
-};
-
-void ParseActiveChannels(char* arg, std::set<int>* channel_list) {
- char* tok = strtok(arg, ",");
- do {
- channel_list->insert(atoi(tok));
- } while ((tok = strtok(NULL, ",")) != NULL);
-}
-
-SampleFormat ParseFormat(const char* arg) {
- if (strcmp(arg, "u8") == 0) {
- return SampleFormat(SampleFormat::kPcmU8);
- } else if (strcmp(arg, "s16") == 0) {
- return SampleFormat(SampleFormat::kPcmS16);
- } else if (strcmp(arg, "s24") == 0) {
- return SampleFormat(SampleFormat::kPcmS24);
- } else if (strcmp(arg, "s32") == 0) {
- return SampleFormat(SampleFormat::kPcmS32);
- } else {
- return SampleFormat(SampleFormat::kPcmInvalid);
- }
-}
-
-bool ParseOptions(int argc, char* argv[], AudioFunTestConfig* config) {
- int opt = 0;
- int optindex = -1;
- while ((opt = getopt_long(argc, argv, "o:i:l:f:r:s:e:c:a:n:vh",
- long_options,
- &optindex)) != -1) {
- switch (opt) {
- case 'o':
- config->playback_alsa_device = std::string(optarg);
- break;
-
- case 'i':
- config->capture_alsa_device = std::string(optarg);
- break;
-
- case 'l':
- config->tone_length_sec = atof(optarg);
- break;
-
- case 'f':
- config->format = ParseFormat(optarg);
- break;
-
- case 'r':
- config->sample_rate = atoi(optarg);
- break;
-
- case 's':
- config->start_volume = atof(optarg);
- break;
-
- case 'e':
- config->end_volume = atof(optarg);
- break;
-
- case 'c':
- config->channels = atoi(optarg);
- break;
-
- case 'a':
- ParseActiveChannels(optarg, &config->active_channels);
- break;
-
- case 'n':
- config->fftsize = atoi(optarg);
- break;
-
- case 'v':
- config->verbose = true;
- break;
-
- case 'h':
- return false;
-
- default:
- assert(false);
- };
- }
-
- // Avoid overly short tones.
- if (config->tone_length_sec < 0.01) {
- fprintf(stderr, "Tone length too short. Must be 0.01s or greater.\n");
- return false;
- }
-
- // Normalize the active channel set to explicitly list all channels.
- if (config->active_channels.empty()) {
- for (int i = 0; i < config->channels; ++i) {
- config->active_channels.insert(i);
- }
- }
-
- return true;
-}
-
-void PrintUsage(FILE* out, const char* name) {
- AudioFunTestConfig default_config;
-
- fprintf(out, "Usage: %s [options]\n", name);
- fprintf(out,
- "\t-i, --capture-device: "
- "Name of alsa device to use (def %s).\n",
- default_config.capture_alsa_device.c_str());
- fprintf(out,
- "\t-o, --playback-device: "
- "Name of alsa device to use (def %s).\n",
- default_config.playback_alsa_device.c_str());
- fprintf(out,
- "\t-l, --tone-length: "
- "Decimal value of tone length in secs (def %0.2lf).\n",
- default_config.tone_length_sec);
- fprintf(out,
- "\t-f, --format: "
- "Sample format {u8, s16, s24, s32} to use "
- "when talking to PA (def %s).\n",
- default_config.format.to_string());
- fprintf(out,
- "\t-r, --sample-rate: "
- "Sample rate of generated wave in HZ (def %d).\n",
- default_config.sample_rate);
- fprintf(out,
- "\t-s, --start-volume: "
- "Decimal value of start volume (def %0.2lf).\n",
- default_config.start_volume);
- fprintf(out,
- "\t-e, --end-volume: "
- "Decimal value of end volume (def %0.2lf).\n",
- default_config.end_volume);
- fprintf(out,
- "\t-c, --channels: "
- "The number of channels (def %d).\n",
- default_config.channels);
- fprintf(out,
- "\t-n, --fftsize: "
- "Longer fftsize has more carriers but longer latency. (def 1024)\n");
- fprintf(out,
- "\t-a, --active-channels: "
- "Comma-separated list of channels to play on. (def all channels)\n");
- fprintf(out,
- "\t-v, --verbose: "
- "Show debugging information.\n");
- fprintf(out,
- "\t-h, --help: "
- "Show this page.\n");
-}
-
-void PrintConfig(FILE* out, const AudioFunTestConfig& config) {
- fprintf(out, "Config Values:\n");
-
- fprintf(out, "\tCapture Alsa Device: %s\n",
- config.capture_alsa_device.c_str());
- fprintf(out, "\tPlayback Alsa Device: %s\n",
- config.playback_alsa_device.c_str());
- fprintf(out, "\tFormat: %s\n", config.format.to_string());
- fprintf(out, "\tTone Length (sec): %0.2lf\n", config.tone_length_sec);
- fprintf(out, "\tSample Rate (HZ): %d\n", config.sample_rate);
- fprintf(out, "\tStart Volume (0-1.0): %0.2lf\n", config.start_volume);
- fprintf(out, "\tEnd Volume (0-1.0): %0.2lf\n", config.end_volume);
- fprintf(out, "\tChannels: %d\n", config.channels);
- fprintf(out, "\tFFTsize: %d\n", config.fftsize);
-
- fprintf(out, "\tActive Channels: ");
- for (std::set<int>::const_iterator it = config.active_channels.begin();
- it != config.active_channels.end();
- ++it) {
- fprintf(out, "%d ", *it);
- }
- fprintf(out, "\n");
-}
-
-void *PlayToneThreadEntry(void *arg) {
- AlsaPlaybackClient *client = static_cast<AlsaPlaybackClient *>(arg);
- client->PlayTones();
- return 0;
-}
-
-void *CaptureThreadEntry(void *arg) {
- AlsaCaptureClient *client = static_cast<AlsaCaptureClient *>(arg);
- client->Capture();
- return 0;
-}
-
-struct Carrier {
-
- void InitMatchedFilter(int low, int hi, double *data) {
- double mean = 0.0;
- double std = 0.0;
- lo_bin = low;
- hi_bin = hi;
- matched_filter.clear();
- for (int b = low; b <= hi; ++b) {
- matched_filter.push_back(data[b]);
- mean += data[b];
- std += data[b] * data[b];
- }
- mean /= matched_filter.size();
- std /= matched_filter.size();
- std -= mean * mean;
- std = sqrt(std);
- for (unsigned i = 0; i < matched_filter.size(); ++i) {
- matched_filter[i] -= mean;
- matched_filter[i] /= std;
- }
- }
-
- double MatchedFilterConfidence(double *data) {
- double confidence = 0.0;
- double mean = 0.0;
- double std = 0.0;
- double power_ratio = 0.0;
- for (unsigned i = 0; i < matched_filter.size(); ++i) {
- double sample = data[lo_bin + i];
- confidence += sample * matched_filter[i];
- mean += sample;
- std += sample * sample;
- }
- power_ratio = data[center_bin] / mean;
- mean /= matched_filter.size();
- std = sqrt(std / matched_filter.size() - mean * mean);
- confidence /= std * matched_filter.size();
- return power_ratio * confidence;
- }
-
- int center_bin;
- int lo_bin;
- int hi_bin;
- vector<double> matched_filter;
-
-};
-
-struct LoopParam {
- LoopParam(const AlsaCaptureClient& capture_client,
- const double low_cutoff = 1600.0,
- const double hi_cutoff = 10000.0) {
- num_frames = NumFrames(*capture_client.Buffer(), capture_client.Format(),
- capture_client.NumChannel());
- num_freq = num_frames / 2 + 1;
- num_bin = num_frames / 2;
- freq_resol = (double) capture_client.SampRate() / num_frames;
- bin_start = ceil(low_cutoff/ freq_resol);
- bin_end = ceil(hi_cutoff / freq_resol);
- if (bin_end > num_bin) bin_end = num_bin;
- num_used_bin = bin_end - bin_start;
- carriers.resize(num_used_bin / 2);
- for (int i = 0; i < num_used_bin / 2; ++i) {
- carriers[i].center_bin = bin_start + 2 * i;
- }
- target_carrier = 0;
- hwparams = capture_client.get_hw_params();
- }
- bool SetTargetCarrier(int c) {
- if (c < 0 ||
- static_cast<unsigned>(c) >= carriers.size()) {
- return false;
- } else {
- target_carrier = c;
- frequencies.resize(1);
- frequencies[0] = carriers[target_carrier].center_bin * freq_resol;
- return true;
- }
- }
- double TargetCarrierConfidence(double *data) {
- return carriers[target_carrier].MatchedFilterConfidence(data);
- }
- int TargetCarrierCenterBin() {
- return carriers[target_carrier].center_bin;
- }
- void Print(FILE* fp) {
- snd_output_t *log;
- fprintf(fp, "LoopParam::Print()\n");
- fprintf(fp, " num_frames = %d\n", num_frames);
- fprintf(fp, " num_freq = %d\n", num_freq);
- fprintf(fp, " num_bin = %d\n", num_bin);
- fprintf(fp, " freq_resol = %f\n", freq_resol);
- fprintf(fp, " bin_start = %d\n", bin_start);
- fprintf(fp, " bin_end = %d\n", bin_end);
- fprintf(fp, " num_used_bin = %d\n", num_used_bin);
- fprintf(fp, " targte_carrier = %d\n", target_carrier);
- fprintf(fp, " carriers = {\n");
-
-
- for (unsigned int i = 0; i < carriers.size(); ++i) {
- fprintf(fp, " %d: @%d(%.f) (%d, %d): {",
- i, carriers[i].center_bin, carriers[i].center_bin * freq_resol,
- carriers[i].lo_bin, carriers[i].hi_bin);
- for (unsigned int j = 0; j < carriers[i].matched_filter.size(); ++j) {
- fprintf(fp, " %d:%.3f",
- carriers[i].lo_bin + j,
- carriers[i].matched_filter[j]);
- }
- fprintf(fp, "}\n");
- }
- fprintf(fp, " }\n");
-
- fprintf(fp, "hw_params =\n");
- snd_output_stdio_attach(&log, fp, 0);
- snd_pcm_hw_params_dump(hwparams, log);
- }
- int num_frames;
- int num_freq;
- int num_bin;
- double freq_resol;
- int bin_start;
- int bin_end;
- int num_used_bin;
- vector<double> frequencies;
- vector<struct Carrier> carriers;
- int target_carrier;
- snd_pcm_hw_params_t *hwparams;
-};
-
-static double sqmag(double x[2]) {
- return x[0] * x[0] + x[1] * x[1];
-}
-
-/*
- * Estimate matched filter by giving 1 in the center
- * frequency and 0 otherwise. Then substract mean and
- * normalize variance, so the frequency response in the
- * filter has unit length (if viewed as a vector)
- */
-void EstimateFilter(struct LoopParam* parm) {
-
- vector<struct Carrier>& carriers = parm->carriers;
-
- /* Create estimated filter for each carrier */
- double *double_cell = new double[parm->num_bin];
- for (int b = 0; b < parm->num_bin; ++b) {
- double_cell[b] = 0.0;
- }
- for (unsigned c = 0; c < carriers.size(); ++c) {
- int low = max(carriers[c].center_bin - lo_bandwidth, 0);
- int hi = min(carriers[c].center_bin + hi_bandwidth, parm->num_bin - 1);
- double_cell[carriers[c].center_bin] = 1.0;
- carriers[c].InitMatchedFilter(low, hi, double_cell);
- double_cell[carriers[c].center_bin] = 0.0;
- }
- delete [] double_cell;
-}
-
-int LoopControl(AudioFunTestConfig& config) {
- srand(time(NULL) + getpid());
- /* AlsaCaptureClient */
- AlsaCaptureClient capture_client(config.capture_alsa_device);
- if (!capture_client.Init(config.sample_rate,
- config.format,
- config.channels,
- 2,
- config.fftsize)) {
- fprintf(stderr, "Unable to initialize AlsaCaputreClient: %d\n",
- capture_client.last_error());
- return 2;
- }
- if (config.verbose) capture_client.Print(stderr);
-
-
- /* AlsaPlaybackClient */
- AlsaPlaybackClient playback_client(config.playback_alsa_device);
- if (!playback_client.Init(config.sample_rate,
- config.format,
- config.channels,
- &config.active_channels,
- config.fftsize)) {
- fprintf(stderr, "Unable to initialize AlsaPlaybackClient: %d\n",
- playback_client.last_error());
- return 3;
- }
- if (config.verbose) playback_client.Print(stderr);
-
- /* Tone generator */
- MultiToneGenerator tone_generator(config.sample_rate,
- config.tone_length_sec);
- tone_generator.SetVolumes(config.start_volume, config.end_volume);
- playback_client.SetPlayObj(&tone_generator);
-
- /* Loop parameter */
- struct LoopParam loop_parm(capture_client);
-
- EstimateFilter(&loop_parm);
- if (config.verbose) loop_parm.Print(stderr);
-
- fftw_plan plan;
- fftw_complex *spectrum = static_cast<double(*)[2]>(
- fftw_malloc(sizeof(fftw_complex) * (loop_parm.num_freq)));
-
- /* Start capture and playback threads */
- playback_client.set_state(AlsaPlaybackClient::kReady);
- capture_client.set_state(AlsaCaptureClient::kReady);
- pthread_t capture_thread;
- pthread_create(&capture_thread, NULL, CaptureThreadEntry, &capture_client);
- pthread_t playback_thread;
- pthread_create(&playback_thread, NULL, PlayToneThreadEntry, &playback_client);
-
- loop_parm.SetTargetCarrier(rand() % loop_parm.carriers.size());
- tone_generator.Reset(loop_parm.frequencies);
-
- /* Start feedback */
- int delay = 0;
- vector<int> success(config.channels, 0);
- vector<int> fail(config.channels, 0);
- vector<double> accum_confidence(config.channels, 0.0);
-
- /* tmp flag the indicate channels already passed test */
- vector<bool> success_flag(config.channels, false);
- vector<vector<double> > double_cell(config.channels,
- vector<double>(loop_parm.num_frames));
- /* Analyze cell by cell */
- while(playback_client.state() ==
- autotest_client::audio::AlsaPlaybackClient::kReady) {
-
- char *sample_cell = capture_client.Buffer()->LockCellToRead();
-
- SampleCellToDoubleCell(static_cast<void *>(sample_cell),
- double_cell,
- loop_parm.num_frames,
- capture_client.Format(),
- capture_client.NumChannel());
-
- capture_client.Buffer()->UnlockCellToRead();
-
- bool all_channel_pass = true;
- for (int c = 0; c < config.channels; ++c) {
- /* For channels that already pass, bypass calculating fft and following
- * logic. */
- if (success_flag[c]) continue;
-
- plan = fftw_plan_dft_r2c_1d(loop_parm.num_frames,
- double_cell[c].data(),
- spectrum,
- FFTW_ESTIMATE);
- fftw_execute(plan);
- for (int i = 0; i < loop_parm.num_bin; ++i) {
- double_cell[c][i] = sqmag(spectrum[i]) / loop_parm.num_frames;
- }
- // Calculate spectrum energy
- double confidence = loop_parm.TargetCarrierConfidence(
- double_cell[c].data());
-
- if (confidence > 0.0) accum_confidence[c] += confidence;
- if (accum_confidence[c] >= 3.0) {
- success_flag[c] = true;
- } else {
- all_channel_pass = false;
- }
- }
-
- ++delay;
- if (!all_channel_pass && delay < 15) {
- continue;
- }
-
- /* Either success or fail */
- fprintf(stderr, "carrier = %2d, delay = %2d\n",
- loop_parm.target_carrier, delay);
-
- for (int c = 0; c < config.channels; ++c) {
- if (success_flag[c]) {
- success[c]++;
- } else {
- fail[c]++;
- }
-
- fprintf(stderr,
- "%s: channel = %2d, success = %3d, fail = %3d, rate = %.1f\n",
- success_flag[c] ? "O" : "X",
- c,
- success[c],
- fail[c],
- 100.0 * success[c] / (success[c] + fail[c]));
-
- accum_confidence[c] = 0.0;
- success_flag[c] = false;
- }
-
- delay = 0;
- int new_target_carrier;
- do {
- new_target_carrier = rand() % loop_parm.carriers.size();
- } while (new_target_carrier == loop_parm.target_carrier);
- loop_parm.SetTargetCarrier(new_target_carrier);
- tone_generator.Reset(loop_parm.frequencies);
- }
- playback_client.set_state(AlsaPlaybackClient::kTerminated);
- capture_client.set_state(AlsaCaptureClient::kTerminated);
- /* Play recorded sounds */
-
- void *status;
- pthread_join(playback_thread, &status);
- pthread_join(capture_thread, &status);
-
- return 0;
-
-}
-
-int main(int argc, char* argv[]) {
- AudioFunTestConfig config;
-
- if (!ParseOptions(argc, argv, &config)) {
- fprintf(stderr, "\n");
- PrintUsage(stderr, argv[0]);
- return 1;
- }
-
- PrintConfig(stderr, config);
-
- LoopControl(config);
-
- return 0;
-}
diff --git a/common.h b/include/common.h
similarity index 100%
rename from common.h
rename to include/common.h
diff --git a/libaudiodev.h b/include/libaudiodev.h
similarity index 100%
rename from libaudiodev.h
rename to include/libaudiodev.h
diff --git a/include/module.mk b/include/module.mk
new file mode 100644
index 0000000..7e2fa4d
--- /dev/null
+++ b/include/module.mk
@@ -0,0 +1,5 @@
+# Copyright 2016 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 common.mk
diff --git a/tone_generators.h b/include/tone_generators.h
similarity index 100%
rename from tone_generators.h
rename to include/tone_generators.h
diff --git a/libaudiodev.c b/libaudiodev.c
deleted file mode 100644
index 3e8b667..0000000
--- a/libaudiodev.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (c) 2011 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 <alsa/asoundlib.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "libaudiodev.h"
-
-#define CHANNELS 2
-#define SAMPLE_RATE 44100
-#define FORMAT SND_PCM_FORMAT_S16
-#define NON_BLOCKING 0
-#define INTERLEAVED SND_PCM_ACCESS_RW_INTERLEAVED
-
-static size_t bits_per_sample;
-static size_t bits_per_frame;
-unsigned int chunk_size;
-
-void free_device_list(audio_device_info_list_t *list) {
- int i;
-
- for (i=0; i < list->count; i++) {
- free((void *)list->devs[i].dev_id);
- free((void *)list->devs[i].dev_name);
- free((void *)list->devs[i].pcm_id);
- free((void *)list->devs[i].pcm_name);
- }
-
- free(list->devs);
- free(list);
-}
-
-int get_device_count(snd_pcm_stream_t direction) {
- int count = 0;
- int cid = -1;
- int ret;
- int dev;
- char hwname[MAX_HWNAME_SIZE];
- snd_ctl_t *handle;
- snd_ctl_card_info_t *info;
-
- snd_ctl_card_info_malloc(&info);
-
- ret = snd_card_next(&cid);
- if (ret == 0 && cid == -1) {
- printf("No %s audio devices found.\n", snd_pcm_stream_name(direction));
- }
-
- for (; cid != -1 && ret >= 0; ret = snd_card_next(&cid)) {
- snprintf(hwname, MAX_HWNAME_SIZE, "hw:%d", cid);
-
- ret = snd_ctl_open(&handle, hwname, 0);
- if (ret < 0) {
- fprintf(stderr, "Could not open card %d: %s", cid, snd_strerror(ret));
- continue;
- }
-
- ret = snd_ctl_card_info(handle, info);
- if (ret < 0) {
- fprintf(stderr, "Could not get info for card %d: %s",
- cid, snd_strerror(ret));
- snd_ctl_close(handle);
- continue;
- }
-
- dev = -1;
- ret = snd_ctl_pcm_next_device(handle, &dev);
- if (ret >= 0 && dev == -1) {
- fprintf(stderr, "Warning: No devices found on card %d\n", cid);
- }
- for (;dev != -1 && ret >= 0; ret = snd_ctl_pcm_next_device(handle, &dev)) {
- count++;
- }
- if (ret == -1) {
- fprintf(stderr, "Error reading next sound device on card %d\n", cid);
- }
- snd_ctl_close(handle);
- }
- if (ret == -1) {
- fprintf(stderr, "Error reading next sound card\n");
- }
-
- snd_ctl_card_info_free(info);
-
- return count;
-}
-
-/*
- * Refresh the list of playback or capture devices as specified by direction.
- */
-audio_device_info_list_t *get_device_list(snd_pcm_stream_t direction) {
- int i = 0;
- int cid = -1;
- int ret;
- int dev;
- char hwname[MAX_HWNAME_SIZE];
- snd_ctl_t *handle;
- snd_ctl_card_info_t *info;
- snd_pcm_info_t *pcminfo;
- audio_device_info_list_t *list = (audio_device_info_list_t *)malloc(
- sizeof(audio_device_info_list_t));
-
- list->count = get_device_count(direction);
- list->devs = (audio_device_info_t *)malloc(
- list->count * sizeof(audio_device_info_t));
-
- snd_ctl_card_info_malloc(&info);
- snd_pcm_info_malloc(&pcminfo);
-
- ret = snd_card_next(&cid);
- if (ret == 0 && cid == -1)
- printf("No %s audio devices found.\n", snd_pcm_stream_name(direction));
-
- for (; cid != -1 && ret >= 0 && i < list->count; ret = snd_card_next(&cid)) {
- snprintf(hwname, MAX_HWNAME_SIZE, "hw:%d", cid);
-
- ret = snd_ctl_open(&handle, hwname, 0);
- if (ret < 0) {
- fprintf(stderr, "Could not open card %d: %s", cid, snd_strerror(ret));
- continue;
- }
-
- ret = snd_ctl_card_info(handle, info);
- if (ret < 0) {
- fprintf(stderr, "Could not get info for card %d: %s",
- cid, snd_strerror(ret));
- snd_ctl_close(handle);
- continue;
- }
-
- dev = -1;
- ret = snd_ctl_pcm_next_device(handle, &dev);
- if (ret >= 0 && dev == -1) {
- fprintf(stderr, "Warning: No devices found on card %d\n", cid);
- }
- for (;dev != -1 && ret >= 0; ret = snd_ctl_pcm_next_device(handle, &dev)) {
- snd_pcm_info_set_device(pcminfo, dev);
- snd_pcm_info_set_subdevice(pcminfo, 0);
- snd_pcm_info_set_stream(pcminfo, direction);
- ret = snd_ctl_pcm_info(handle, pcminfo);
- if (ret < 0) {
- fprintf(stderr, "error getting device info [%d, %d]: %s\n",
- cid, dev, snd_strerror(ret));
- continue;
- }
-
- list->devs[i].card = cid;
- list->devs[i].dev_no = dev;
- list->devs[i].dev_id = strdup(snd_ctl_card_info_get_id(info));
- list->devs[i].dev_name = strdup(snd_ctl_card_info_get_name(info));
- list->devs[i].pcm_id = strdup(snd_pcm_info_get_id(pcminfo));
- list->devs[i].pcm_name = strdup(snd_pcm_info_get_name(pcminfo));
- list->devs[i].audio_device.direction = direction;
- list->devs[i].audio_device.handle = NULL;
- snprintf(list->devs[i].audio_device.hwdevname, MAX_HWNAME_SIZE,
- "plughw:%d,%d", cid, dev);
- i++;
- }
- if (ret == -1) {
- fprintf(stderr, "Error reading next sound device on card %d\n", cid);
- }
- snd_ctl_close(handle);
- }
- if (i != list->count) {
- fprintf(stderr,
- "Error: expect %d sound device(s) but read only %d device(s)\n",
- list->count, i);
- list->count = i;
- }
- if (ret == -1) {
- fprintf(stderr, "Error reading next sound card\n");
- }
-
- snd_ctl_card_info_free(info);
- snd_pcm_info_free(pcminfo);
-
- return list;
-}
-
-void close_sound_handle(audio_device_t *device) {
- if (!device || !device->handle)
- return;
-
- snd_pcm_drop(device->handle);
- snd_pcm_close(device->handle);
- device->handle = NULL;
-}
-
-/*
- * Helper to create_sound_handle. Used to set hardware parameters like
- * sample rate, channels, interleaving, etc.
- */
-static int set_hw_params(audio_device_t *device, int buffer_size,
- snd_output_t *log) {
- snd_pcm_hw_params_t *hwparams;
- unsigned int rate_set;
-
- snd_pcm_hw_params_malloc(&hwparams);
-
- if (snd_pcm_hw_params_any(device->handle, hwparams) < 0) {
- fprintf(stderr, "No config available for PCM device %s\n",
- device->hwdevname);
- return 1;
- }
- if (snd_pcm_hw_params_set_access(device->handle, hwparams, INTERLEAVED) < 0) {
- fprintf(stderr, "Access type not available on PCM device %s\n",
- device->hwdevname);
- return 2;
- }
-
- if (snd_pcm_hw_params_set_format(device->handle, hwparams, FORMAT) < 0) {
- fprintf(stderr, "Could not set format for device %s\n", device->hwdevname);
- return 3;
- }
-
- if (snd_pcm_hw_params_set_channels(device->handle, hwparams, CHANNELS) < 0) {
- fprintf(stderr, "Could not set channel count for device %s\n",
- device->hwdevname);
- return 4;
- }
-
- /* Try to set rate. Check to see if rate is actually what we requested. */
- rate_set = SAMPLE_RATE;
- if (snd_pcm_hw_params_set_rate_near(device->handle,
- hwparams, &rate_set, 0) < 0) {
- fprintf(stderr, "Could not set bitrate near %u for PCM device %s\n",
- SAMPLE_RATE, device->hwdevname);
- return 5;
- }
-
- if (rate_set != SAMPLE_RATE)
- fprintf(stderr, "Warning: Actual rate(%u) != Requested rate(%u)\n",
- rate_set, SAMPLE_RATE);
-
- snd_pcm_hw_params_set_periods(device->handle, hwparams, 2, 0);
- snd_pcm_hw_params_set_period_size(device->handle,
- hwparams,
- buffer_size / 2,
- 0);
-
- if (snd_pcm_hw_params(device->handle, hwparams) < 0) {
- fprintf(stderr, "Unable to install hw params:\n");
- snd_pcm_hw_params_dump(hwparams, log);
- return 6;
- }
-
- return 0;
-}
-
-/*
- * Helper to create_sound_handle. Set software parameters. There are
- * very few that are not deprecated.
- */
-static int set_sw_params(audio_device_t *device, int buffer_size,
- snd_output_t *log) {
- snd_pcm_sw_params_t *swparams;
- snd_pcm_sw_params_malloc(&swparams);
- snd_pcm_sw_params_current(device->handle, swparams);
-
- snd_pcm_sw_params_set_avail_min(device->handle, swparams,
- buffer_size / 2);
- snd_pcm_sw_params_set_start_threshold(device->handle, swparams,
- buffer_size / 8);
-
- if (snd_pcm_sw_params(device->handle, swparams) < 0) {
- fprintf(stderr, "Unable to install sw params:\n");
- snd_pcm_sw_params_dump(swparams, log);
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Try to open a sound handle and set all required parameters.
- */
-int create_sound_handle(audio_device_t *device, int buffer_size) {
- int ret;
- static snd_output_t *log;
-
- if (!device || device->handle)
- return 1;
-
- snd_output_stdio_attach(&log, stderr, 0);
-
- ret = snd_pcm_open(&device->handle, device->hwdevname,
- device->direction, NON_BLOCKING);
- if (ret < 0) {
- fprintf(stderr, "Could not open sound device %s: %s\n",
- device->hwdevname, snd_strerror(ret));
- snd_output_close(log);
- return 2;
- }
-
- /* Try to set non-blocking mode if requested. */
- if (NON_BLOCKING) {
- ret = snd_pcm_nonblock(device->handle, 1);
- if (ret < 0)
- fprintf(stderr, "Could not set %s to non-blocking mode: %s\n",
- device->hwdevname, snd_strerror(ret));
- }
-
- if (set_hw_params(device, buffer_size, log) ||
- set_sw_params(device, buffer_size, log)) {
- snd_pcm_close(device->handle);
- device->handle = NULL;
- snd_output_close(log);
- return 3;
- }
-
- bits_per_sample = snd_pcm_format_physical_width(FORMAT);
- bits_per_frame = bits_per_sample * CHANNELS;
- chunk_size = buffer_size * 8 / bits_per_frame;
-
- snd_output_close(log);
-
- return 0;
-}
-
-ssize_t pcm_io(audio_device_t *device, unsigned char *data, size_t count) {
- ssize_t completed;
- ssize_t result = 0;
- int res;
-
- if (device->direction == SND_PCM_STREAM_PLAYBACK && count < chunk_size) {
- snd_pcm_format_set_silence(FORMAT, data + (count * bits_per_frame / 8),
- (chunk_size - count) * CHANNELS);
- count = chunk_size;
- }
- while (count > 0) {
- if (device->direction == SND_PCM_STREAM_PLAYBACK) {
- completed = snd_pcm_writei(device->handle, data, count);
- } else {
- completed = snd_pcm_readi(device->handle, data, count);
- }
- if (completed == -EAGAIN) {
- snd_pcm_wait(device->handle, 1000);
- } else if (completed == -EPIPE) {
- res = snd_pcm_prepare(device->handle);
- if (res < 0) {
- fprintf(stderr, "Prepare error: %s", snd_strerror(res));
- exit(EXIT_FAILURE);
- }
- } else if (completed < 0) {
- fprintf(stderr, "I/O error in %s: %s, %lu\n",
- snd_pcm_stream_name(device->direction), snd_strerror(completed),
- (long unsigned int)completed);
- } else {
- result += completed;
- count -= completed;
- data += completed * bits_per_frame / 8;
- }
- }
- return result;
-}
diff --git a/looptest.c b/looptest.c
deleted file mode 100644
index 789d893..0000000
--- a/looptest.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2011 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 <signal.h>
-#include <pthread.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "libaudiodev.h"
-
-typedef struct {
- unsigned char *data;
-} audio_buffer;
-
-static int verbose = 0;
-
-static int buffer_count; // Total number of buffer
-static pthread_mutex_t buf_mutex; // This protects the variables below
-audio_buffer *buffers;
-static int write_index; // buffer should be written next
-static int read_index; // buffer should be read next
-static int write_available; // number of buffers can be write
-static int read_available; // number of buffers can be read
-static pthread_cond_t has_data;
-static struct timespec cap_start_time, play_start_time;
-static int total_cap_frames, total_play_frames;
-
-/* Termination variable. */
-static int terminate;
-
-static void set_current_time(struct timespec *ts) {
- clock_gettime(CLOCK_MONOTONIC, ts);
-}
-
-// Returns the time since the given time in nanoseconds.
-static long long since(struct timespec *ts) {
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- long long t = now.tv_sec - ts->tv_sec;
- t *= 1000000000;
- t += (now.tv_nsec - ts->tv_nsec);
- return t;
-}
-
-static void update_stat() {
- if (verbose) {
- double cap_rate = total_cap_frames * 1e9 / since(&cap_start_time);
- double play_rate = total_play_frames * 1e9 / since(&play_start_time);
- printf("Buffer: %d/%d, Capture: %d, Play: %d \r",
- read_available, buffer_count,
- (int) cap_rate, (int) play_rate);
- }
-}
-
-static void *play_loop(void *arg) {
- audio_device_t *device = (audio_device_t *)arg;
- int buf_play;
-
- pthread_mutex_lock(&buf_mutex);
- // Wait until half of the buffers are filled.
- while (!terminate && read_available < buffer_count / 2) {
- pthread_cond_wait(&has_data, &buf_mutex);
- }
-
- // Now start playing
- set_current_time(&play_start_time);
- total_play_frames = 0;
- while (!terminate) {
- while (read_available == 0) {
- pthread_cond_wait(&has_data, &buf_mutex);
- }
- buf_play = read_index;
- read_index = (read_index + 1) % buffer_count;
- read_available--;
-
- pthread_mutex_unlock(&buf_mutex);
- pcm_io(device, buffers[buf_play].data, chunk_size);
- pthread_mutex_lock(&buf_mutex);
-
- total_play_frames += chunk_size;
- write_available++;
- update_stat();
- }
- pthread_mutex_unlock(&buf_mutex);
-
- return NULL;
-}
-
-static void *cap_loop(void *arg) {
- audio_device_t *device = (audio_device_t *)arg;
- int buf_cap;
-
- pthread_mutex_lock(&buf_mutex);
- total_cap_frames = 0;
- set_current_time(&cap_start_time);
- while (!terminate) {
- // If we have no more buffer to write, drop the oldest one
- if (write_available == 0) {
- read_index = (read_index + 1) % buffer_count;
- read_available--;
- } else {
- write_available--;
- }
- buf_cap = write_index;
- write_index = (write_index + 1) % buffer_count;
-
- pthread_mutex_unlock(&buf_mutex);
- pcm_io(device, buffers[buf_cap].data, chunk_size);
- pthread_mutex_lock(&buf_mutex);
-
- total_cap_frames += chunk_size;
- read_available++;
- pthread_cond_signal(&has_data);
- update_stat();
- }
- pthread_mutex_unlock(&buf_mutex);
-
- return NULL;
-}
-
-static void signal_handler(int signal) {
- printf("Signal Caught.\n");
-
- terminate = 1;
-}
-
-static void dump_line(FILE *fp) {
- int ch;
- while ((ch = fgetc(fp)) != EOF && ch != '\n') {}
-}
-
-static void get_choice(char *direction_name, audio_device_info_list_t *list,
- int *choice) {
- int i;
- while (1) {
- printf("%s devices:\n", direction_name);
- if (list->count == 0) {
- printf("No devices :(\n");
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < list->count; i++) {
- printf("(%d)\nCard %d: %s, %s\n Device %d: %s [%s], %s", i + 1,
- list->devs[i].card, list->devs[i].dev_id,
- list->devs[i].dev_name, list->devs[i].dev_no,
- list->devs[i].pcm_id, list->devs[i].pcm_name,
- list->devs[i].audio_device.hwdevname);
- printf("\n");
- }
- printf("\nChoose one(1 - %d): ", list->count);
-
- if (scanf("%d", choice) == 0) {
- dump_line(stdin);
- printf("\nThat was an invalid choice.\n");
- } else if (*choice > 0 && *choice <= list->count) {
- break;
- } else {
- printf("\nThat was an invalid choice.\n");
- }
- }
-}
-
-static void init_buffers(int size) {
- int i;
- buffers = (audio_buffer *)malloc(buffer_count * sizeof(audio_buffer));
- if (!buffers) {
- fprintf(stderr, "Error: Could not create audio buffer array.\n");
- exit(EXIT_FAILURE);
- }
- pthread_mutex_init(&buf_mutex, NULL);
- pthread_cond_init(&has_data, NULL);
- for (i = 0; i < buffer_count; i++) {
- buffers[i].data = (unsigned char *)malloc(size);
- if (!buffers[i].data) {
- fprintf(stderr, "Error: Could not create audio buffers.\n");
- exit(EXIT_FAILURE);
- }
- }
- read_index = write_index = 0;
- read_available = 0;
- write_available = buffer_count;
-}
-
-void test(int buffer_size, unsigned int ct, char *pdev_name, char *cdev_name) {
- pthread_t capture_thread;
- pthread_t playback_thread;
- buffer_count = ct;
-
- audio_device_info_list_t *playback_list = NULL;
- audio_device_info_list_t *capture_list = NULL;
-
- // Actual playback and capture devices we use to loop. Their
- // pcm handle will be closed in close_sound_handle.
- audio_device_t playback_device;
- audio_device_t capture_device;
-
- if (pdev_name) {
- playback_device.direction = SND_PCM_STREAM_PLAYBACK;
- playback_device.handle = NULL;
- strcpy(playback_device.hwdevname, pdev_name);
- } else {
- playback_list = get_device_list(SND_PCM_STREAM_PLAYBACK);
- int pdev;
- get_choice("playback", playback_list, &pdev);
- playback_device = playback_list->devs[pdev - 1].audio_device;
- }
-
- if (cdev_name) {
- capture_device.direction = SND_PCM_STREAM_CAPTURE;
- capture_device.handle = NULL;
- strcpy(capture_device.hwdevname, cdev_name);
- } else {
- capture_list = get_device_list(SND_PCM_STREAM_CAPTURE);
- int cdev;
- get_choice("capture", capture_list, &cdev);
- capture_device = capture_list->devs[cdev - 1].audio_device;
- }
-
- init_buffers(buffer_size);
- terminate = 0;
-
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
- signal(SIGABRT, signal_handler);
-
- if (create_sound_handle(&playback_device, buffer_size) ||
- create_sound_handle(&capture_device, buffer_size))
- exit(EXIT_FAILURE);
-
- pthread_create(&playback_thread, NULL, play_loop, &playback_device);
- pthread_create(&capture_thread, NULL, cap_loop, &capture_device);
-
- pthread_join(capture_thread, NULL);
- pthread_join(playback_thread, NULL);
-
- close_sound_handle(&playback_device);
- close_sound_handle(&capture_device);
-
- if (playback_list)
- free_device_list(playback_list);
- if (capture_list)
- free_device_list(capture_list);
-
- printf("Exiting.\n");
-}
-
-int main(int argc, char **argv) {
- char *play_dev = NULL;
- char *cap_dev = NULL;
- int count = 100;
- int size = 1024;
- int arg;
-
- while ((arg = getopt(argc, argv, "i:o:c:s:v")) != -1) {
- switch(arg) {
- case 'i':
- cap_dev = optarg;
- break;
- case 'o':
- play_dev = optarg;
- break;
- case 'c':
- count = atoi(optarg);
- break;
- case 's':
- size = atoi(optarg);
- break;
- case 'v':
- verbose = 1;
- break;
- case '?':
- if (optopt == 'i' || optopt == 'o' || optopt == 'c' || optopt == 's') {
- fprintf(stderr, "Option -%c requires an argument.\n", optopt);
- } else {
- fprintf(stderr, "Unknown Option -%c.\n", optopt);
- }
- default:
- return 1;
- }
- }
-
- test(size, count, play_dev, cap_dev);
- return 0;
-}
diff --git a/alsa_api_test.c b/src/alsa_api_test.c
similarity index 100%
rename from alsa_api_test.c
rename to src/alsa_api_test.c
diff --git a/audiofuntest_v2.cc b/src/audiofuntest.cc
similarity index 100%
rename from audiofuntest_v2.cc
rename to src/audiofuntest.cc
diff --git a/connector.cc b/src/connector.cc
similarity index 100%
rename from connector.cc
rename to src/connector.cc
diff --git a/cras_api_test.c b/src/cras_api_test.c
similarity index 100%
rename from cras_api_test.c
rename to src/cras_api_test.c
diff --git a/evaluator.cc b/src/evaluator.cc
similarity index 100%
rename from evaluator.cc
rename to src/evaluator.cc
diff --git a/frame_generator.cc b/src/frame_generator.cc
similarity index 100%
rename from frame_generator.cc
rename to src/frame_generator.cc
diff --git a/loopback_latency.c b/src/loopback_latency.c
similarity index 100%
rename from loopback_latency.c
rename to src/loopback_latency.c
diff --git a/src/module.mk b/src/module.mk
new file mode 100644
index 0000000..1b3140e
--- /dev/null
+++ b/src/module.mk
@@ -0,0 +1,52 @@
+# Copyright 2016 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 common.mk
+
+CPPFLAGS += -I$(SRC)/include
+LDLIBS += -lm -lpthread
+
+ALSA_CFLAGS := $(shell $(PKG_CONFIG) --cflags alsa)
+ALSA_LIBS := $(shell $(PKG_CONFIG) --libs alsa)
+CRAS_CFLAGS := $(shell $(PKG_CONFIG) --cflags libcras)
+CRAS_LIBS := $(shell $(PKG_CONFIG) --libs libcras)
+
+CC_BINARY(src/loopback_latency): \
+ src/loopback_latency.o
+CC_BINARY(src/loopback_latency): \
+ CFLAGS += $(ALSA_CFLAGS) $(CRAS_CFLAGS)
+CC_BINARY(src/loopback_latency): \
+ LDLIBS += $(ALSA_LIBS) $(CRAS_LIBS)
+clean: CC_BINARY(src/loopback_latency)
+all: CC_BINARY(src/loopback_latency)
+
+CC_BINARY(src/alsa_api_test): \
+ src/alsa_api_test.o
+CC_BINARY(src/alsa_api_test): \
+ CFLAGS += $(ALSA_CFLAGS)
+CC_BINARY(src/alsa_api_test): \
+ LDLIBS += $(ALSA_LIBS)
+clean: CC_BINARY(src/alsa_api_test)
+all: CC_BINARY(src/alsa_api_test)
+
+CC_BINARY(src/cras_api_test): \
+ src/cras_api_test.o
+CC_BINARY(src/cras_api_test): \
+ CFLAGS += $(ALSA_CFLAGS) $(CRAS_CFLAGS)
+CC_BINARY(src/cras_api_test): \
+ LDLIBS += $(ALSA_LIBS) $(CRAS_LIBS)
+clean: CC_BINARY(src/cras_api_test)
+all: CC_BINARY(src/cras_api_test)
+
+
+CXX_BINARY(src/audiofuntest): \
+ src/audiofuntest.o \
+ src/frame_generator.o \
+ src/connector.o \
+ src/param_config.o \
+ src/evaluator.o
+CXX_BINARY(src/audiofuntest): \
+ CPPFLAGS += -std=c++11 -I$(SRC)
+clean: CLEAN(src/audiofuntest)
+all: CXX_BINARY(src/audiofuntest)
diff --git a/param_config.cc b/src/param_config.cc
similarity index 100%
rename from param_config.cc
rename to src/param_config.cc
diff --git a/test_tones.cc b/test_tones.cc
deleted file mode 100644
index d6fe6e7..0000000
--- a/test_tones.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2010 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.
-
-// Simple playback test drivers. Plays test tones using the native Alsa
-// API allowing for configuration of volume, frequency, channels of output,
-// etc. See the output of PrintUsage() for instructions on how to use.
-
-#include <getopt.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <set>
-#include <string>
-
-#include "common.h"
-#include "alsa_client.h"
-#include "tone_generators.h"
-
-using autotest_client::audio::ASharpMinorGenerator;
-using autotest_client::audio::AlsaPlaybackClient;
-using autotest_client::audio::SampleFormat;
-using autotest_client::audio::MultiToneGenerator;
-using autotest_client::audio::TestConfig;
-
-static struct option long_options[] = {
- {"test-type", 1, NULL, 't'},
- {"alsa-device", 1, NULL, 'd'},
- {"tone-length", 1, NULL, 'l'},
- {"frequency", 1, NULL, 'h'},
- {"format", 1, NULL, 'f'},
- {"sample-rate", 1, NULL, 'r'},
- {"start-volume", 1, NULL, 's'},
- {"end-volume", 1, NULL, 'e'},
- {"channels", 1, NULL, 'c'},
- {"active-channels", 1, NULL, 'a'},
-};
-
-TestConfig::TestType ParseTestType(const char* option) {
- if (strcmp(option, "scale") == 0) {
- return TestConfig::kASharpMinorScale;
- } else if (strcmp(option, "tone") == 0) {
- return TestConfig::kSingleTone;
- }
- return TestConfig::kInvalid;
-}
-
-void ParseActiveChannels(char* arg, std::set<int>* channel_list) {
- char* tok = strtok(arg, ",");
- do {
- channel_list->insert(atoi(tok));
- } while ((tok = strtok(NULL, ",")) != NULL);
-}
-
-SampleFormat ParseFormat(const char* arg) {
- if (strcmp(arg, "u8") == 0) {
- return SampleFormat(SampleFormat::kPcmU8);
- } else if (strcmp(arg, "s16") == 0) {
- return SampleFormat(SampleFormat::kPcmS16);
- } else if (strcmp(arg, "s24") == 0) {
- return SampleFormat(SampleFormat::kPcmS24);
- } else if (strcmp(arg, "s32") == 0) {
- return SampleFormat(SampleFormat::kPcmS32);
- } else {
- return SampleFormat(SampleFormat::kPcmInvalid);
- }
-}
-
-bool ParseOptions(int argc, char* argv[], TestConfig* config) {
- int opt = 0;
- int optindex = -1;
- while ((opt = getopt_long(argc, argv, "t:d:l:f:h:r:s:e:c:a:",
- long_options,
- &optindex)) != -1) {
- switch (opt) {
- case 't':
- config->type = ParseTestType(optarg);
- break;
-
- case 'd':
- config->alsa_device = std::string(optarg);
- break;
-
- case 'l':
- config->tone_length_sec = atof(optarg);
- break;
-
- case 'f':
- config->format = ParseFormat(optarg);
- break;
-
- case 'h':
- config->frequency = atof(optarg);
- break;
-
- case 'r':
- config->sample_rate = atoi(optarg);
- break;
-
- case 's':
- config->start_volume = atof(optarg);
- break;
-
- case 'e':
- config->end_volume = atof(optarg);
- break;
-
- case 'c':
- config->channels = atoi(optarg);
- break;
-
- case 'a':
- ParseActiveChannels(optarg, &config->active_channels);
- break;
-
- default:
- assert(false);
- };
- }
-
- if (config->type == TestConfig::kInvalid) {
- fprintf(stderr, "Test type must be \"scale\" or \"tone\"\n");
- return false;
- }
-
- // Avoid overly short tones.
- if (config->tone_length_sec < 0.01) {
- fprintf(stderr, "Tone length too short. Must be 0.01s or greater.\n");
- return false;
- }
-
- // Normalize the active channel set to explicitly list all channels.
- if (config->active_channels.empty()) {
- for (int i = 0; i < config->channels; ++i) {
- config->active_channels.insert(i);
- }
- }
-
- return true;
-}
-
-void PrintUsage(FILE* out, const char* name) {
- TestConfig default_config;
-
- fprintf(out, "Usage: %s [options]\n", name);
- fprintf(out, "\t-t, --test-type: \"scale\" or \"tone\"\n");
- fprintf(out, "\t-d, --alsa-device: "
- "Name of alsa device to use (def %s).\n",
- default_config.alsa_device.c_str());
- fprintf(out,
- "\t-l, --tone-length: "
- "Decimal value of tone length in secs (def %0.2lf).\n",
- default_config.tone_length_sec);
- fprintf(out,
- "\t-h, --frequency: "
- "Tone frequency in HZ (def %0.2lf). Used if -T tone.\n",
- default_config.frequency);
- fprintf(out,
- "\t-f, --format: "
- "Sample format to use when talking to PA (def %s).\n",
- default_config.format.to_string());
- fprintf(out,
- "\t-r, --sample-rate: "
- "Sample rate of generated wave in HZ (def %d).\n",
- default_config.sample_rate);
- fprintf(out,
- "\t-s, --start-volume: "
- "Decimal value of start volume (def %0.2lf).\n",
- default_config.start_volume);
- fprintf(out,
- "\t-e, --end-volume: "
- "Decimal value of end volume (def %0.2lf).\n",
- default_config.end_volume);
- fprintf(out,
- "\t-c, --channels: "
- "The number of channels (def %d).\n",
- default_config.channels);
- fprintf(out,
- "\t-a, --active-channels: "
- "Comma-separated list of channels to play on. (def all channels)\n");
- fprintf(out, "\nThe volume of the sample will be a linear ramp over the "
- "duration of playback. The tone length, in scale mode, is the "
- "length of each individual tone in the scale.\n\n");
-}
-
-void PrintConfig(FILE* out, const TestConfig& config) {
- fprintf(out, "Config Values:\n");
- if (config.type == TestConfig::kASharpMinorScale) {
- fprintf(out, "\tType: A#Minor Scale\n");
- } else if (config.type == TestConfig::kSingleTone) {
- fprintf(out, "\tType: Single Tone\n");
- fprintf(out, "\tFrequency: %0.2lf\n", config.frequency);
- }
-
- fprintf(out, "\tAlsa Device: %s\n", config.alsa_device.c_str());
- fprintf(out, "\tFormat: %s\n", config.format.to_string());
- fprintf(out, "\tTone Length (sec): %0.2lf\n", config.tone_length_sec);
- fprintf(out, "\tSample Rate (HZ): %d\n", config.sample_rate);
- fprintf(out, "\tStart Volume (0-1.0): %0.2lf\n", config.start_volume);
- fprintf(out, "\tEnd Volume (0-1.0): %0.2lf\n", config.end_volume);
- fprintf(out, "\tChannels: %d\n", config.channels);
-
- fprintf(out, "\tActive Channels: ");
- for (std::set<int>::const_iterator it = config.active_channels.begin();
- it != config.active_channels.end();
- ++it) {
- fprintf(out, "%d ", *it);
- }
- fprintf(out, "\n");
-}
-
-int main(int argc, char* argv[]) {
- TestConfig config;
-
- if (!ParseOptions(argc, argv, &config)) {
- fprintf(stderr, "\n"); // Newline before usage.
- PrintUsage(stderr, argv[0]);
- return 1;
- }
-
- PrintConfig(stdout, config);
-
- AlsaPlaybackClient client(config.alsa_device);
- if (!client.Init(config.sample_rate,
- config.format,
- config.channels,
- &config.active_channels)) {
- fprintf(stderr, "Unable to initialize Alsa: %d\n",
- client.last_error());
- return 1;
- }
-
- if (config.type == TestConfig::kASharpMinorScale) {
- ASharpMinorGenerator scale_generator(config.sample_rate,
- config.tone_length_sec);
- scale_generator.SetVolumes(config.start_volume, config.end_volume);
- client.SetPlayObj(&scale_generator);
- client.PlayTones();
- } else {
- MultiToneGenerator tone_generator(config.sample_rate,
- config.tone_length_sec);
- tone_generator.SetVolumes(config.start_volume, config.end_volume);
- tone_generator.Reset(config.frequency);
- client.SetPlayObj(&tone_generator);
- client.PlayTones();
- }
-
- return 0;
-}
diff --git a/tone_generators.cc b/tone_generators.cc
deleted file mode 100644
index 8b2d0c1..0000000
--- a/tone_generators.cc
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) 2010 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 "tone_generators.h"
-
-#include <assert.h>
-#include <cstdio>
-#include <limits>
-
-namespace autotest_client {
-namespace audio {
-
-namespace {
-
-template <typename T>
-void* WriteSample(void* data, double magnitude) {
- // Handle unsigned.
- if (std::numeric_limits<T>::min() == 0) {
- magnitude += 1.0;
- magnitude /= 2.0;
- }
-
- T* sample_data = reinterpret_cast<T*>(data);
- *sample_data = magnitude * std::numeric_limits<T>::max();
- return sample_data + 1;
-}
-
-void* WriteSampleForFormat(void* data, double magnitude, SampleFormat format) {
- if (format.type() == SampleFormat::kPcmU8) {
- return WriteSample<unsigned char>(data, magnitude);
-
- } else if (format.type() == SampleFormat::kPcmS16) {
- return WriteSample<int16_t>(data, magnitude);
-
- } else if (format.type() == SampleFormat::kPcmS24) {
- unsigned char* sample_data = reinterpret_cast<unsigned char*>(data);
- int32_t value = magnitude * (1 << 23); // 1 << 23 24-bit singed max().
- sample_data[0] = value & 0xff;
- sample_data[1] = (value >> 8) & 0xff;
- sample_data[2] = (value >> 16) & 0xff;
- return sample_data + 3;
-
- } else if (format.type() == SampleFormat::kPcmS32) {
- return WriteSample<int32_t>(data, magnitude);
- }
-
- // Return NULL, which should crash the caller.
- assert(false);
- return NULL;
-}
-
-} // namespace
-
-
-MultiToneGenerator::MultiToneGenerator(int sample_rate, double length_sec)
- : frames_generated_(0),
- frames_wanted_(length_sec * sample_rate),
- fade_frames_(0), // Calculated below.
- sample_rate_(sample_rate),
- cur_vol_(1.0),
- start_vol_(1.0),
- inc_vol_(0.0) {
-
- // Use a fade of 2.5ms at both the start and end of a tone .
- const double kFadeTimeSec = 0.005;
-
- // Only fade if the fade won't take more than 1/2 the tone.
- if (length_sec > (kFadeTimeSec * 4)) {
- fade_frames_ = kFadeTimeSec * sample_rate;
- }
-
- frequencies_.clear();
- pthread_mutex_init(¶m_mutex, NULL);
-}
-
-MultiToneGenerator::~MultiToneGenerator() {
- pthread_mutex_destroy(¶m_mutex);
-}
-
-void MultiToneGenerator::SetVolumes(double start_vol, double end_vol) {
- pthread_mutex_lock(¶m_mutex);
- cur_vol_ = start_vol_ = start_vol;
- inc_vol_ = (end_vol - start_vol) / frames_wanted_;
- pthread_mutex_unlock(¶m_mutex);
-}
-
-void MultiToneGenerator::Reset(const std::vector<double> &frequencies,
- bool reset_timer) {
- pthread_mutex_lock(¶m_mutex);
- frequencies_ = frequencies;
- if (reset_timer) {
- frames_generated_ = 0;
- cur_vol_ = start_vol_;
- }
- pthread_mutex_unlock(¶m_mutex);
-}
-
-void MultiToneGenerator::Reset(const double *frequency, unsigned int ntones,
- bool reset_timer) {
- pthread_mutex_lock(¶m_mutex);
- frequencies_.resize(ntones);
- for (unsigned int i = 0; i < ntones; ++i) {
- frequencies_[i] = frequency[i];
- }
- if (reset_timer) {
- frames_generated_ = 0;
- cur_vol_ = start_vol_;
- }
- pthread_mutex_unlock(¶m_mutex);
-}
-
-void MultiToneGenerator::Reset(double frequency, bool reset_timer) {
- pthread_mutex_lock(¶m_mutex);
- frequencies_.resize(1);
- frequencies_[0] = frequency;
- if (reset_timer) {
- frames_generated_ = 0;
- cur_vol_ = start_vol_;
- }
- pthread_mutex_unlock(¶m_mutex);
-}
-
-size_t MultiToneGenerator::GetFrames(SampleFormat format,
- int channels,
- const std::set<int>& active_channels,
- void* data,
- size_t buf_size) {
- const size_t kBytesPerFrame = channels * format.bytes();
- void* cur = data;
- size_t frames = buf_size / kBytesPerFrame;
- size_t frames_written;
- pthread_mutex_lock(¶m_mutex);
- tone_wave_.resize(frequencies_.size());
- for (frames_written = 0; frames_written < frames; ++frames_written) {
- if (!HasMoreFrames()) {
- break;
- }
-
- double frame_magnitude = 0;
- for (unsigned int f = 0; f < frequencies_.size(); ++f) {
- frame_magnitude += tone_wave_[f].Next(sample_rate_, frequencies_[f]);
- }
- frame_magnitude *= GetFadeMagnitude() * cur_vol_;
- if (frequencies_.size() > 1) {
- frame_magnitude /= static_cast<double>(frequencies_.size());
- }
- //printf("%f\n", frame_magnitude);
- cur_vol_ += inc_vol_;
- for (int c = 0; c < channels; ++c) {
- if (active_channels.find(c) != active_channels.end()) {
- cur = WriteSampleForFormat(cur, frame_magnitude, format);
- } else {
- // Silence the non-active channels.
- cur = WriteSampleForFormat(cur, 0.0f, format);
- }
- }
-
- ++frames_generated_;
- }
- pthread_mutex_unlock(¶m_mutex);
- return frames_written * kBytesPerFrame;
-}
-
-bool MultiToneGenerator::HasMoreFrames() const {
- return frames_generated_ < frames_wanted_;
-}
-
-double MultiToneGenerator::GetFadeMagnitude() const {
- int frames_left = frames_wanted_ - frames_generated_;
- if (frames_generated_ < fade_frames_) { // Fade in.
- return sin(kHalfPi * frames_generated_ / fade_frames_);
- } else if (frames_left < fade_frames_) { // Fade out.
- return sin(kHalfPi * frames_left / fade_frames_);
- } else {
- return 1.0f;
- }
-}
-
-// A# minor harmoic scale is: A#, B# (C), C#, D#, E# (F), F#, G## (A).
-const double ASharpMinorGenerator::kNoteFrequencies[] = {
- 466.16, 523.25, 554.37, 622.25, 698.46, 739.99, 880.00, 932.33,
- 932.33, 880.00, 739.99, 698.46, 622.25, 554.37, 523.25, 466.16,
-};
-
-ASharpMinorGenerator::ASharpMinorGenerator(int sample_rate,
- double tone_length_sec)
- : tone_generator_(sample_rate, tone_length_sec),
- cur_note_(0) {
- tone_generator_.Reset(kNoteFrequencies[cur_note_], true);
-}
-
-ASharpMinorGenerator::~ASharpMinorGenerator() {
-}
-
-void ASharpMinorGenerator::SetVolumes(double start_vol, double end_vol) {
- tone_generator_.SetVolumes(start_vol, end_vol);
-}
-
-void ASharpMinorGenerator::Reset() {
- cur_note_ = 0;
- tone_generator_.Reset(kNoteFrequencies[cur_note_], true);
-}
-
-size_t ASharpMinorGenerator::GetFrames(SampleFormat format,
- int channels,
- const std::set<int>& active_channels,
- void* data,
- size_t buf_size) {
- if (!HasMoreFrames()) {
- return 0;
- }
-
- // Go to next note if necessary.
- if (!tone_generator_.HasMoreFrames()) {
- tone_generator_.Reset(kNoteFrequencies[++cur_note_], true);
- }
-
- return tone_generator_.GetFrames(format,
- channels,
- active_channels,
- data,
- buf_size);
-}
-
-bool ASharpMinorGenerator::HasMoreFrames() const {
- return cur_note_ < kNumNotes - 1 || tone_generator_.HasMoreFrames();
-}
-
-} // namespace audio
-} // namespace autotest_client