diff --git a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp index 5e5cca1df..73a7cd56f 100644 --- a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp +++ b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp @@ -254,7 +254,8 @@ IDevice* SoxBackend::open_device(DeviceType device_type, switch (device_type) { case DeviceType_Sink: { - core::ScopedPtr sink(new (arena) SoxSink(arena, config), arena); + core::ScopedPtr 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); @@ -271,7 +272,8 @@ IDevice* SoxBackend::open_device(DeviceType device_type, } break; case DeviceType_Source: { - core::ScopedPtr source(new (arena) SoxSource(arena, config), arena); + core::ScopedPtr 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); diff --git a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.cpp b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.cpp index f28511e36..f8e3fc445 100644 --- a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.cpp +++ b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.cpp @@ -14,7 +14,7 @@ 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) @@ -22,18 +22,30 @@ SoxSink::SoxSink(core::IArena& arena, const Config& config) , 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"); @@ -41,8 +53,8 @@ SoxSink::SoxSink(core::IArena& arena, const Config& config) } 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; @@ -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; @@ -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; @@ -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_; @@ -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; } diff --git a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.h b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.h index 7bf68265a..53ca692fd 100644 --- a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.h +++ b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_sink.h @@ -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 { @@ -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(); diff --git a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.cpp b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.cpp index 3b5a3743e..2f2dd9052 100644 --- a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.cpp +++ b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.cpp @@ -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) @@ -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; @@ -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()); @@ -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 { @@ -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; } diff --git a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.h b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.h index 215e72996..a943822e2 100644 --- a/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.h +++ b/src/internal_modules/roc_sndio/target_sox/roc_sndio/sox_source.h @@ -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 { @@ -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();