Skip to content

Commit

Permalink
backend beginning to be implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
Hrick87 committed Nov 27, 2023
1 parent 2cf71a2 commit 2436690
Show file tree
Hide file tree
Showing 6 changed files with 503 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <stdio.h>

#include "roc_core/log.h"
#include "roc_core/macro_helpers.h"
#include "roc_core/scoped_lock.h"
#include "roc_core/scoped_ptr.h"
#include "roc_sndio/sndfile_backend.h"
#include "roc_sndio/sndfile_sink.h"
#include "roc_sndio/sndfile_source.h"

namespace roc {
namespace sndio {

namespace {



}

SndfileBackend::SndfileBackend() : first_created_(false) {
roc_log(LogDebug, "sndfile backend: initializing");
}

void SndfileBackend::set_frame_size(core::nanoseconds_t frame_length, const audio::SampleSpec& sample_spec){
size_t size = sample_spec.ns_2_samples_overall(frame_length);

if (first_created_) {
roc_panic(
"sox backend:"
" set_frame_size() can be called only before creating first source or sink");
}
}

void SndfileBackend::discover_drivers(core::Array<DriverInfo, MaxDrivers>& driver_list){

}


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 Roc Streaming 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/target_sndfile/roc_sndio/sndfile_backend.h
//! @brief SndFile backend.

#ifndef ROC_SNDIO_SNDFILE_BACKEND_H_
#define ROC_SNDIO_SNDFILE_BACKEND_H_

#include <sndfile.h>

#include "roc_audio/sample_spec.h"
#include "roc_core/noncopyable.h"
#include "roc_sndio/ibackend.h"

namespace roc {
namespace sndio {

//! SoX backend.
class SndfileBackend : public IBackend, core::NonCopyable<> {
public:
SndfileBackend();

//! Set internal SndFile frame size.
//! @remarks
//! Number of samples for all channels.
void set_frame_size(core::nanoseconds_t frame_length,
const audio::SampleSpec& sample_spec);

//! Append supported drivers to the list.
virtual void discover_drivers(core::Array<DriverInfo, MaxDrivers>& driver_list);

//! Create and open a sink or source.
virtual IDevice* open_device(DeviceType device_type,
DriverType driver_type,
const char* driver,
const char* path,
const Config& config,
core::IArena& arena);

private:
bool first_created_;
};

} // namespace sndio
} // namespace roc

#endif // ROC_SNDIO_SNDFILE_BACKEND_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
/*
* Copyright (c) 2023 Roc Streaming 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/.
*/


#include "roc_core/log.h"
#include "roc_core/panic.h"
#include "roc_sndio/backend_map.h"
#include "roc_sndio/sndfile_sink.h"

namespace roc {
namespace sndio {

SndfileSink::SndfileSink(core::IArena& arena, const Config& config)
: sndfile_output_(NULL)
, buffer_(arena)
, buffer_size_(0)
, is_file_(false)
, valid_(false) {
BackendMap::instance();

if (config.sample_spec.num_channels() == 0) {
roc_log(LogError, "sndfile sink: # of channels is zero");
return;
}

if (config.latency != 0) {
roc_log(LogError, "sndfile sink: setting io latency not supported by sndfile backend");
return;
}

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

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

memset(&sf_info_out_, 0, sizeof(sf_info_out_));
sf_info_out_->samplerate = (int)config.sample_spec.sample_rate();
sf_info_out_->channels = (int)config.sample_spec.num_channels();
sf_info_out_->format = SF_FORMAT_PCM_32;

valid_ = true;
}

SndfileSink::~SndfileSink() {
close_();
}

bool SndfileSink::is_valid() const {
return valid_;
}

bool SndfileSink::open(const char* driver, const char* path) {
roc_panic_if(!valid_);

roc_log(LogDebug, "sndfile sink: opening: driver=%s path=%s", driver, path);

if (buffer_.size() != 0 || sndfile_output_) {
roc_panic("sndfile sink: can't call open() more than once");
}

if (!open_(driver, path)) {
return false;
}

if (!setup_buffer_()) {
return false;
}

return true;
}

DeviceType SndfileSink::type() const {
return DeviceType_Sink;
}

DeviceState SndfileSink::state() const {
return DeviceState_Active;
}

void SndfileSink::pause() {
// no-op
}

bool SndfileSink::resume() {
return true;
}

bool SndfileSink::restart() {
return true;
}

audio::SampleSpec SndfileSink::sample_spec() const {
roc_panic_if(!valid_);

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

if (sf_info_out_->channels == 1) {
return audio::SampleSpec(size_t(sf_info_out_->samplerate), audio::ChanLayout_Surround,
audio::ChanOrder_Smpte, audio::ChanMask_Surround_Mono);
}

if (sf_info_out_->channels == 2) {
return audio::SampleSpec(size_t(sf_info_out_->samplerate), audio::ChanLayout_Surround,
audio::ChanOrder_Smpte, audio::ChanMask_Surround_Stereo);
}

roc_panic("sndfile sink: unsupported channel count");
}

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

if (!sndfile_output_) {
roc_panic("sndfile sink: latency(): non-open output file or device");
}

return 0;
}

bool SndfileSink::has_latency() const {
roc_panic_if(!valid_);

if (!sndfile_output_) {
roc_panic("sndfile sink: has_latency(): non-open output file or device");
}

return false;
}

bool SndfileSink::has_clock() const {
roc_panic_if(!valid_);

if (!sndfile_output_) {
roc_panic("sndfile sink: has_clock(): non-open output file or device");
}

return !is_file_;
}

void SndfileSink::write(audio::Frame& frame) {
roc_panic_if(!valid_);

const audio::sample_t* frame_data = frame.samples();
size_t frame_size = frame.num_samples();

int32_t* buffer_data = buffer_.data();
size_t buffer_pos = 0;



while (frame_size > 0) {
for (; buffer_pos < buffer_size_ && frame_size > 0; buffer_pos++) {
buffer_data[buffer_pos] = (int32_t)frame_data[buffer_pos]; //??
frame_data++;
frame_size--;
}

if (buffer_pos == buffer_size_) {
write_(buffer_data, buffer_pos);
buffer_pos = 0;
}
}

write_(buffer_data, buffer_pos);
}

bool SndfileSink::setup_buffer_() {
buffer_size_ = sample_spec_.ns_2_samples_overall(frame_length_);
if (buffer_size_ == 0) {
roc_log(LogError, "sndfile sink: buffer size is zero");
return false;
}
if (!buffer_.resize(buffer_size_)) {
roc_log(LogError, "sndfile sink: can't allocate sample buffer");
return false;
}

return true;
}

bool SndfileSink::open_(const char* driver, const char* path) {
sndfile_output_ = sf_open(path, SFM_WRITE, sf_info_out_);
if (!sndfile_output_) {
roc_log(LogDebug, "sndfile sink: can't open: driver=%s path=%s", driver, path);
return false;
}

is_file_ = true;

unsigned long in_rate = (unsigned long)sf_info_out_->samplerate;
unsigned long out_rate = (unsigned long)sf_info_out_->samplerate;

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

sample_spec_.set_sample_rate((unsigned long)sf_info_out_->samplerate);

/*
roc_log(LogInfo,
"sndfile sink:"
" opened: bits=%lu out_rate=%lu in_rate=%lu ch=%lu is_file=%d",
(unsigned long)sndfile_output_->encoding.bits_per_sample, out_rate, in_rate,
(unsigned long)sndfile_output_->signal.channels, (int)is_file_);
*/

roc_log(LogInfo,
"sndfile sink:"
" out_rate=%lu in_rate=%lu ch=%lu is_file=%d",
out_rate, in_rate,
(unsigned long)sf_info_out_->channels, (int)is_file_);

return true;
}

void SndfileSink::write_(const int32_t * samples, size_t n_samples) {
if (n_samples > 0) {
if (sf_writef_int(sndfile_output_, samples, (sf_count_t)n_samples) != (sf_count_t)n_samples) {
roc_log(LogError, "sndfile sink: failed to write output buffer");
}
}
}

void SndfileSink::close_() {
if (!sndfile_output_) {
return;
}

roc_log(LogDebug, "sndfile sink: closing output");

int err = sf_close(sndfile_output_);
if (err != 0) {
roc_panic("sndfile sink: can't close output: %s", sf_error_number(err));
}

sndfile_output_ = NULL;
}

} // namespace sndio
} // namespace roc
Loading

0 comments on commit 2436690

Please sign in to comment.