blob: 55deeedc1b48d281afd5a92dfb72cce08f1e5899 [file] [log] [blame]
// 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 "include/connector.h"
#include <assert.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
namespace autotest_client {
namespace audio {
void PlayClient::InitProcess(bool log_to_file) {
int pipe_fd[2];
bool fifo_mode = false;
if (!fifo_name_.empty()) { // use fifo
mkfifo(fifo_name_.c_str(), 0600);
fifo_mode = true;
} else if (pipe(pipe_fd) < 0) {
perror("Failed to create pipe for player program");
exit(EXIT_FAILURE);
}
child_pid_ = fork();
if (child_pid_ < 0) {
perror("Failed to fork for player program");
} else if (child_pid_ == 0) { // child
if (!fifo_mode) {
dup2(pipe_fd[0], STDIN_FILENO);
close(pipe_fd[1]);
}
// Writes log to file if set.
if (log_to_file) {
int file_err = open("recorder.err",
O_WRONLY | O_TRUNC | O_CREAT, S_IRWXU);
assert(file_err > 0);
dup2(file_err, STDERR_FILENO);
}
if (player_.Exec() < 0) {
perror("Exec player");
kill(getppid(), SIGKILL);
exit(EXIT_FAILURE);
}
} else { // parent
if (fifo_mode) {
play_fd_ = open(fifo_name_.c_str(), O_WRONLY);
} else {
play_fd_ = pipe_fd[1];
close(pipe_fd[0]);
}
}
}
int PlayClient::Play(const vector< vector<double> > &block,
unsigned num_frames) {
size_t buf_size = num_frames * num_channels_ * format_.bytes();
char *buf = new char[buf_size];
if (num_frames > max_num_frames_) {
cerr << "Request value: " << num_frames
<< " > Maximum frames capability: " << max_num_frames_ << endl;
num_frames = max_num_frames_;
}
void *cur = buf;
for (unsigned f = 0; f < num_frames; ++f) {
for (int ch = 0; ch < num_channels_; ++ch) {
cur = WriteSample(block[ch][f], cur, format_);
}
}
int res;
int cur_write = buf_size;
// Keep writing to pipe until error or finishing.
while ((res = write(play_fd_, buf, cur_write)) < cur_write) {
if (res < 0) {
return res;
}
buf += res;
cur_write -= res;
}
return num_frames;
}
void PlayClient::Terminate() {
kill(child_pid_, SIGINT);
close(play_fd_);
}
void RecordClient::InitProcess(bool log_to_file) {
int pipe_fd[2];
/* fifo OR pipe */
bool fifo_mode = false;
if (!fifo_name_.empty()) { // use fifo
mkfifo(fifo_name_.c_str(), 0600);
fifo_mode = true;
} else if (pipe(pipe_fd) < 0) { // stdout
perror("Failed to create pipe for recorder program");
exit(EXIT_FAILURE);
}
child_pid_ = fork();
if (child_pid_ < 0) {
perror("Failed to fork for recorder");
} else if (child_pid_ == 0) { // child
if (!fifo_mode) {
dup2(pipe_fd[1], STDOUT_FILENO);
close(pipe_fd[0]);
}
// Writes log to file if set.
if (log_to_file) {
int file_err = open("recorder.err",
O_WRONLY | O_TRUNC | O_CREAT, S_IRWXU);
assert(file_err > 0);
dup2(file_err, STDERR_FILENO);
}
if (recorder_.Exec() < 0) {
perror("Failed to exec recorder");
kill(getppid(), SIGKILL);
exit(EXIT_FAILURE);
}
} else { // parent
if (fifo_mode) {
record_fd_ = open(fifo_name_.c_str(), O_RDWR);
} else {
record_fd_ = pipe_fd[0];
close(pipe_fd[1]);
}
}
}
int RecordClient::Record(vector< vector<double> > *sample_ptr,
unsigned num_frames) {
size_t bufsize = num_frames * num_channels_ * format_.bytes();
char *buf = new char[bufsize];
int res = read(record_fd_, buf, bufsize);
if (res <= 0)
return res;
FramesToSamples(buf, bufsize, num_channels_, sample_ptr, format_);
delete [] buf;
// Returns number of frames read.
return res / (num_channels_ * format_.bytes());
}
void RecordClient::Terminate() {
kill(child_pid_, SIGINT);
close(record_fd_);
}
} // namespace audio
} // namespace autotest_client