Skip to content

Commit

Permalink
roc-streaminggh-246 Sox backend refinements
Browse files Browse the repository at this point in the history
- Pass driver type to SoxSource/SoxSink ctor.

- Check or populate SampleSpec in ctor depending on
  driver type (file or device).

- In SoxSink, populate with defaults all fields (format,
  channels, rate) for files, and all except rate for
  devices.

  (If we don't popolate rate for device, sox will pick
   a rate natively supported by device, which is good.
   But if we don't populate channels, sox will pick
   mono, which is a bad default. So if channels are not
   specified, we select stereo).

- In SoxSource, forbid non-empty SampleSpec for files.
  For devices, populate all fields except rate.

- Remove panic.
  • Loading branch information
gavv committed Apr 9, 2024
1 parent 913093a commit d207243
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ IDevice* SoxBackend::open_device(DeviceType device_type,

switch (device_type) {
case DeviceType_Sink: {
core::ScopedPtr<SoxSink> sink(new (arena) SoxSink(arena, config), arena);
core::ScopedPtr<SoxSink> sink(new (arena) SoxSink(arena, config, driver_type),
arena);
if (!sink || !sink->is_valid()) {
roc_log(LogDebug, "sox backend: can't construct sink: driver=%s path=%s",
driver, path);
Expand All @@ -271,7 +272,8 @@ IDevice* SoxBackend::open_device(DeviceType device_type,
} break;

case DeviceType_Source: {
core::ScopedPtr<SoxSource> source(new (arena) SoxSource(arena, config), arena);
core::ScopedPtr<SoxSource> source(
new (arena) SoxSource(arena, config, driver_type), arena);
if (!source || !source->is_valid()) {
roc_log(LogDebug, "sox backend: can't construct source: driver=%s path=%s",
driver, path);
Expand Down
83 changes: 49 additions & 34 deletions src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,47 @@
namespace roc {
namespace sndio {

SoxSink::SoxSink(core::IArena& arena, const Config& config)
SoxSink::SoxSink(core::IArena& arena, const Config& config, DriverType type)
: output_(NULL)
, buffer_(arena)
, buffer_size_(0)
, is_file_(false)
, valid_(false) {
BackendMap::instance();

if (config.sample_spec.num_channels() == 0) {
roc_log(LogError, "sox sink: # of channels is zero");
if (config.latency != 0) {
roc_log(LogError, "sox sink: setting io latency not supported by sox backend");
return;
}

if (config.latency != 0) {
roc_log(LogError, "sox sink: setting io latency not supported by sox backend");
sample_spec_ = config.sample_spec;

if (type == DriverType_File) {
sample_spec_.use_defaults(audio::Sample_RawFormat, audio::ChanLayout_Surround,
audio::ChanOrder_Smpte, audio::ChanMask_Surround_Stereo,
44100);
} else {
sample_spec_.use_defaults(audio::Sample_RawFormat, audio::ChanLayout_Surround,
audio::ChanOrder_Smpte, audio::ChanMask_Surround_Stereo,
0);
}

if (!sample_spec_.is_raw()) {
roc_log(LogError, "sox sink: sample format can be only \"-\" or \"%s\"",
audio::pcm_format_to_str(audio::Sample_RawFormat));
return;
}

frame_length_ = config.frame_length;
sample_spec_ = config.sample_spec;

if (frame_length_ == 0) {
roc_log(LogError, "sox sink: frame length is zero");
return;
}

memset(&out_signal_, 0, sizeof(out_signal_));
out_signal_.rate = (sox_rate_t)config.sample_spec.sample_rate();
out_signal_.channels = (unsigned)config.sample_spec.num_channels();
out_signal_.rate = (sox_rate_t)sample_spec_.sample_rate();
out_signal_.channels = (unsigned)sample_spec_.num_channels();
out_signal_.precision = SOX_SAMPLE_PRECISION;

valid_ = true;
Expand Down Expand Up @@ -108,29 +120,17 @@ audio::SampleSpec SoxSink::sample_spec() const {
roc_panic_if(!valid_);

if (!output_) {
roc_panic("sox sink: sample_rate(): non-open output file or device");
}

if (output_->signal.channels == 1) {
return audio::SampleSpec(size_t(output_->signal.rate), audio::Sample_RawFormat,
audio::ChanLayout_Surround, audio::ChanOrder_Smpte,
audio::ChanMask_Surround_Mono);
}

if (output_->signal.channels == 2) {
return audio::SampleSpec(size_t(output_->signal.rate), audio::Sample_RawFormat,
audio::ChanLayout_Surround, audio::ChanOrder_Smpte,
audio::ChanMask_Surround_Stereo);
roc_panic("sox sink: not opened");
}

roc_panic("sox sink: unsupported channel count");
return sample_spec_;
}

core::nanoseconds_t SoxSink::latency() const {
roc_panic_if(!valid_);

if (!output_) {
roc_panic("sox sink: latency(): non-open output file or device");
roc_panic("sox sink: not opened");
}

return 0;
Expand All @@ -140,7 +140,7 @@ bool SoxSink::has_latency() const {
roc_panic_if(!valid_);

if (!output_) {
roc_panic("sox sink: has_latency(): non-open output file or device");
roc_panic("sox sink: not opened");
}

return false;
Expand All @@ -150,7 +150,7 @@ bool SoxSink::has_clock() const {
roc_panic_if(!valid_);

if (!output_) {
roc_panic("sox sink: has_clock(): non-open output file or device");
roc_panic("sox sink: not opened");
}

return !is_file_;
Expand Down Expand Up @@ -208,25 +208,40 @@ bool SoxSink::open_(const char* driver, const char* path) {

is_file_ = !(output_->handler.flags & SOX_FILE_DEVICE);

unsigned long in_rate = (unsigned long)out_signal_.rate;
unsigned long out_rate = (unsigned long)output_->signal.rate;
const unsigned long requested_rate = (unsigned long)out_signal_.rate;
const unsigned long actual_rate = (unsigned long)output_->signal.rate;

if (requested_rate != 0 && requested_rate != actual_rate) {
roc_log(LogError,
"sox sink:"
" can't open output file or device with the requested sample rate:"
" required_by_output=%lu requested_by_user=%lu",
actual_rate, requested_rate);
return false;
}

const unsigned long requested_chans = (unsigned long)out_signal_.channels;
const unsigned long actual_chans = (unsigned long)output_->signal.channels;

if (in_rate != 0 && in_rate != out_rate) {
if (requested_chans != 0 && requested_chans != actual_chans) {
roc_log(LogError,
"sox sink:"
" can't open output file or device with the required sample rate:"
" can't open output file or device with the requested channel count:"
" required_by_output=%lu requested_by_user=%lu",
out_rate, in_rate);
actual_chans, requested_chans);
return false;
}

sample_spec_.set_sample_rate((unsigned long)output_->signal.rate);
sample_spec_.set_sample_rate(actual_rate);
sample_spec_.channel_set().set_layout(audio::ChanLayout_Surround);
sample_spec_.channel_set().set_order(audio::ChanOrder_Smpte);
sample_spec_.channel_set().set_range(0, actual_chans - 1);

roc_log(LogInfo,
"sox sink:"
" opened: bits=%lu out_rate=%lu in_rate=%lu ch=%lu is_file=%d",
(unsigned long)output_->encoding.bits_per_sample, out_rate, in_rate,
(unsigned long)output_->signal.channels, (int)is_file_);
" opened: bits=%lu rate=%lu req_rate=%lu chans=%lu req_chans=%lu is_file=%d",
(unsigned long)output_->encoding.bits_per_sample, actual_rate, requested_rate,
actual_chans, requested_chans, (int)is_file_);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "roc_core/stddefs.h"
#include "roc_packet/units.h"
#include "roc_sndio/config.h"
#include "roc_sndio/driver.h"
#include "roc_sndio/isink.h"

namespace roc {
Expand All @@ -33,7 +34,7 @@ namespace sndio {
class SoxSink : public ISink, public core::NonCopyable<> {
public:
//! Initialize.
SoxSink(core::IArena& arena, const Config& config);
SoxSink(core::IArena& arena, const Config& config, DriverType type);

virtual ~SoxSink();

Expand Down
94 changes: 54 additions & 40 deletions src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace roc {
namespace sndio {

SoxSource::SoxSource(core::IArena& arena, const Config& config)
SoxSource::SoxSource(core::IArena& arena, const Config& config, DriverType type)
: driver_name_(arena)
, input_name_(arena)
, buffer_(arena)
Expand All @@ -31,17 +31,35 @@ SoxSource::SoxSource(core::IArena& arena, const Config& config)
return;
}

frame_length_ = config.frame_length;

sample_spec_ = config.sample_spec;

if (type == DriverType_File) {
if (!sample_spec_.is_empty()) {
roc_log(LogError, "sox source: setting io encoding for files not supported");
return;
}
} else {
sample_spec_.use_defaults(audio::Sample_RawFormat, audio::ChanLayout_Surround,
audio::ChanOrder_Smpte, audio::ChanMask_Surround_Stereo,
0);

if (!sample_spec_.is_raw()) {
roc_log(LogError, "sox sink: sample format can be only \"-\" or \"%s\"",
audio::pcm_format_to_str(audio::Sample_RawFormat));
return;
}
}

frame_length_ = config.frame_length;

if (frame_length_ == 0) {
roc_log(LogError, "sox source: frame length is zero");
return;
}

memset(&in_signal_, 0, sizeof(in_signal_));
in_signal_.rate = (sox_rate_t)config.sample_spec.sample_rate();
in_signal_.rate = (sox_rate_t)sample_spec_.sample_rate();
in_signal_.channels = (unsigned)sample_spec_.num_channels();
in_signal_.precision = SOX_SAMPLE_PRECISION;

valid_ = true;
Expand Down Expand Up @@ -152,7 +170,6 @@ bool SoxSource::restart() {

if (is_file_ && !eof_) {
if (!seek_(0)) {
roc_panic("Reached");
roc_log(LogError,
"sox source: seek failed when restarting: driver=%s input=%s",
driver_name_.c_str(), input_name_.c_str());
Expand Down Expand Up @@ -188,19 +205,7 @@ audio::SampleSpec SoxSource::sample_spec() const {
roc_panic("sox source: sample_rate(): non-open output file or device");
}

if (input_->signal.channels == 1) {
return audio::SampleSpec(size_t(input_->signal.rate), audio::Sample_RawFormat,
audio::ChanLayout_Surround, audio::ChanOrder_Smpte,
audio::ChanMask_Surround_Mono);
}

if (input_->signal.channels == 2) {
return audio::SampleSpec(size_t(input_->signal.rate), audio::Sample_RawFormat,
audio::ChanLayout_Surround, audio::ChanOrder_Smpte,
audio::ChanMask_Surround_Stereo);
}

roc_panic("sox source: unsupported channel count");
return sample_spec_;
}

core::nanoseconds_t SoxSource::latency() const {
Expand Down Expand Up @@ -361,33 +366,42 @@ bool SoxSource::open_() {

is_file_ = !(input_->handler.flags & SOX_FILE_DEVICE);

if (is_file_) {
if (!sample_spec_.is_empty()) {
roc_log(LogError, "sox source: setting io encoding for files not supported");
return false;
}
sample_spec_ = sample_spec();
} else {
if (input_->signal.channels != sample_spec_.num_channels()) {
roc_log(LogError,
"sox source: can't open: unsupported # of channels: "
"expected=%lu actual=%lu",
(unsigned long)sample_spec_.num_channels(),
(unsigned long)input_->signal.channels);
return false;
}
const unsigned long requested_rate = (unsigned long)in_signal_.rate;
const unsigned long actual_rate = (unsigned long)input_->signal.rate;

if (requested_rate != 0 && requested_rate != actual_rate) {
roc_log(LogError,
"sox source:"
" can't open input file or device with the requested sample rate:"
" required_by_input=%lu requested_by_user=%lu",
actual_rate, requested_rate);
return false;
}

const unsigned long requested_chans = (unsigned long)in_signal_.channels;
const unsigned long actual_chans = (unsigned long)input_->signal.channels;

if (requested_chans != 0 && requested_chans != actual_chans) {
roc_log(LogError,
"sox source:"
" can't open input file or device with the requested channel count:"
" required_by_input=%lu requested_by_user=%lu",
actual_chans, requested_chans);
return false;
}

sample_spec_.set_sample_rate((unsigned long)input_->signal.rate);
sample_spec_.set_sample_format(audio::SampleFormat_Pcm);
sample_spec_.set_pcm_format(audio::Sample_RawFormat);
sample_spec_.set_sample_rate(actual_rate);
sample_spec_.channel_set().set_layout(audio::ChanLayout_Surround);
sample_spec_.channel_set().set_order(audio::ChanOrder_Smpte);
sample_spec_.channel_set().set_range(0, actual_chans - 1);

roc_log(LogInfo,
"sox source:"
" in_bits=%lu out_bits=%lu in_rate=%lu out_rate=%lu"
" in_ch=%lu out_ch=%lu is_file=%d",
(unsigned long)input_->encoding.bits_per_sample,
(unsigned long)in_signal_.precision, (unsigned long)input_->signal.rate,
(unsigned long)in_signal_.rate, (unsigned long)input_->signal.channels,
(unsigned long)in_signal_.channels, (int)is_file_);
" opened: bits=%lu rate=%lu req_rate=%lu chans=%lu req_chans=%lu is_file=%d",
(unsigned long)input_->encoding.bits_per_sample, actual_rate, requested_rate,
actual_chans, requested_chans, (int)is_file_);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "roc_core/string_buffer.h"
#include "roc_packet/units.h"
#include "roc_sndio/config.h"
#include "roc_sndio/driver.h"
#include "roc_sndio/isource.h"

namespace roc {
Expand All @@ -34,7 +35,7 @@ namespace sndio {
class SoxSource : public ISource, private core::NonCopyable<> {
public:
//! Initialize.
SoxSource(core::IArena& arena, const Config& config);
SoxSource(core::IArena& arena, const Config& config, DriverType type);

virtual ~SoxSource();

Expand Down

0 comments on commit d207243

Please sign in to comment.