From 8d2c1a57e9c4be334b56a7f29921981f64eb6fe2 Mon Sep 17 00:00:00 2001 From: Thomas Dwyer Date: Wed, 18 Sep 2019 19:59:35 -0700 Subject: [PATCH] Add --list-drivers -L support References: #251, #257 --- .../target_openfec/roc_fec/of_decoder.cpp | 10 ++-- src/modules/roc_sndio/backend_dispatcher.cpp | 16 +++++-- src/modules/roc_sndio/backend_dispatcher.h | 4 ++ src/modules/roc_sndio/driver_info.cpp | 48 +++++++++++++++++++ src/modules/roc_sndio/driver_info.h | 42 ++++++++++++++++ src/modules/roc_sndio/ibackend.h | 15 ++++-- .../roc_sndio/pulseaudio_backend.cpp | 13 ++++- .../roc_sndio/pulseaudio_backend.h | 4 ++ .../target_sox/roc_sndio/sox_backend.cpp | 26 +++++++++- .../target_sox/roc_sndio/sox_backend.h | 4 ++ src/tools/roc_recv/cmdline.ggo | 2 + src/tools/roc_recv/main.cpp | 23 ++++++++- src/tools/roc_send/cmdline.ggo | 2 + src/tools/roc_send/main.cpp | 23 ++++++++- 14 files changed, 212 insertions(+), 20 deletions(-) create mode 100644 src/modules/roc_sndio/driver_info.cpp create mode 100644 src/modules/roc_sndio/driver_info.h diff --git a/src/modules/roc_fec/target_openfec/roc_fec/of_decoder.cpp b/src/modules/roc_fec/target_openfec/roc_fec/of_decoder.cpp index 69d6fec2b3..2660c302f0 100644 --- a/src/modules/roc_fec/target_openfec/roc_fec/of_decoder.cpp +++ b/src/modules/roc_fec/target_openfec/roc_fec/of_decoder.cpp @@ -294,11 +294,11 @@ void OFDecoder::reset_session_() { if (OF_STATUS_OK != of_set_callback_functions( - of_sess_, source_cb_, - // OpenFEC doesn't repair fec-packets in case of Reed-Solomon FEC - // and prints curses to the console if we give it the callback for that - codec_id_ == OF_CODEC_REED_SOLOMON_GF_2_M_STABLE ? NULL : repair_cb_, - (void*)this)) { + of_sess_, source_cb_, + // OpenFEC doesn't repair fec-packets in case of Reed-Solomon FEC + // and prints curses to the console if we give it the callback for that + codec_id_ == OF_CODEC_REED_SOLOMON_GF_2_M_STABLE ? NULL : repair_cb_, + (void*)this)) { roc_panic("of decoder: of_set_callback_functions() failed"); } } diff --git a/src/modules/roc_sndio/backend_dispatcher.cpp b/src/modules/roc_sndio/backend_dispatcher.cpp index 99baadbcc9..cabf490795 100644 --- a/src/modules/roc_sndio/backend_dispatcher.cpp +++ b/src/modules/roc_sndio/backend_dispatcher.cpp @@ -42,7 +42,7 @@ ISink* BackendDispatcher::open_sink(core::IAllocator& allocator, const char* driver, const char* output, const Config& config) { - IBackend* backend = select_backend_(driver, output, IBackend::ProbeSink); + IBackend* backend = select_backend_(driver, output, IBackend::FilterSink); if (!backend) { return NULL; } @@ -53,7 +53,7 @@ ISource* BackendDispatcher::open_source(core::IAllocator& allocator, const char* driver, const char* input, const Config& config) { - IBackend* backend = select_backend_(driver, input, IBackend::ProbeSource); + IBackend* backend = select_backend_(driver, input, IBackend::FilterSource); if (!backend) { return NULL; } @@ -62,12 +62,13 @@ ISource* BackendDispatcher::open_source(core::IAllocator& allocator, IBackend* BackendDispatcher::select_backend_(const char* driver, const char* inout, int flags) { - if (IBackend* backend = probe_backends_(driver, inout, flags | IBackend::ProbeFile)) { + if (IBackend* backend = + probe_backends_(driver, inout, flags | IBackend::FilterFile)) { return backend; } if (IBackend* backend = probe_backends_( - driver, inout, flags | IBackend::ProbeFile | IBackend::ProbeDevice)) { + driver, inout, flags | IBackend::FilterFile | IBackend::FilterDevice)) { return backend; } @@ -90,5 +91,12 @@ void BackendDispatcher::add_backend_(IBackend& backend) { backends_[n_backends_++] = &backend; } +void BackendDispatcher::get_drivers(core::Array& arr, + IBackend::FilterFlags driver_type) { + for (size_t n = 0; n < n_backends_; n++) { + backends_[n]->get_drivers(arr, driver_type); + } +} + } // namespace sndio } // namespace roc diff --git a/src/modules/roc_sndio/backend_dispatcher.h b/src/modules/roc_sndio/backend_dispatcher.h index bb506fa9a3..9d58ff399f 100644 --- a/src/modules/roc_sndio/backend_dispatcher.h +++ b/src/modules/roc_sndio/backend_dispatcher.h @@ -12,6 +12,7 @@ #ifndef ROC_SNDIO_BACKEND_DISPATCHER_H_ #define ROC_SNDIO_BACKEND_DISPATCHER_H_ +#include "roc_core/array.h" #include "roc_core/iallocator.h" #include "roc_core/noncopyable.h" #include "roc_core/shared_ptr.h" @@ -46,6 +47,9 @@ class BackendDispatcher : public core::NonCopyable<> { const char* input, const Config& config); + //! Append supported drivers from all registered backends to Array + void get_drivers(core::Array& arr, IBackend::FilterFlags driver_type); + private: friend class core::Singleton; diff --git a/src/modules/roc_sndio/driver_info.cpp b/src/modules/roc_sndio/driver_info.cpp new file mode 100644 index 0000000000..104aaa8e2e --- /dev/null +++ b/src/modules/roc_sndio/driver_info.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Roc authors + * + * This Sink Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include "roc_sndio/driver_info.h" + +namespace roc { +namespace sndio { + +DriverInfo::DriverInfo() { + for (size_t x = 0; x < MaxSize; x++) { + name[x] = '\0'; + } +} + +DriverInfo::DriverInfo(const char* driver_name) { + size_t length = strlen(driver_name); + if (length > MaxSize - 1) { + length = MaxSize - 1; + } + strncpy(name, driver_name, MaxSize); + name[length] = '\0'; +} + +bool add_driver_uniq(core::Array& arr, const char* driver_name) { + roc_panic_if(driver_name == NULL); + for (size_t n = 0; n < arr.size(); n++) { + if (strcmp(driver_name, arr[n].name) == 0) { + return false; + } + } + if (arr.grow(arr.size() + 1)) { + DriverInfo new_driver(driver_name); + arr.push_back(new_driver); + return true; + } else { + return false; + } +} + +} // namespace sndio +} // namespace roc diff --git a/src/modules/roc_sndio/driver_info.h b/src/modules/roc_sndio/driver_info.h new file mode 100644 index 0000000000..4b746f31c6 --- /dev/null +++ b/src/modules/roc_sndio/driver_info.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Roc authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +//! @file roc_sndio/driver_info.h +//! @brief Driver info interface. + +#ifndef ROC_SNDIO_DRIVER_INFO_H_ +#define ROC_SNDIO_DRIVER_INFO_H_ + +#include "roc_core/array.h" + +namespace roc { +namespace sndio { + +//! Driver info interface. +struct DriverInfo { + DriverInfo(); + + //! Max size of string + enum { MaxSize = 20 }; + + //! Parameterized Constructor initializes name, assumes driver_name is terminated with + //! null char + explicit DriverInfo(const char* driver_name); + + //! Placeholder for the driver name + char name[MaxSize]; +}; + +//! Append driver to array and ensure uniqueness, returns false if unable to add item, +//! or if unable to allocate space for item +bool add_driver_uniq(core::Array& arr, const char* driver_name); + +} // namespace sndio +} // namespace roc + +#endif // ROC_SNDIO_DRIVER_INFO_H_ diff --git a/src/modules/roc_sndio/ibackend.h b/src/modules/roc_sndio/ibackend.h index 4b405a51d9..8dd006445b 100644 --- a/src/modules/roc_sndio/ibackend.h +++ b/src/modules/roc_sndio/ibackend.h @@ -12,9 +12,11 @@ #ifndef ROC_SNDIO_IBACKEND_H_ #define ROC_SNDIO_IBACKEND_H_ +#include "roc_core/array.h" #include "roc_core/iallocator.h" #include "roc_core/shared_ptr.h" #include "roc_sndio/config.h" +#include "roc_sndio/driver_info.h" #include "roc_sndio/isink.h" #include "roc_sndio/isource.h" @@ -27,18 +29,18 @@ class IBackend { virtual ~IBackend(); //! Probing flags. - enum ProbeFlags { + enum FilterFlags { //! Input or output may be a sink. - ProbeSink = (1 << 0), + FilterSink = (1 << 0), //! Input or output may be a source. - ProbeSource = (1 << 1), + FilterSource = (1 << 1), //! Input or output may be a file. - ProbeFile = (1 << 2), + FilterFile = (1 << 2), //! Input or output may be a device. - ProbeDevice = (1 << 3) + FilterDevice = (1 << 3) }; //! Check whether the backend can handle given input or output. @@ -55,6 +57,9 @@ class IBackend { const char* driver, const char* input, const Config& config) = 0; + + //! Append supported dirvers to Array + virtual void get_drivers(core::Array& arr, FilterFlags driver_type) = 0; }; } // namespace sndio diff --git a/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.cpp b/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.cpp index 82a1ee7b0d..64142399fd 100644 --- a/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.cpp +++ b/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.cpp @@ -11,6 +11,7 @@ #include "roc_core/log.h" #include "roc_core/stddefs.h" #include "roc_core/unique_ptr.h" +#include "roc_sndio/driver_info.h" #include "roc_sndio/pulseaudio_backend.h" #include "roc_sndio/pulseaudio_sink.h" @@ -22,11 +23,11 @@ PulseaudioBackend::PulseaudioBackend() { } bool PulseaudioBackend::probe(const char* driver, const char*, int flags) { - if ((flags & ProbeDevice) == 0) { + if ((flags & FilterDevice) == 0) { return false; } - if ((flags & ProbeSink) == 0) { + if ((flags & FilterSink) == 0) { return false; } @@ -57,5 +58,13 @@ ISource* PulseaudioBackend::open_source(core::IAllocator&, return NULL; } +void PulseaudioBackend::get_drivers(core::Array& arr, + FilterFlags driver_type) { + const char* format_name = "pulseaudio"; + if (driver_type & FilterDevice) { + add_driver_uniq(arr, format_name); + } +} + } // namespace sndio } // namespace roc diff --git a/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.h b/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.h index a7af119216..dad49481f8 100644 --- a/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.h +++ b/src/modules/roc_sndio/target_pulseaudio/roc_sndio/pulseaudio_backend.h @@ -12,6 +12,7 @@ #ifndef ROC_SNDIO_PULSEAUDIO_BACKEND_H_ #define ROC_SNDIO_PULSEAUDIO_BACKEND_H_ +#include "roc_core/array.h" #include "roc_core/noncopyable.h" #include "roc_core/singleton.h" #include "roc_sndio/ibackend.h" @@ -42,6 +43,9 @@ class PulseaudioBackend : public IBackend, core::NonCopyable<> { const char* input, const Config& config); + //! Append supported drivers to Array + virtual void get_drivers(core::Array& arr, FilterFlags driver_type); + private: friend class core::Singleton; diff --git a/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp b/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp index 99f4a279e3..2175ba7e4e 100644 --- a/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp +++ b/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.cpp @@ -135,11 +135,11 @@ bool SoxBackend::probe(const char* driver, const char* inout, int flags) { } if (handler->flags & SOX_FILE_DEVICE) { - if ((flags & ProbeDevice) == 0) { + if ((flags & FilterDevice) == 0) { return false; } } else { - if ((flags & ProbeFile) == 0) { + if ((flags & FilterFile) == 0) { return false; } } @@ -196,5 +196,27 @@ ISource* SoxBackend::open_source(core::IAllocator& allocator, return source.release(); } +void SoxBackend::get_drivers(core::Array& arr, FilterFlags driver_type) { + const sox_format_tab_t* formats = sox_get_format_fns(); + char const* const* format_names; + for (size_t n = 0; formats[n].fn; n++) { + sox_format_handler_t const* handler = formats[n].fn(); + bool match = false; + if (driver_type & FilterFile) { + match = !(handler->flags & SOX_FILE_DEVICE); + } else if (driver_type & FilterDevice) { + match = ((handler->flags & SOX_FILE_DEVICE) + && !(handler->flags & SOX_FILE_PHONY)); + } + if (match) { + for (format_names = handler->names; *format_names; ++format_names) { + if (!strchr(*format_names, '/')) { + add_driver_uniq(arr, *format_names); + } + } + } + } +} + } // namespace sndio } // namespace roc diff --git a/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.h b/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.h index 099248c877..c10c866b0b 100644 --- a/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.h +++ b/src/modules/roc_sndio/target_sox/roc_sndio/sox_backend.h @@ -50,6 +50,10 @@ class SoxBackend : public IBackend, core::NonCopyable<> { const char* input, const Config& config); + //! Append supported dirvers to Array, replicates the behavior of + //! display_supported_formats() from sox.c + virtual void get_drivers(core::Array& arr, FilterFlags driver_type); + private: friend class core::Singleton; diff --git a/src/tools/roc_recv/cmdline.ggo b/src/tools/roc_recv/cmdline.ggo index 1125d64579..76f67de140 100644 --- a/src/tools/roc_recv/cmdline.ggo +++ b/src/tools/roc_recv/cmdline.ggo @@ -3,6 +3,8 @@ usage "roc-recv OPTIONS" section "Options" + option "list-drivers" L "list all supported audio drivers" optional + option "verbose" v "Increase verbosity level (may be used multiple times)" multiple optional diff --git a/src/tools/roc_recv/main.cpp b/src/tools/roc_recv/main.cpp index 5f0183fc1d..d2dbd39b26 100644 --- a/src/tools/roc_recv/main.cpp +++ b/src/tools/roc_recv/main.cpp @@ -7,6 +7,7 @@ */ #include "roc_audio/resampler_profile.h" +#include "roc_core/array.h" #include "roc_core/crash.h" #include "roc_core/heap_allocator.h" #include "roc_core/log.h" @@ -17,6 +18,7 @@ #include "roc_pipeline/parse_port.h" #include "roc_pipeline/receiver.h" #include "roc_sndio/backend_dispatcher.h" +#include "roc_sndio/driver_info.h" #include "roc_sndio/pump.h" #include "roc_recv/cmdline.h" @@ -39,6 +41,26 @@ int main(int argc, char** argv) { core::Logger::instance().set_level( LogLevel(core::DefaultLogLevel + args.verbose_given)); + core::HeapAllocator allocator; + + if (args.list_drivers_given) { + core::Array device_driver_list(allocator); + core::Array file_driver_list(allocator); + sndio::BackendDispatcher::instance().get_drivers(device_driver_list, + sndio::IBackend::FilterDevice); + sndio::BackendDispatcher::instance().get_drivers(file_driver_list, + sndio::IBackend::FilterFile); + printf("%s\n", "device drivers:"); + for (size_t n = 0; n < device_driver_list.size(); n++) { + printf(" %s\n", device_driver_list[n].name); + } + printf("\n%s\n", "file drivers:"); + for (size_t m = 0; m < file_driver_list.size(); m++) { + printf(" %s\n", file_driver_list[m].name); + } + return 0; + } + pipeline::ReceiverConfig config; size_t max_packet_size = 2048; @@ -183,7 +205,6 @@ int main(int argc, char** argv) { config.common.poisoning = args.poisoning_flag; config.common.beeping = args.beeping_flag; - core::HeapAllocator allocator; core::BufferPool byte_buffer_pool(allocator, max_packet_size, args.poisoning_flag); core::BufferPool sample_buffer_pool( diff --git a/src/tools/roc_send/cmdline.ggo b/src/tools/roc_send/cmdline.ggo index 05a7edae27..6585e3da7f 100644 --- a/src/tools/roc_send/cmdline.ggo +++ b/src/tools/roc_send/cmdline.ggo @@ -3,6 +3,8 @@ usage "roc-send OPTIONS" section "Options" + option "list-drivers" L "List all supported audio drivers" optional + option "verbose" v "Increase verbosity level (may be used multiple times)" multiple optional diff --git a/src/tools/roc_send/main.cpp b/src/tools/roc_send/main.cpp index 0493912975..50d595b10c 100644 --- a/src/tools/roc_send/main.cpp +++ b/src/tools/roc_send/main.cpp @@ -7,6 +7,7 @@ */ #include "roc_audio/resampler_profile.h" +#include "roc_core/array.h" #include "roc_core/crash.h" #include "roc_core/heap_allocator.h" #include "roc_core/log.h" @@ -18,6 +19,7 @@ #include "roc_pipeline/port_utils.h" #include "roc_pipeline/sender.h" #include "roc_sndio/backend_dispatcher.h" +#include "roc_sndio/driver_info.h" #include "roc_sndio/pump.h" #include "roc_send/cmdline.h" @@ -40,6 +42,26 @@ int main(int argc, char** argv) { core::Logger::instance().set_level( LogLevel(core::DefaultLogLevel + args.verbose_given)); + core::HeapAllocator allocator; + + if (args.list_drivers_given) { + core::Array device_driver_list(allocator); + core::Array file_driver_list(allocator); + sndio::BackendDispatcher::instance().get_drivers(device_driver_list, + sndio::IBackend::FilterDevice); + sndio::BackendDispatcher::instance().get_drivers(file_driver_list, + sndio::IBackend::FilterFile); + printf("%s\n", "device drivers:"); + for (size_t n = 0; n < device_driver_list.size(); n++) { + printf(" %s\n", device_driver_list[n].name); + } + printf("\n%s\n", "file drivers:"); + for (size_t m = 0; m < file_driver_list.size(); m++) { + printf(" %s\n", file_driver_list[m].name); + } + return 0; + } + pipeline::SenderConfig config; if (args.packet_length_given) { @@ -166,7 +188,6 @@ int main(int argc, char** argv) { config.interleaving = args.interleaving_flag; config.poisoning = args.poisoning_flag; - core::HeapAllocator allocator; core::BufferPool byte_buffer_pool(allocator, max_packet_size, args.poisoning_flag); core::BufferPool sample_buffer_pool(