Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

roc_audio: adjust resampler coef #113

Merged
merged 1 commit into from
Oct 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/lib/roc/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ typedef struct roc_receiver_config {

//! A bitmask of ROC_FLAG_* constants.
unsigned int flags;

//! Number of samples per second per channel.
unsigned int sample_rate;
} roc_receiver_config;

#ifdef __cplusplus
Expand Down
4 changes: 4 additions & 0 deletions src/lib/roc/receiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ bool make_receiver_config(pipeline::ReceiverConfig& out, const roc_receiver_conf
out.default_session.timeout = in->timeout;
out.default_session.samples_per_packet = in->samples_per_packet;

if (in->sample_rate) {
out.sample_rate = in->sample_rate;
}

switch ((unsigned)in->fec_scheme) {
case ROC_FEC_RS8M:
out.default_session.fec.codec = fec::ReedSolomon8m;
Expand Down
15 changes: 10 additions & 5 deletions src/modules/roc_audio/resampler_updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const core::nanoseconds_t LogRate = 5000000000;
} // namespace

ResamplerUpdater::ResamplerUpdater(packet::timestamp_t update_interval,
packet::timestamp_t aim_queue_size)
packet::timestamp_t aim_queue_size,
const float sample_rate_coef)
: writer_(NULL)
, reader_(NULL)
, resampler_(NULL)
Expand All @@ -34,7 +35,8 @@ ResamplerUpdater::ResamplerUpdater(packet::timestamp_t update_interval,
, head_(0)
, has_tail_(false)
, tail_(0)
, started_(false) {
, started_(false)
, sample_rate_coef_(sample_rate_coef) {
}

void ResamplerUpdater::set_writer(packet::IWriter& writer) {
Expand Down Expand Up @@ -96,13 +98,16 @@ bool ResamplerUpdater::update(packet::timestamp_t time) {
update_time_ += update_interval_;
}

const float adjusted_coef = sample_rate_coef_ * fe_.freq_coeff();

if (rate_limiter_.allow()) {
roc_log(LogDebug, "resampler updater: queue_size=%lu fe=%.5f",
(unsigned long)queue_size, (double)fe_.freq_coeff());
roc_log(LogDebug, "resampler updater: queue_size=%lu fe=%.5f, adjust_fe=%.5f",
(unsigned long)queue_size, (double)fe_.freq_coeff(),
(double)adjusted_coef);
}

roc_panic_if(!resampler_);
return resampler_->set_scaling(fe_.freq_coeff());
return resampler_->set_scaling(adjusted_coef);
}

} // namespace audio
Expand Down
7 changes: 6 additions & 1 deletion src/modules/roc_audio/resampler_updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ class ResamplerUpdater : public packet::IWriter,
//! @b Parameters
//! - @p update_interval defines how often to call FreqEstimator, in samples
//! - @p aim_queue_size defines FreqEstimator target queue size, in samples
//! - @p sample_rate_coef represents a factor for converting session sample rate to
//! output sample rate of a receiver.
ResamplerUpdater(packet::timestamp_t update_interval,
packet::timestamp_t aim_queue_size);
packet::timestamp_t aim_queue_size,
const float sample_rate_coef);

//! Set output writer.
void set_writer(packet::IWriter&);
Expand Down Expand Up @@ -76,6 +79,8 @@ class ResamplerUpdater : public packet::IWriter,
packet::timestamp_t tail_;

bool started_;

