Change SampleFormat variables to getters

This commit is contained in:
badaix 2020-02-18 22:47:04 +01:00
parent 96856ae5a6
commit 1bc8f74c41
17 changed files with 164 additions and 140 deletions

View file

@ -62,7 +62,7 @@ void Controller::onMessageReceived(ClientConnection* /*connection*/, const msg::
{ {
auto pcmChunk = make_unique<msg::PcmChunk>(sampleFormat_, 0); auto pcmChunk = make_unique<msg::PcmChunk>(sampleFormat_, 0);
pcmChunk->deserialize(baseMessage, buffer); pcmChunk->deserialize(baseMessage, buffer);
// LOG(DEBUG) << "chunk: " << pcmChunk->payloadSize << ", sampleFormat: " << sampleFormat_.rate << "\n"; // LOG(DEBUG) << "chunk: " << pcmChunk->payloadSize << ", sampleFormat: " << sampleFormat_.getFormat() << "\n";
if (decoder_->decode(pcmChunk.get())) if (decoder_->decode(pcmChunk.get()))
{ {
// TODO: do decoding in thread? // TODO: do decoding in thread?
@ -119,7 +119,7 @@ void Controller::onMessageReceived(ClientConnection* /*connection*/, const msg::
throw SnapException("codec not supported: \"" + headerChunk_->codec + "\""); throw SnapException("codec not supported: \"" + headerChunk_->codec + "\"");
sampleFormat_ = decoder_->setHeader(headerChunk_.get()); sampleFormat_ = decoder_->setHeader(headerChunk_.get());
LOG(NOTICE) << TAG("state") << "sampleformat: " << sampleFormat_.rate << ":" << sampleFormat_.bits << ":" << sampleFormat_.channels << "\n"; LOG(NOTICE) << TAG("state") << "sampleformat: " << sampleFormat_.getFormat() << "\n";
stream_ = make_shared<Stream>(sampleFormat_, settings_.player.sample_format); stream_ = make_shared<Stream>(sampleFormat_, settings_.player.sample_format);
stream_->setBufferLen(serverSettings_->getBufferMs() - settings_.player.latency); stream_->setBufferLen(serverSettings_->getBufferMs() - settings_.player.latency);

View file

@ -91,12 +91,11 @@ bool FlacDecoder::decode(msg::PcmChunk* chunk)
if ((cacheInfo_.cachedBlocks_ > 0) && (cacheInfo_.sampleRate_ != 0)) if ((cacheInfo_.cachedBlocks_ > 0) && (cacheInfo_.sampleRate_ != 0))
{ {
double diffMs = cacheInfo_.cachedBlocks_ / ((double)cacheInfo_.sampleRate_ / 1000.); double diffMs = static_cast<double>(cacheInfo_.cachedBlocks_) / (static_cast<double>(cacheInfo_.sampleRate_) / 1000.);
int32_t s = (diffMs / 1000); auto us = static_cast<uint64_t>(diffMs * 1000.);
int32_t us = (diffMs * 1000); tv diff(us / 1000000, us % 1000000);
us %= 1000000; LOG(DEBUG) << "Cached: " << cacheInfo_.cachedBlocks_ << ", " << diffMs << "ms, " << diff.sec << "s, " << diff.usec << "us\n";
LOG(DEBUG) << "Cached: " << cacheInfo_.cachedBlocks_ << ", " << diffMs << "ms, " << s << "s, " << us << "us\n"; chunk->timestamp = chunk->timestamp - diff;
chunk->timestamp = chunk->timestamp - tv(s, us);
} }
return true; return true;
} }
@ -116,9 +115,8 @@ SampleFormat FlacDecoder::setHeader(msg::CodecHeader* chunk)
if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
throw SnapException("ERROR: initializing decoder: " + string(FLAC__StreamDecoderInitStatusString[init_status])); throw SnapException("ERROR: initializing decoder: " + string(FLAC__StreamDecoderInitStatusString[init_status]));
sampleFormat.rate = 0;
FLAC__stream_decoder_process_until_end_of_metadata(decoder); FLAC__stream_decoder_process_until_end_of_metadata(decoder);
if (sampleFormat.rate == 0) if (sampleFormat.rate() == 0)
throw SnapException("Sample format not found"); throw SnapException("Sample format not found");
return sampleFormat; return sampleFormat;
@ -158,7 +156,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* /*decod
{ {
if (pcmChunk != nullptr) if (pcmChunk != nullptr)
{ {
size_t bytes = frame->header.blocksize * sampleFormat.frameSize; size_t bytes = frame->header.blocksize * sampleFormat.frameSize();
FlacDecoder* flacDecoder = static_cast<FlacDecoder*>(client_data); FlacDecoder* flacDecoder = static_cast<FlacDecoder*>(client_data);
if (flacDecoder->cacheInfo_.isCachedChunk_) if (flacDecoder->cacheInfo_.isCachedChunk_)
@ -166,7 +164,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* /*decod
pcmChunk->payload = (char*)realloc(pcmChunk->payload, pcmChunk->payloadSize + bytes); pcmChunk->payload = (char*)realloc(pcmChunk->payload, pcmChunk->payloadSize + bytes);
for (size_t channel = 0; channel < sampleFormat.channels; ++channel) for (size_t channel = 0; channel < sampleFormat.channels(); ++channel)
{ {
if (buffer[channel] == nullptr) if (buffer[channel] == nullptr)
{ {
@ -174,23 +172,23 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* /*decod
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
} }
if (sampleFormat.sampleSize == 1) if (sampleFormat.sampleSize() == 1)
{ {
int8_t* chunkBuffer = (int8_t*)(pcmChunk->payload + pcmChunk->payloadSize); int8_t* chunkBuffer = (int8_t*)(pcmChunk->payload + pcmChunk->payloadSize);
for (size_t i = 0; i < frame->header.blocksize; i++) for (size_t i = 0; i < frame->header.blocksize; i++)
chunkBuffer[sampleFormat.channels * i + channel] = (int8_t)(buffer[channel][i]); chunkBuffer[sampleFormat.channels() * i + channel] = (int8_t)(buffer[channel][i]);
} }
else if (sampleFormat.sampleSize == 2) else if (sampleFormat.sampleSize() == 2)
{ {
int16_t* chunkBuffer = (int16_t*)(pcmChunk->payload + pcmChunk->payloadSize); int16_t* chunkBuffer = (int16_t*)(pcmChunk->payload + pcmChunk->payloadSize);
for (size_t i = 0; i < frame->header.blocksize; i++) for (size_t i = 0; i < frame->header.blocksize; i++)
chunkBuffer[sampleFormat.channels * i + channel] = SWAP_16((int16_t)(buffer[channel][i])); chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_16((int16_t)(buffer[channel][i]));
} }
else if (sampleFormat.sampleSize == 4) else if (sampleFormat.sampleSize() == 4)
{ {
int32_t* chunkBuffer = (int32_t*)(pcmChunk->payload + pcmChunk->payloadSize); int32_t* chunkBuffer = (int32_t*)(pcmChunk->payload + pcmChunk->payloadSize);
for (size_t i = 0; i < frame->header.blocksize; i++) for (size_t i = 0; i < frame->header.blocksize; i++)
chunkBuffer[sampleFormat.channels * i + channel] = SWAP_32((int32_t)(buffer[channel][i])); chunkBuffer[sampleFormat.channels() * i + channel] = SWAP_32((int32_t)(buffer[channel][i]));
} }
} }
pcmChunk->payloadSize += bytes; pcmChunk->payloadSize += bytes;

View file

@ -104,16 +104,16 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
(-1.<=range<=1.) to whatever PCM format and write it out */ (-1.<=range<=1.) to whatever PCM format and write it out */
while ((samples = vorbis_synthesis_pcmout(&vd, &pcm)) > 0) while ((samples = vorbis_synthesis_pcmout(&vd, &pcm)) > 0)
{ {
size_t bytes = sampleFormat_.sampleSize * vi.channels * samples; size_t bytes = sampleFormat_.sampleSize() * vi.channels * samples;
chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize + bytes); chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize + bytes);
for (int channel = 0; channel < vi.channels; ++channel) for (int channel = 0; channel < vi.channels; ++channel)
{ {
if (sampleFormat_.sampleSize == 1) if (sampleFormat_.sampleSize() == 1)
{ {
int8_t* chunkBuffer = (int8_t*)(chunk->payload + chunk->payloadSize); int8_t* chunkBuffer = (int8_t*)(chunk->payload + chunk->payloadSize);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
{ {
int8_t& val = chunkBuffer[sampleFormat_.channels * i + channel]; int8_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
#ifdef HAS_TREMOR #ifdef HAS_TREMOR
val = clip<int8_t>(pcm[channel][i], -128, 127); val = clip<int8_t>(pcm[channel][i], -128, 127);
#else #else
@ -121,12 +121,12 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
#endif #endif
} }
} }
else if (sampleFormat_.sampleSize == 2) else if (sampleFormat_.sampleSize() == 2)
{ {
int16_t* chunkBuffer = (int16_t*)(chunk->payload + chunk->payloadSize); int16_t* chunkBuffer = (int16_t*)(chunk->payload + chunk->payloadSize);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
{ {
int16_t& val = chunkBuffer[sampleFormat_.channels * i + channel]; int16_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
#ifdef HAS_TREMOR #ifdef HAS_TREMOR
val = SWAP_16(clip<int16_t>(pcm[channel][i] >> 9, -32768, 32767)); val = SWAP_16(clip<int16_t>(pcm[channel][i] >> 9, -32768, 32767));
#else #else
@ -134,12 +134,12 @@ bool OggDecoder::decode(msg::PcmChunk* chunk)
#endif #endif
} }
} }
else if (sampleFormat_.sampleSize == 4) else if (sampleFormat_.sampleSize() == 4)
{ {
int32_t* chunkBuffer = (int32_t*)(chunk->payload + chunk->payloadSize); int32_t* chunkBuffer = (int32_t*)(chunk->payload + chunk->payloadSize);
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
{ {
int32_t& val = chunkBuffer[sampleFormat_.channels * i + channel]; int32_t& val = chunkBuffer[sampleFormat_.channels() * i + channel];
#ifdef HAS_TREMOR #ifdef HAS_TREMOR
val = SWAP_32(clip<int32_t>(pcm[channel][i] << 7, -2147483648, 2147483647)); val = SWAP_32(clip<int32_t>(pcm[channel][i] << 7, -2147483648, 2147483647));
#else #else

View file

@ -50,13 +50,13 @@ bool OpusDecoder::decode(msg::PcmChunk* chunk)
{ {
int frame_size = 0; int frame_size = 0;
while ((frame_size = opus_decode(dec_, (unsigned char*)chunk->payload, chunk->payloadSize, pcm_.data(), pcm_.size() / sample_format_.channels, 0)) == while ((frame_size = opus_decode(dec_, (unsigned char*)chunk->payload, chunk->payloadSize, pcm_.data(), pcm_.size() / sample_format_.channels(), 0)) ==
OPUS_BUFFER_TOO_SMALL) OPUS_BUFFER_TOO_SMALL)
{ {
if (pcm_.size() < const_max_frame_size * sample_format_.channels) if (pcm_.size() < const_max_frame_size * sample_format_.channels())
{ {
pcm_.resize(pcm_.size() * 2); pcm_.resize(pcm_.size() * 2);
LOG(INFO) << "OPUS encoding buffer too small, resizing to " << pcm_.size() / sample_format_.channels << " samples per channel\n"; LOG(INFO) << "OPUS encoding buffer too small, resizing to " << pcm_.size() / sample_format_.channels() << " samples per channel\n";
} }
else else
break; break;
@ -72,7 +72,7 @@ bool OpusDecoder::decode(msg::PcmChunk* chunk)
LOG(DEBUG) << "Decoded chunk: size " << chunk->payloadSize << " bytes, decoded " << frame_size << " samples" << '\n'; LOG(DEBUG) << "Decoded chunk: size " << chunk->payloadSize << " bytes, decoded " << frame_size << " samples" << '\n';
// copy encoded data to chunk // copy encoded data to chunk
chunk->payloadSize = frame_size * sample_format_.channels * sizeof(opus_int16); chunk->payloadSize = frame_size * sample_format_.channels() * sizeof(opus_int16);
chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize); chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize);
memcpy(chunk->payload, (char*)pcm_.data(), chunk->payloadSize); memcpy(chunk->payload, (char*)pcm_.data(), chunk->payloadSize);
return true; return true;
@ -105,7 +105,7 @@ SampleFormat OpusDecoder::setHeader(msg::CodecHeader* chunk)
// create the decoder // create the decoder
int error; int error;
dec_ = opus_decoder_create(sample_format_.rate, sample_format_.channels, &error); dec_ = opus_decoder_create(sample_format_.rate(), sample_format_.channels(), &error);
if (error != 0) if (error != 0)
throw SnapException("Failed to initialize Opus decoder: " + std::string(opus_strerror(error))); throw SnapException("Failed to initialize Opus decoder: " + std::string(opus_strerror(error)));

View file

@ -38,8 +38,8 @@ void AlsaPlayer::initAlsa()
snd_pcm_hw_params_t* params; snd_pcm_hw_params_t* params;
const SampleFormat& format = stream_->getFormat(); const SampleFormat& format = stream_->getFormat();
rate = format.rate; rate = format.rate();
channels = format.channels; channels = format.channels();
/* Open the PCM device in playback mode */ /* Open the PCM device in playback mode */
if ((pcm = snd_pcm_open(&handle_, pcmDevice_.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) if ((pcm = snd_pcm_open(&handle_, pcmDevice_.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
@ -61,16 +61,16 @@ void AlsaPlayer::initAlsa()
throw SnapException("Can't set interleaved mode: " + string(snd_strerror(pcm))); throw SnapException("Can't set interleaved mode: " + string(snd_strerror(pcm)));
snd_pcm_format_t snd_pcm_format; snd_pcm_format_t snd_pcm_format;
if (format.bits == 8) if (format.bits() == 8)
snd_pcm_format = SND_PCM_FORMAT_S8; snd_pcm_format = SND_PCM_FORMAT_S8;
else if (format.bits == 16) else if (format.bits() == 16)
snd_pcm_format = SND_PCM_FORMAT_S16_LE; snd_pcm_format = SND_PCM_FORMAT_S16_LE;
else if ((format.bits == 24) && (format.sampleSize == 4)) else if ((format.bits() == 24) && (format.sampleSize() == 4))
snd_pcm_format = SND_PCM_FORMAT_S24_LE; snd_pcm_format = SND_PCM_FORMAT_S24_LE;
else if (format.bits == 32) else if (format.bits() == 32)
snd_pcm_format = SND_PCM_FORMAT_S32_LE; snd_pcm_format = SND_PCM_FORMAT_S32_LE;
else else
throw SnapException("Unsupported sample format: " + cpt::to_string(format.bits)); throw SnapException("Unsupported sample format: " + cpt::to_string(format.bits()));
pcm = snd_pcm_hw_params_set_format(handle_, params, snd_pcm_format); pcm = snd_pcm_hw_params_set_format(handle_, params, snd_pcm_format);
if (pcm == -EINVAL) if (pcm == -EINVAL)
@ -233,8 +233,8 @@ void AlsaPlayer::worker()
chronos::usec delay(static_cast<chronos::usec::rep>(1000 * (double)framesDelay / format.msRate())); chronos::usec delay(static_cast<chronos::usec::rep>(1000 * (double)framesDelay / format.msRate()));
// LOG(TRACE) << "delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << ", avail: " << framesAvail << "\n"; // LOG(TRACE) << "delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << ", avail: " << framesAvail << "\n";
if (buffer_.size() < static_cast<size_t>(framesAvail * format.frameSize)) if (buffer_.size() < static_cast<size_t>(framesAvail * format.frameSize()))
buffer_.resize(framesAvail * format.frameSize); buffer_.resize(framesAvail * format.frameSize());
if (stream_->getPlayerChunk(buffer_.data(), delay, framesAvail)) if (stream_->getPlayerChunk(buffer_.data(), delay, framesAvail))
{ {
lastChunkTick = chronos::getTickCount(); lastChunkTick = chronos::getTickCount();

View file

@ -155,12 +155,12 @@ void CoreAudioPlayer::initAudioQueue()
const SampleFormat& sampleFormat = pubStream_->getFormat(); const SampleFormat& sampleFormat = pubStream_->getFormat();
AudioStreamBasicDescription format; AudioStreamBasicDescription format;
format.mSampleRate = sampleFormat.rate; format.mSampleRate = sampleFormat.rate();
format.mFormatID = kAudioFormatLinearPCM; format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // | kAudioFormatFlagIsPacked; format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; // | kAudioFormatFlagIsPacked;
format.mBitsPerChannel = sampleFormat.bits; format.mBitsPerChannel = sampleFormat.bits;
format.mChannelsPerFrame = sampleFormat.channels; format.mChannelsPerFrame = sampleFormat.channels();
format.mBytesPerFrame = sampleFormat.frameSize; format.mBytesPerFrame = sampleFormat.frameSize();
format.mFramesPerPacket = 1; format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket; format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
format.mReserved = 0; format.mReserved = 0;
@ -176,9 +176,9 @@ void CoreAudioPlayer::initAudioQueue()
// //
// For 100ms @ 48000:16:2 we have 19.2K // For 100ms @ 48000:16:2 we have 19.2K
// frames: 4800, ms: 100, buffer size: 19200 // frames: 4800, ms: 100, buffer size: 19200
frames_ = (sampleFormat.rate * ms_) / 1000; frames_ = (sampleFormat.rate() * ms_) / 1000;
ms_ = frames_ * 1000 / sampleFormat.rate; ms_ = frames_ * 1000 / sampleFormat.rate();
buff_size_ = frames_ * sampleFormat.frameSize; buff_size_ = frames_ * sampleFormat.frameSize();
LOG(INFO) << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n"; LOG(INFO) << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n";
AudioQueueBufferRef buffers[NUM_BUFFERS]; AudioQueueBufferRef buffers[NUM_BUFFERS];

View file

@ -161,10 +161,10 @@ void OpenslPlayer::initOpensl()
const SampleFormat& format = stream_->getFormat(); const SampleFormat& format = stream_->getFormat();
frames_ = format.rate / (1000 / ms_); // * format.channels; // 1920; // 48000 * 2 / 50 // => 50ms frames_ = format.rate() / (1000 / ms_); // * format.channels(); // 1920; // 48000 * 2 / 50 // => 50ms
buff_size = frames_ * format.frameSize /* 2 -> sample size */; buff_size = frames_ * format.frameSize() /* 2 -> sample size */;
LOG(INFO, LOG_TAG) << "frames: " << frames_ << ", channels: " << format.channels << ", rate: " << format.rate << ", buff: " << buff_size << "\n"; LOG(INFO, LOG_TAG) << "frames: " << frames_ << ", channels: " << format.channels() << ", rate: " << format.rate() << ", buff: " << buff_size << "\n";
SLresult result; SLresult result;
// create engine // create engine
@ -181,7 +181,7 @@ void OpenslPlayer::initOpensl()
throwUnsuccess(kPhaseInit, "OutputMixObject::Realize", result); throwUnsuccess(kPhaseInit, "OutputMixObject::Realize", result);
SLuint32 samplesPerSec = SL_SAMPLINGRATE_48; SLuint32 samplesPerSec = SL_SAMPLINGRATE_48;
switch (format.rate) switch (format.rate())
{ {
case 8000: case 8000:
samplesPerSec = SL_SAMPLINGRATE_8; samplesPerSec = SL_SAMPLINGRATE_8;
@ -250,7 +250,7 @@ void OpenslPlayer::initOpensl()
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = { SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM, format.channels, samplesPerSec, bitsPerSample, containerSize, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_DATAFORMAT_PCM, format.channels(), samplesPerSec, bitsPerSample, containerSize, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN}; SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm}; SLDataSource audioSrc = {&loc_bufq, &format_pcm};

View file

@ -68,12 +68,12 @@ void Player::adjustVolume(char* buffer, size_t frames)
if ((volume < 1.0) || (volCorrection_ != 1.)) if ((volume < 1.0) || (volCorrection_ != 1.))
{ {
volume *= volCorrection_; volume *= volCorrection_;
if (sampleFormat.sampleSize == 1) if (sampleFormat.sampleSize() == 1)
adjustVolume<int8_t>(buffer, frames * sampleFormat.channels, volume); adjustVolume<int8_t>(buffer, frames * sampleFormat.channels(), volume);
else if (sampleFormat.sampleSize == 2) else if (sampleFormat.sampleSize() == 2)
adjustVolume<int16_t>(buffer, frames * sampleFormat.channels, volume); adjustVolume<int16_t>(buffer, frames * sampleFormat.channels(), volume);
else if (sampleFormat.sampleSize == 4) else if (sampleFormat.sampleSize() == 4)
adjustVolume<int32_t>(buffer, frames * sampleFormat.channels, volume); adjustVolume<int32_t>(buffer, frames * sampleFormat.channels(), volume);
} }
} }

View file

@ -38,7 +38,7 @@ Stream::Stream(const SampleFormat& in_format, const SampleFormat& out_format)
shortBuffer_.setSize(100); shortBuffer_.setSize(100);
miniBuffer_.setSize(20); miniBuffer_.setSize(20);
if (out_format.rate != 0) if (out_format.rate() != 0)
format_ = out_format; format_ = out_format;
else else
format_ = in_format_; format_ = in_format_;
@ -50,30 +50,30 @@ Stream::Stream(const SampleFormat& in_format, const SampleFormat& out_format)
x = 1,000016667 / (1,000016667 - 1) x = 1,000016667 / (1,000016667 - 1)
*/ */
// setRealSampleRate(format_.rate); // setRealSampleRate(format_.rate());
if ((format_.rate != in_format_.rate) || (format_.bits != in_format_.bits)) if ((format_.rate() != in_format_.rate()) || (format_.bits() != in_format_.bits()))
{ {
LOG(INFO, LOG_TAG) << "Resampling from " << in_format_.getFormat() << " to " << format_.getFormat() << "\n"; LOG(INFO, LOG_TAG) << "Resampling from " << in_format_.getFormat() << " to " << format_.getFormat() << "\n";
soxr_error_t error; soxr_error_t error;
soxr_datatype_t in_type = SOXR_INT16_I; soxr_datatype_t in_type = SOXR_INT16_I;
soxr_datatype_t out_type = SOXR_INT16_I; soxr_datatype_t out_type = SOXR_INT16_I;
if (in_format_.sampleSize > 2) if (in_format_.sampleSize() > 2)
in_type = SOXR_INT32_I; in_type = SOXR_INT32_I;
if (format_.sampleSize > 2) if (format_.sampleSize() > 2)
out_type = SOXR_INT32_I; out_type = SOXR_INT32_I;
soxr_io_spec_t iospec = soxr_io_spec(in_type, out_type); soxr_io_spec_t iospec = soxr_io_spec(in_type, out_type);
// HQ should be fine: http://sox.sourceforge.net/Docs/FAQ // HQ should be fine: http://sox.sourceforge.net/Docs/FAQ
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0); soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, 0);
soxr_ = soxr_create(static_cast<double>(in_format_.rate), static_cast<double>(format_.rate), format_.channels, &error, &iospec, &q_spec, NULL); soxr_ = soxr_create(static_cast<double>(in_format_.rate()), static_cast<double>(format_.rate()), format_.channels(), &error, &iospec, &q_spec, NULL);
if (error) if (error)
{ {
LOG(ERROR, LOG_TAG) << "Error soxr_create: " << error << "\n"; LOG(ERROR, LOG_TAG) << "Error soxr_create: " << error << "\n";
soxr_ = nullptr; soxr_ = nullptr;
} }
// initialize the buffer with 20ms (~latency of the reampler) // initialize the buffer with 20ms (~latency of the reampler)
resample_buffer_.resize(format_.frameSize * ceil(format_.msRate()) * 20); resample_buffer_.resize(format_.frameSize() * ceil(format_.msRate()) * 20);
} }
} }
@ -87,14 +87,14 @@ Stream::~Stream()
void Stream::setRealSampleRate(double sampleRate) void Stream::setRealSampleRate(double sampleRate)
{ {
if (sampleRate == format_.rate) if (sampleRate == format_.rate())
{ {
correctAfterXFrames_ = 0; correctAfterXFrames_ = 0;
} }
else else
{ {
correctAfterXFrames_ = round((format_.rate / sampleRate) / (format_.rate / sampleRate - 1.)); correctAfterXFrames_ = round((format_.rate() / sampleRate) / (format_.rate() / sampleRate - 1.));
// LOG(TRACE, LOG_TAG) << "Correct after X: " << correctAfterXFrames_ << " (Real rate: " << sampleRate << ", rate: " << format_.rate << ")\n"; // LOG(TRACE, LOG_TAG) << "Correct after X: " << correctAfterXFrames_ << " (Real rate: " << sampleRate << ", rate: " << format_.rate() << ")\n";
} }
} }
@ -135,7 +135,7 @@ void Stream::addChunk(unique_ptr<msg::PcmChunk> chunk)
} }
else else
{ {
if (in_format_.bits == 24) if (in_format_.bits() == 24)
{ {
// sox expects 32 bit input, shift 8 bits left // sox expects 32 bit input, shift 8 bits left
int32_t* frames = (int32_t*)chunk->payload; int32_t* frames = (int32_t*)chunk->payload;
@ -145,7 +145,7 @@ void Stream::addChunk(unique_ptr<msg::PcmChunk> chunk)
size_t idone; size_t idone;
size_t odone; size_t odone;
auto resample_buffer_framesize = resample_buffer_.size() / format_.frameSize; auto resample_buffer_framesize = resample_buffer_.size() / format_.frameSize();
auto error = soxr_process(soxr_, chunk->payload, chunk->getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone); auto error = soxr_process(soxr_, chunk->payload, chunk->getFrameCount(), &idone, resample_buffer_.data(), resample_buffer_framesize, &odone);
if (error) if (error)
{ {
@ -154,7 +154,7 @@ void Stream::addChunk(unique_ptr<msg::PcmChunk> chunk)
else else
{ {
LOG(TRACE, LOG_TAG) << "Resample idone: " << idone << "/" << chunk->getFrameCount() << ", odone: " << odone << "/" LOG(TRACE, LOG_TAG) << "Resample idone: " << idone << "/" << chunk->getFrameCount() << ", odone: " << odone << "/"
<< resample_buffer_.size() / format_.frameSize << ", delay: " << soxr_delay(soxr_) << "\n"; << resample_buffer_.size() / format_.frameSize() << ", delay: " << soxr_delay(soxr_) << "\n";
// some data has been resampled (odone frames) and some is still in the pipe (soxr_delay frames) // some data has been resampled (odone frames) and some is still in the pipe (soxr_delay frames)
if (odone > 0) if (odone > 0)
@ -170,11 +170,11 @@ void Stream::addChunk(unique_ptr<msg::PcmChunk> chunk)
resampled_chunk->timestamp.usec = us % 1000000; resampled_chunk->timestamp.usec = us % 1000000;
// copy from the resample_buffer to the resampled chunk // copy from the resample_buffer to the resampled chunk
resampled_chunk->payloadSize = odone * format_.frameSize; resampled_chunk->payloadSize = odone * format_.frameSize();
resampled_chunk->payload = (char*)realloc(resampled_chunk->payload, resampled_chunk->payloadSize); resampled_chunk->payload = (char*)realloc(resampled_chunk->payload, resampled_chunk->payloadSize);
memcpy(resampled_chunk->payload, resample_buffer_.data(), resampled_chunk->payloadSize); memcpy(resampled_chunk->payload, resample_buffer_.data(), resampled_chunk->payloadSize);
if (format_.bits == 24) if (format_.bits() == 24)
{ {
// sox has quantized to 32 bit, shift 8 bits right // sox has quantized to 32 bit, shift 8 bits right
int32_t* frames = (int32_t*)resampled_chunk->payload; int32_t* frames = (int32_t*)resampled_chunk->payload;
@ -192,7 +192,7 @@ void Stream::addChunk(unique_ptr<msg::PcmChunk> chunk)
if (odone == resample_buffer_framesize) if (odone == resample_buffer_framesize)
{ {
// buffer for resampled data too small, add space for 5ms // buffer for resampled data too small, add space for 5ms
resample_buffer_.resize(resample_buffer_.size() + format_.frameSize * ceil(format_.msRate()) * 5); resample_buffer_.resize(resample_buffer_.size() + format_.frameSize() * ceil(format_.msRate()) * 5);
LOG(DEBUG, LOG_TAG) << "Resample buffer completely filled, adding space for 5ms; new buffer size: " << resample_buffer_.size() LOG(DEBUG, LOG_TAG) << "Resample buffer completely filled, adding space for 5ms; new buffer size: " << resample_buffer_.size()
<< " bytes\n"; << " bytes\n";
} }
@ -216,7 +216,7 @@ bool Stream::waitForChunk(const std::chrono::milliseconds& timeout) const
void Stream::getSilentPlayerChunk(void* outputBuffer, uint32_t frames) const void Stream::getSilentPlayerChunk(void* outputBuffer, uint32_t frames) const
{ {
memset(outputBuffer, 0, frames * format_.frameSize); memset(outputBuffer, 0, frames * format_.frameSize());
} }
@ -229,7 +229,7 @@ cs::time_point_clk Stream::getNextPlayerChunk(void* outputBuffer, uint32_t frame
uint32_t read = 0; uint32_t read = 0;
while (read < frames) while (read < frames)
{ {
read += chunk_->readFrames(static_cast<char*>(outputBuffer) + read * format_.frameSize, frames - read); read += chunk_->readFrames(static_cast<char*>(outputBuffer) + read * format_.frameSize(), frames - read);
if (chunk_->isEndOfChunk() && !chunks_.try_pop(chunk_)) if (chunk_->isEndOfChunk() && !chunks_.try_pop(chunk_))
throw 0; throw 0;
} }
@ -251,8 +251,8 @@ cs::time_point_clk Stream::getNextPlayerChunk(void* outputBuffer, uint32_t frame
frame_delta_ -= framesCorrection; frame_delta_ -= framesCorrection;
uint32_t toRead = frames + framesCorrection; uint32_t toRead = frames + framesCorrection;
if (toRead * format_.frameSize > read_buffer_.size()) if (toRead * format_.frameSize() > read_buffer_.size())
read_buffer_.resize(toRead * format_.frameSize); read_buffer_.resize(toRead * format_.frameSize());
cs::time_point_clk tp = getNextPlayerChunk(read_buffer_.data(), toRead); cs::time_point_clk tp = getNextPlayerChunk(read_buffer_.data(), toRead);
const auto max = framesCorrection < 0 ? frames : toRead; const auto max = framesCorrection < 0 ? frames : toRead;
@ -284,14 +284,16 @@ cs::time_point_clk Stream::getNextPlayerChunk(void* outputBuffer, uint32_t frame
// Read one frame less per slice from the input, but write a duplicated frame per slice to the output // Read one frame less per slice from the input, but write a duplicated frame per slice to the output
// LOG(TRACE, LOG_TAG) << "duplicate - requested: " << frames << ", read: " << toRead << ", slice: " << n << ", size: " << size << ", out pos: " << // LOG(TRACE, LOG_TAG) << "duplicate - requested: " << frames << ", read: " << toRead << ", slice: " << n << ", size: " << size << ", out pos: " <<
// pos << ", source pos: " << pos - n << "\n"; // pos << ", source pos: " << pos - n << "\n";
memcpy(static_cast<char*>(outputBuffer) + pos * format_.frameSize, read_buffer_.data() + (pos - n) * format_.frameSize, size * format_.frameSize); memcpy(static_cast<char*>(outputBuffer) + pos * format_.frameSize(), read_buffer_.data() + (pos - n) * format_.frameSize(),
size * format_.frameSize());
} }
else else
{ {
// Read all input frames, but skip a frame per slice when writing to the output. // Read all input frames, but skip a frame per slice when writing to the output.
// LOG(TRACE, LOG_TAG) << "remove - requested: " << frames << ", read: " << toRead << ", slice: " << n << ", size: " << size << ", out pos: " << pos // LOG(TRACE, LOG_TAG) << "remove - requested: " << frames << ", read: " << toRead << ", slice: " << n << ", size: " << size << ", out pos: " << pos
// - n << ", source pos: " << pos << "\n"; // - n << ", source pos: " << pos << "\n";
memcpy(static_cast<char*>(outputBuffer) + (pos - n) * format_.frameSize, read_buffer_.data() + pos * format_.frameSize, size * format_.frameSize); memcpy(static_cast<char*>(outputBuffer) + (pos - n) * format_.frameSize(), read_buffer_.data() + pos * format_.frameSize(),
size * format_.frameSize());
} }
pos += size; pos += size;
} }
@ -381,7 +383,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
LOG(DEBUG, LOG_TAG) << "Silent frames: " << silent_frames << ", frames: " << frames LOG(DEBUG, LOG_TAG) << "Silent frames: " << silent_frames << ", frames: " << frames
<< ", age: " << std::chrono::duration_cast<cs::usec>(age).count() / 1000. << "\n"; << ", age: " << std::chrono::duration_cast<cs::usec>(age).count() / 1000. << "\n";
getSilentPlayerChunk(outputBuffer, silent_frames); getSilentPlayerChunk(outputBuffer, silent_frames);
getNextPlayerChunk((char*)outputBuffer + (chunk_->format.frameSize * silent_frames), frames - silent_frames); getNextPlayerChunk((char*)outputBuffer + (chunk_->format.frameSize() * silent_frames), frames - silent_frames);
if (result) if (result)
{ {
@ -410,7 +412,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
cs::usec age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, frames, framesCorrection) - bufferMs_ + cs::usec age = std::chrono::duration_cast<cs::usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, frames, framesCorrection) - bufferMs_ +
outputBufferDacTime); outputBufferDacTime);
setRealSampleRate(format_.rate); setRealSampleRate(format_.rate());
// check if we need a hard sync // check if we need a hard sync
if (buffer_.full() && (cs::usec(abs(median_)) > cs::msec(2))) if (buffer_.full() && (cs::usec(abs(median_)) > cs::msec(2)))
{ {
@ -444,7 +446,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
// LOG(INFO, LOG_TAG) << "Rate: " << rate << "\n"; // LOG(INFO, LOG_TAG) << "Rate: " << rate << "\n";
// we are late (age > 0), this means we are not playing fast enough // we are late (age > 0), this means we are not playing fast enough
// => the real sample rate seems to be lower, we have to drop some frames // => the real sample rate seems to be lower, we have to drop some frames
setRealSampleRate(format_.rate * rate); // 0.9999); setRealSampleRate(format_.rate() * rate); // 0.9999);
} }
else if ((cs::usec(shortMedian_) < -kCorrectionBegin) && (cs::usec(miniMedian) < -cs::usec(50)) && (cs::usec(age) < -cs::usec(50))) else if ((cs::usec(shortMedian_) < -kCorrectionBegin) && (cs::usec(miniMedian) < -cs::usec(50)) && (cs::usec(age) < -cs::usec(50)))
{ {
@ -453,7 +455,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT
// LOG(INFO, LOG_TAG) << "Rate: " << rate << "\n"; // LOG(INFO, LOG_TAG) << "Rate: " << rate << "\n";
// we are early (age > 0), this means we are playing too fast // we are early (age > 0), this means we are playing too fast
// => the real sample rate seems to be higher, we have to insert some frames // => the real sample rate seems to be higher, we have to insert some frames
setRealSampleRate(format_.rate * rate); // 1.0001); setRealSampleRate(format_.rate() * rate); // 1.0001);
} }
} }

View file

@ -36,7 +36,7 @@ namespace msg
class PcmChunk : public WireChunk class PcmChunk : public WireChunk
{ {
public: public:
PcmChunk(const SampleFormat& sampleFormat, size_t ms) : WireChunk(sampleFormat.rate * sampleFormat.frameSize * ms / 1000), format(sampleFormat), idx_(0) PcmChunk(const SampleFormat& sampleFormat, size_t ms) : WireChunk(sampleFormat.rate() * sampleFormat.frameSize() * ms / 1000), format(sampleFormat), idx_(0)
{ {
} }
@ -59,18 +59,18 @@ public:
int readFrames(void* outputBuffer, size_t frameCount) int readFrames(void* outputBuffer, size_t frameCount)
{ {
// logd << "read: " << frameCount << ", total: " << (wireChunk->length / format.frameSize) << ", idx: " << idx;// << std::endl; // logd << "read: " << frameCount << ", total: " << (wireChunk->length / format.frameSize()) << ", idx: " << idx;// << std::endl;
int result = frameCount; int result = frameCount;
if (idx_ + frameCount > (payloadSize / format.frameSize)) if (idx_ + frameCount > (payloadSize / format.frameSize()))
result = (payloadSize / format.frameSize) - idx_; result = (payloadSize / format.frameSize()) - idx_;
// logd << ", from: " << format.frameSize*idx << ", to: " << format.frameSize*idx + format.frameSize*result; // logd << ", from: " << format.frameSize()*idx << ", to: " << format.frameSize()*idx + format.frameSize()*result;
if (outputBuffer != nullptr) if (outputBuffer != nullptr)
memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize * idx_, format.frameSize * result); memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize() * idx_, format.frameSize() * result);
idx_ += result; idx_ += result;
// logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize // logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize(): " <<
// << "\n";//std::endl; // format.frameSize() << "\n";
return result; return result;
} }
@ -90,7 +90,7 @@ public:
chronos::time_point_clk start() const override chronos::time_point_clk start() const override
{ {
return chronos::time_point_clk(chronos::sec(timestamp.sec) + chronos::usec(timestamp.usec) + return chronos::time_point_clk(chronos::sec(timestamp.sec) + chronos::usec(timestamp.usec) +
chronos::usec(static_cast<chronos::usec::rep>(1000000. * ((double)idx_ / (double)format.rate)))); chronos::usec(static_cast<chronos::usec::rep>(1000000. * ((double)idx_ / (double)format.rate()))));
} }
inline chronos::time_point_clk end() const inline chronos::time_point_clk end() const
@ -117,12 +117,12 @@ public:
inline size_t getFrameCount() const inline size_t getFrameCount() const
{ {
return (payloadSize / format.frameSize); return (payloadSize / format.frameSize());
} }
inline size_t getSampleCount() const inline size_t getSampleCount() const
{ {
return (payloadSize / format.sampleSize); return (payloadSize / format.sampleSize());
} }
SampleFormat format; SampleFormat format;

View file

@ -51,7 +51,7 @@ SampleFormat::SampleFormat(uint32_t sampleRate, uint16_t bitsPerSample, uint16_t
string SampleFormat::getFormat() const string SampleFormat::getFormat() const
{ {
stringstream ss; stringstream ss;
ss << rate << ":" << bits << ":" << channels; ss << rate_ << ":" << bits_ << ":" << channels_;
return ss.str(); return ss.str();
} }
@ -70,12 +70,12 @@ void SampleFormat::setFormat(uint32_t rate, uint16_t bits, uint16_t channels)
// needs something like: // needs something like:
// 24_4 = 3 bytes, padded to 4 // 24_4 = 3 bytes, padded to 4
// 32 = 4 bytes // 32 = 4 bytes
this->rate = rate; rate_ = rate;
this->bits = bits; bits_ = bits;
this->channels = channels; channels_ = channels;
sampleSize = bits / 8; sample_size_ = bits / 8;
if (bits == 24) if (bits_ == 24)
sampleSize = 4; sample_size_ = 4;
frameSize = channels * sampleSize; frame_size_ = channels_ * sample_size_;
// LOG(DEBUG) << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n"; // LOG(DEBUG) << "SampleFormat: " << rate << ":" << bits << ":" << channels << "\n";
} }

View file

@ -46,30 +46,54 @@ public:
void setFormat(const std::string& format); void setFormat(const std::string& format);
void setFormat(uint32_t rate, uint16_t bits, uint16_t channels); void setFormat(uint32_t rate, uint16_t bits, uint16_t channels);
uint32_t rate; uint32_t rate() const
uint16_t bits; {
uint16_t channels; return rate_;
}
uint16_t bits() const
{
return bits_;
}
uint16_t channels() const
{
return channels_;
}
// size in [bytes] of a single mono sample, e.g. 2 bytes (= 16 bits) // size in [bytes] of a single mono sample, e.g. 2 bytes (= 16 bits)
uint16_t sampleSize; uint16_t sampleSize() const
{
return sample_size_;
}
// size in [bytes] of a frame (sum of sample sizes = #channel*sampleSize), e.g. 4 bytes (= 2 channel * 16 bit) // size in [bytes] of a frame (sum of sample sizes = #channel*sampleSize), e.g. 4 bytes (= 2 channel * 16 bit)
uint16_t frameSize; uint16_t frameSize() const
{
return frame_size_;
}
inline double msRate() const inline double msRate() const
{ {
return (double)rate / 1000.; return (double)rate_ / 1000.;
} }
inline double usRate() const inline double usRate() const
{ {
return (double)rate / 1000000.; return (double)rate_ / 1000000.;
} }
inline double nsRate() const inline double nsRate() const
{ {
return (double)rate / 1000000000.; return (double)rate_ / 1000000000.;
} }
private:
uint16_t sample_size_;
uint16_t frame_size_;
uint32_t rate_;
uint16_t bits_;
uint16_t channels_;
}; };

View file

@ -82,19 +82,19 @@ void FlacEncoder::encode(const msg::PcmChunk* chunk)
pcmBuffer_ = (FLAC__int32*)realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32)); pcmBuffer_ = (FLAC__int32*)realloc(pcmBuffer_, pcmBufferSize_ * sizeof(FLAC__int32));
} }
if (sampleFormat_.sampleSize == 1) if (sampleFormat_.sampleSize() == 1)
{ {
FLAC__int8* buffer = (FLAC__int8*)chunk->payload; FLAC__int8* buffer = (FLAC__int8*)chunk->payload;
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
pcmBuffer_[i] = (FLAC__int32)(buffer[i]); pcmBuffer_[i] = (FLAC__int32)(buffer[i]);
} }
else if (sampleFormat_.sampleSize == 2) else if (sampleFormat_.sampleSize() == 2)
{ {
FLAC__int16* buffer = (FLAC__int16*)chunk->payload; FLAC__int16* buffer = (FLAC__int16*)chunk->payload;
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
pcmBuffer_[i] = (FLAC__int32)(buffer[i]); pcmBuffer_[i] = (FLAC__int32)(buffer[i]);
} }
else if (sampleFormat_.sampleSize == 4) else if (sampleFormat_.sampleSize() == 4)
{ {
FLAC__int32* buffer = (FLAC__int32*)chunk->payload; FLAC__int32* buffer = (FLAC__int32*)chunk->payload;
for (int i = 0; i < samples; i++) for (int i = 0; i < samples; i++)
@ -106,7 +106,7 @@ void FlacEncoder::encode(const msg::PcmChunk* chunk)
if (encodedSamples_ > 0) if (encodedSamples_ > 0)
{ {
double resMs = encodedSamples_ / ((double)sampleFormat_.rate / 1000.); double resMs = encodedSamples_ / sampleFormat_.msRate();
// LOG(INFO) << "encoded: " << chunk->payloadSize << "\tframes: " << encodedSamples_ << "\tres: " << resMs << "\n"; // LOG(INFO) << "encoded: " << chunk->payloadSize << "\tframes: " << encodedSamples_ << "\tres: " << resMs << "\n";
encodedSamples_ = 0; encodedSamples_ = 0;
listener_->onChunkEncoded(this, flacChunk_, resMs); listener_->onChunkEncoded(this, flacChunk_, resMs);
@ -176,9 +176,9 @@ void FlacEncoder::initEncoder()
// 0-2: 1152 frames, ~26.1224ms // 0-2: 1152 frames, ~26.1224ms
// 3-8: 4096 frames, ~92.8798ms // 3-8: 4096 frames, ~92.8798ms
ok &= FLAC__stream_encoder_set_compression_level(encoder_, quality); ok &= FLAC__stream_encoder_set_compression_level(encoder_, quality);
ok &= FLAC__stream_encoder_set_channels(encoder_, sampleFormat_.channels); ok &= FLAC__stream_encoder_set_channels(encoder_, sampleFormat_.channels());
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits); ok &= FLAC__stream_encoder_set_bits_per_sample(encoder_, sampleFormat_.bits());
ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate); ok &= FLAC__stream_encoder_set_sample_rate(encoder_, sampleFormat_.rate());
if (!ok) if (!ok)
throw SnapException("error setting up encoder"); throw SnapException("error setting up encoder");

View file

@ -73,25 +73,25 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
float** buffer = vorbis_analysis_buffer(&vd_, frames); float** buffer = vorbis_analysis_buffer(&vd_, frames);
/* uninterleave samples */ /* uninterleave samples */
for (size_t channel = 0; channel < sampleFormat_.channels; ++channel) for (size_t channel = 0; channel < sampleFormat_.channels(); ++channel)
{ {
if (sampleFormat_.sampleSize == 1) if (sampleFormat_.sampleSize() == 1)
{ {
int8_t* chunkBuffer = (int8_t*)chunk->payload; int8_t* chunkBuffer = (int8_t*)chunk->payload;
for (int i = 0; i < frames; i++) for (int i = 0; i < frames; i++)
buffer[channel][i] = chunkBuffer[sampleFormat_.channels * i + channel] / 128.f; buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 128.f;
} }
else if (sampleFormat_.sampleSize == 2) else if (sampleFormat_.sampleSize() == 2)
{ {
int16_t* chunkBuffer = (int16_t*)chunk->payload; int16_t* chunkBuffer = (int16_t*)chunk->payload;
for (int i = 0; i < frames; i++) for (int i = 0; i < frames; i++)
buffer[channel][i] = chunkBuffer[sampleFormat_.channels * i + channel] / 32768.f; buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 32768.f;
} }
else if (sampleFormat_.sampleSize == 4) else if (sampleFormat_.sampleSize() == 4)
{ {
int32_t* chunkBuffer = (int32_t*)chunk->payload; int32_t* chunkBuffer = (int32_t*)chunk->payload;
for (int i = 0; i < frames; i++) for (int i = 0; i < frames; i++)
buffer[channel][i] = chunkBuffer[sampleFormat_.channels * i + channel] / 2147483648.f; buffer[channel][i] = chunkBuffer[sampleFormat_.channels() * i + channel] / 2147483648.f;
} }
} }
@ -141,7 +141,7 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
if (res > 0) if (res > 0)
{ {
res /= (sampleFormat_.rate / 1000.); res /= sampleFormat_.msRate();
// LOG(INFO) << "res: " << res << "\n"; // LOG(INFO) << "res: " << res << "\n";
lastGranulepos_ = os_.granulepos; lastGranulepos_ = os_.granulepos;
// make oggChunk smaller // make oggChunk smaller
@ -209,7 +209,7 @@ void OggEncoder::initEncoder()
*********************************************************************/ *********************************************************************/
int ret = vorbis_encode_init_vbr(&vi_, sampleFormat_.channels, sampleFormat_.rate, quality); int ret = vorbis_encode_init_vbr(&vi_, sampleFormat_.channels(), sampleFormat_.rate(), quality);
/* do not continue if setup failed; this can happen if we ask for a /* do not continue if setup failed; this can happen if we ask for a
mode that libVorbis does not support (eg, too low a bitrate, etc, mode that libVorbis does not support (eg, too low a bitrate, etc,

View file

@ -77,7 +77,7 @@ void OpusEncoder::initEncoder()
{ {
// Opus is quite restrictive in sample rate and bit depth // Opus is quite restrictive in sample rate and bit depth
// It can handle mono signals, but we will check for stereo // It can handle mono signals, but we will check for stereo
if ((sampleFormat_.rate != 48000) || (sampleFormat_.bits != 16) || (sampleFormat_.channels != 2)) if ((sampleFormat_.rate() != 48000) || (sampleFormat_.bits() != 16) || (sampleFormat_.channels() != 2))
throw SnapException("Opus sampleformat must be 48000:16:2"); throw SnapException("Opus sampleformat must be 48000:16:2");
opus_int32 bitrate = 192000; opus_int32 bitrate = 192000;
@ -135,7 +135,7 @@ void OpusEncoder::initEncoder()
LOG(INFO) << "Opus bitrate: " << bitrate << " bps, complexity: " << complexity << "\n"; LOG(INFO) << "Opus bitrate: " << bitrate << " bps, complexity: " << complexity << "\n";
int error; int error;
enc_ = opus_encoder_create(sampleFormat_.rate, sampleFormat_.channels, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &error); enc_ = opus_encoder_create(sampleFormat_.rate(), sampleFormat_.channels(), OPUS_APPLICATION_RESTRICTED_LOWDELAY, &error);
if (error != 0) if (error != 0)
{ {
throw SnapException("Failed to initialize Opus encoder: " + std::string(opus_strerror(error))); throw SnapException("Failed to initialize Opus encoder: " + std::string(opus_strerror(error)));
@ -149,9 +149,9 @@ void OpusEncoder::initEncoder()
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize); headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize);
char* payload = headerChunk_->payload; char* payload = headerChunk_->payload;
assign(payload, SWAP_32(ID_OPUS)); assign(payload, SWAP_32(ID_OPUS));
assign(payload + 4, SWAP_32(sampleFormat_.rate)); assign(payload + 4, SWAP_32(sampleFormat_.rate()));
assign(payload + 8, SWAP_16(sampleFormat_.bits)); assign(payload + 8, SWAP_16(sampleFormat_.bits()));
assign(payload + 10, SWAP_16(sampleFormat_.channels)); assign(payload + 10, SWAP_16(sampleFormat_.channels()));
remainder_ = std::make_unique<msg::PcmChunk>(sampleFormat_, 10); remainder_ = std::make_unique<msg::PcmChunk>(sampleFormat_, 10);
remainder_max_size_ = remainder_->payloadSize; remainder_max_size_ = remainder_->payloadSize;
@ -192,7 +192,7 @@ void OpusEncoder::encode(const msg::PcmChunk* chunk)
std::vector<size_t> chunk_durations{60, 40, 20, 10}; std::vector<size_t> chunk_durations{60, 40, 20, 10};
for (const auto duration : chunk_durations) for (const auto duration : chunk_durations)
{ {
auto ms2bytes = [this](size_t ms) { return (ms * sampleFormat_.msRate() * sampleFormat_.frameSize); }; auto ms2bytes = [this](size_t ms) { return (ms * sampleFormat_.msRate() * sampleFormat_.frameSize()); };
uint32_t bytes = ms2bytes(duration); uint32_t bytes = ms2bytes(duration);
while (chunk->payloadSize - offset >= bytes) while (chunk->payloadSize - offset >= bytes)
{ {
@ -217,7 +217,7 @@ void OpusEncoder::encode(const SampleFormat& format, const char* data, size_t si
{ {
// void* buffer; // void* buffer;
// LOG(INFO) << "frames: " << chunk->readFrames(buffer, std::chrono::milliseconds(10)) << "\n"; // LOG(INFO) << "frames: " << chunk->readFrames(buffer, std::chrono::milliseconds(10)) << "\n";
int samples_per_channel = size / format.frameSize; int samples_per_channel = size / format.frameSize();
if (encoded_.size() < size) if (encoded_.size() < size)
encoded_.resize(size); encoded_.resize(size);
@ -231,7 +231,7 @@ void OpusEncoder::encode(const SampleFormat& format, const char* data, size_t si
opusChunk->payloadSize = len; opusChunk->payloadSize = len;
opusChunk->payload = (char*)realloc(opusChunk->payload, opusChunk->payloadSize); opusChunk->payload = (char*)realloc(opusChunk->payload, opusChunk->payloadSize);
memcpy(opusChunk->payload, encoded_.data(), len); memcpy(opusChunk->payload, encoded_.data(), len);
listener_->onChunkEncoded(this, opusChunk, (double)samples_per_channel / ((double)sampleFormat_.rate / 1000.)); listener_->onChunkEncoded(this, opusChunk, (double)samples_per_channel / sampleFormat_.msRate());
} }
else else
{ {

View file

@ -65,11 +65,11 @@ void PcmEncoder::initEncoder()
assign(payload + 12, SWAP_32(ID_FMT)); assign(payload + 12, SWAP_32(ID_FMT));
assign(payload + 16, SWAP_32(16)); assign(payload + 16, SWAP_32(16));
assign(payload + 20, SWAP_16(1)); assign(payload + 20, SWAP_16(1));
assign(payload + 22, SWAP_16(sampleFormat_.channels)); assign(payload + 22, SWAP_16(sampleFormat_.channels()));
assign(payload + 24, SWAP_32(sampleFormat_.rate)); assign(payload + 24, SWAP_32(sampleFormat_.rate()));
assign(payload + 28, SWAP_32(sampleFormat_.rate * sampleFormat_.bits * sampleFormat_.channels / 8)); assign(payload + 28, SWAP_32(sampleFormat_.rate() * sampleFormat_.bits() * sampleFormat_.channels() / 8));
assign(payload + 32, SWAP_16(sampleFormat_.channels * ((sampleFormat_.bits + 7) / 8))); assign(payload + 32, SWAP_16(sampleFormat_.channels() * ((sampleFormat_.bits() + 7) / 8)));
assign(payload + 34, SWAP_16(sampleFormat_.bits)); assign(payload + 34, SWAP_16(sampleFormat_.bits()));
assign(payload + 36, SWAP_32(ID_DATA)); assign(payload + 36, SWAP_32(ID_DATA));
assign(payload + 40, SWAP_32(0)); assign(payload + 40, SWAP_32(0));
} }

View file

@ -52,7 +52,7 @@ void PosixStream::connect()
return; return;
idle_bytes_ = 0; idle_bytes_ = 0;
max_idle_bytes_ = sampleFormat_.rate * sampleFormat_.frameSize * dryout_ms_ / 1000; max_idle_bytes_ = sampleFormat_.rate() * sampleFormat_.frameSize() * dryout_ms_ / 1000;
try try
{ {
@ -89,7 +89,7 @@ void PosixStream::do_read()
{ {
// nothing to read for a longer time now, set the chunk to silent // nothing to read for a longer time now, set the chunk to silent
LOG(DEBUG, LOG_TAG) << "count < 0: " << errno LOG(DEBUG, LOG_TAG) << "count < 0: " << errno
<< " && idleBytes < maxIdleBytes, ms: " << 1000 * chunk_->payloadSize / (sampleFormat_.rate * sampleFormat_.frameSize) << " && idleBytes < maxIdleBytes, ms: " << 1000 * chunk_->payloadSize / (sampleFormat_.rate() * sampleFormat_.frameSize())
<< "\n"; << "\n";
memset(chunk_->payload + len, 0, toRead - len); memset(chunk_->payload + len, 0, toRead - len);
idle_bytes_ += toRead - len; idle_bytes_ += toRead - len;