const float sample_rate_coef_;
};

} // namespace audio
Expand Down
4 changes: 2 additions & 2 deletions src/modules/roc_pipeline/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ struct ReceiverConfig {
//! Default parameters for session.
SessionConfig default_session;

//! Sample rate, number of samples for all channels per second.
//! Number of samples per second per channel.
size_t sample_rate;

//! Channel mask.
Expand All @@ -149,7 +149,7 @@ struct SenderConfig {
//! Parameters for the port from which repair packets are sent.
PortConfig repair_port;

//! Sample rate, number of samples for all channels per second.
//! Number of samples per second per channel.
size_t sample_rate;

//! Channel mask.
Expand Down
6 changes: 3 additions & 3 deletions src/modules/roc_pipeline/receiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ bool Receiver::create_session_(const packet::PacketPtr& packet) {
}
const packet::Address src_address = packet->udp()->src_addr;

core::SharedPtr<ReceiverSession> sess = new (allocator_)
ReceiverSession(config_.default_session, src_address, format_map_, packet_pool_,
byte_buffer_pool_, sample_buffer_pool_, allocator_);
core::SharedPtr<ReceiverSession> sess = new (allocator_) ReceiverSession(
config_.default_session, config_.sample_rate, src_address, format_map_,
packet_pool_, byte_buffer_pool_, sample_buffer_pool_, allocator_);

if (!sess || !sess->valid()) {
roc_log(LogError, "receiver: can't create session, initialization failed");
Expand Down
6 changes: 5 additions & 1 deletion src/modules/roc_pipeline/receiver_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace roc {
namespace pipeline {

ReceiverSession::ReceiverSession(const SessionConfig& config,
const size_t out_sample_rate,
const packet::Address& src_address,
const rtp::FormatMap& format_map,
packet::PacketPool& packet_pool,
Expand All @@ -28,14 +29,17 @@ ReceiverSession::ReceiverSession(const SessionConfig& config,
: src_address_(src_address)
, allocator_(allocator)
, audio_reader_(NULL) {
roc_panic_if(out_sample_rate == 0);

const rtp::Format* format = format_map.format(config.payload_type);
if (!format) {
return;
}

if (config.resampling) {
resampler_updater_.reset(new (allocator_) audio::ResamplerUpdater(
config.fe_update_interval, config.latency),
config.fe_update_interval, config.latency,
(float)format->sample_rate / out_sample_rate),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should panic if out_sample_rate is zero. A panic is better than a segfault.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

allocator_);
if (!resampler_updater_) {
return;
Expand Down
1 change: 1 addition & 0 deletions src/modules/roc_pipeline/receiver_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class ReceiverSession : public core::RefCnt<ReceiverSession>, public core::ListN
public:
//! Initialize.
ReceiverSession(const SessionConfig& config,
const size_t out_sample_rate,
const packet::Address& src_address,
const rtp::FormatMap& format_map,
packet::PacketPool& packet_pool,
Expand Down
45 changes: 36 additions & 9 deletions src/modules/roc_sndio/target_sox/roc_sndio/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
namespace roc {
namespace sndio {

Player::Player(pipeline::IReceiver& input,
core::BufferPool<audio::sample_t>& buffer_pool,
Player::Player(core::BufferPool<audio::sample_t>& buffer_pool,
core::IAllocator& allocator,
bool oneshot,
packet::channel_mask_t channels,
size_t sample_rate)
: output_(NULL)
, input_(input)
, buffer_pool_(buffer_pool)
, allocator_(allocator)
, clips_(0)
Expand All @@ -34,10 +32,6 @@ Player::Player(pipeline::IReceiver& input,
roc_panic("player: # of channels is zero");
}

if (sample_rate == 0) {
roc_panic("player: sample rate is zero");
}

memset(&out_signal_, 0, sizeof(out_signal_));
out_signal_.rate = sample_rate;
out_signal_.channels = (unsigned)n_channels;
Expand Down Expand Up @@ -71,18 +65,51 @@ bool Player::open(const char* name, const char* type) {
return false;
}

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

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

roc_log(LogInfo,
"player:"
" bits=%lu out_rate=%lu in_rate=%lu ch=%lu",
(unsigned long)output_->encoding.bits_per_sample, out_rate, in_rate,
(unsigned long)output_->signal.channels);

return true;
}

void Player::stop() {
stop_ = 1;
}

void Player::start(pipeline::IReceiver& input) {
input_ = &input;
core::Thread::start();
}

size_t Player::get_sample_rate() const {
if (!output_) {
roc_panic("player: can't get sample rate for non-open output file or device");
}
return size_t(output_->signal.rate);
}

void Player::run() {
roc_log(LogDebug, "player: starting thread");

if (!input_) {
roc_panic("player: thread is started not from the start() call");
}

if (!output_) {
roc_panic("player: thread is started before open() returnes success");
roc_panic("player: thread is started before open() returned success");
}

loop_();
Expand Down Expand Up @@ -115,7 +142,7 @@ void Player::loop_() {
SOX_SAMPLE_LOCALS;

while (!stop_) {
pipeline::IReceiver::Status status = input_.read(frame);
pipeline::IReceiver::Status status = input_->read(frame);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should panic if run() was called and input_ is null. A panic is better than a segfault.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


if (status == pipeline::IReceiver::Inactive) {
if (oneshot_ && n_bufs_ != 0) {
Expand Down
18 changes: 14 additions & 4 deletions src/modules/roc_sndio/target_sox/roc_sndio/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ class Player : public core::Thread {
//! Initialize.
//!
//! @b Parameters
//! - @p input is used to read samples
//! - @p channels defines bitmask of enabled channels in input buffers
//! - @p sample_rate defines sample rate of input buffers
Player(pipeline::IReceiver& input,
core::BufferPool<audio::sample_t>& buffer_pool,
Player(core::BufferPool<audio::sample_t>& buffer_pool,
core::IAllocator& allocator,
bool oneshot,
packet::channel_mask_t channels,
Expand All @@ -60,11 +58,23 @@ class Player : public core::Thread {
//! Should be called once before calling start().
bool open(const char* name, const char* type = NULL);

//! Start reading samples in a separate thread.
//!
//! @b Parameters
//! - @p input is used to read samples.
void start(pipeline::IReceiver& input);

//! Stop thread.
//! @remarks
//! Can be called from any thread.
void stop();

//! Get sample rate of an output file or a device.
//!
//! @pre
//! Output file or device should be opened.
size_t get_sample_rate() const;

private:
virtual void run();

Expand All @@ -76,7 +86,7 @@ class Player : public core::Thread {
sox_format_t* output_;
sox_signalinfo_t out_signal_;

pipeline::IReceiver& input_;
pipeline::IReceiver* input_;

core::BufferPool<audio::sample_t>& buffer_pool_;
core::IAllocator& allocator_;
Expand Down
Loading