samplerate

git-svn-id: svn://elaine/murooma/trunk@307 d8a302eb-03bc-478d-80e4-98257eca68ef
This commit is contained in:
(no author) 2014-10-16 05:40:17 +00:00
parent b715396832
commit 42ef09e726
5 changed files with 103 additions and 42 deletions

View file

@ -121,14 +121,15 @@ void Player::stop()
void Player::worker()
{
unsigned int pcm;
snd_pcm_sframes_t avail;
snd_pcm_sframes_t delay;
snd_pcm_sframes_t framesAvail;
snd_pcm_sframes_t framesDelay;
active_ = true;
while (active_)
{
snd_pcm_avail_delay(pcm_handle, &avail, &delay);
snd_pcm_avail_delay(pcm_handle, &framesAvail, &framesDelay);
if (stream_->getPlayerChunk(buff, chronos::usec((chronos::usec::rep)(1000 * (double)delay / stream_->format.msRate())), frames))
chronos::usec delay((chronos::usec::rep)(1000 * (double)framesDelay / stream_->format.msRate()));
if (stream_->getPlayerChunk(buff, delay, frames))
{
if ((pcm = snd_pcm_writei(pcm_handle, buff, frames)) == -EPIPE)
{

View file

@ -67,6 +67,10 @@ public:
bufferSize = size;
}
const std::deque<T>& getBuffer() const
{
return &buffer;
}
private:
size_t bufferSize;

View file

@ -8,16 +8,35 @@ using namespace std;
using namespace chronos;
Stream::Stream(const SampleFormat& sampleFormat) : format(format_), format_(sampleFormat), sleep(0), median(0), shortMedian(0), lastUpdate(0)
Stream::Stream(const SampleFormat& sampleFormat) : format(format_), format_(sampleFormat), sleep(0), median(0), shortMedian(0), lastUpdate(0), playedFrames(0)
{
buffer.setSize(500);
shortBuffer.setSize(100);
miniBuffer.setSize(20);
// cardBuffer.setSize(50);
bufferMs = msec(500);
playedSamples = 0;
/*
48000 x
------- = -----
47999,2 x - 1
x = 1,000016667 / (1,000016667 - 1)
*/
setRealSampleRate(format.rate);
}
void Stream::setRealSampleRate(double sampleRate)
{
if (sampleRate == format.rate)
correctAfterXFrames = 0;
else
correctAfterXFrames = round((format.rate / sampleRate) / (format.rate / sampleRate - 1.));
// cout << "Correct after X: " << correctAfterXFrames << " (Real rate: " << sampleRate << ", rate: " << format.rate << ")\n";
}
void Stream::setBufferLen(size_t bufferLenMs)
{
@ -91,47 +110,44 @@ time_point_hrc Stream::seek(long ms)
*/
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer, const chronos::usec& correction)
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer)
{
if (!chunk && !chunks.try_pop(chunk, timeout))
throw 0;
//cout << "duration: " << chunk->duration<chronos::msec>().count() << ", " << chunk->duration<chronos::usec>().count() << ", " << chunk->duration<chronos::nsec>().count() << "\n";
time_point_hrc tp = chunk->start();
int read = 0;
int toRead = framesPerBuffer + correction.count()*format.usRate();
char* buffer;
if (correction.count() != 0)
char* buffer = (char*)outputBuffer;
unsigned long read = 0;
while (read < framesPerBuffer)
{
// chronos::usec usBuffer = (chronos::usec::rep)(framesPerBuffer / format.usRate());
// if (abs(correction) > usBuffer / 2)
// correction = copysign(usBuffer / 2, correction);
buffer = (char*)malloc(toRead * format.frameSize);
}
else
buffer = (char*)outputBuffer;
while (read < toRead)
{
read += chunk->readFrames(buffer + read*format.frameSize, toRead - read);
read += chunk->readFrames(buffer + read*format.frameSize, framesPerBuffer - read);
if (chunk->isEndOfChunk() && !chunks.try_pop(chunk, timeout))
throw 0;
}
return tp;
}
if (correction.count() != 0)
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer, long framesCorrection)
{
if (framesCorrection == 0)
return getNextPlayerChunk(outputBuffer, timeout, framesPerBuffer);
long toRead = framesPerBuffer + framesCorrection;
char* buffer = (char*)malloc(toRead * format.frameSize);
time_point_hrc tp = getNextPlayerChunk(buffer, timeout, toRead);
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
if (abs(framesCorrection) > 1)
std::cout << "correction: " << framesCorrection << ", factor: " << factor << "\n";
float idx = 0;
for (size_t n=0; n<framesPerBuffer; ++n)
{
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
std::cout << "correction: " << correction.count() << ", factor: " << factor << "\n";
float idx = 0;
for (size_t n=0; n<framesPerBuffer; ++n)
{
size_t index(floor(idx));// = (int)(ceil(n*factor));
memcpy((char*)outputBuffer + n*format.frameSize, buffer + index*format.frameSize, format.frameSize);
idx += factor;
}
free(buffer);
size_t index(floor(idx));// = (int)(ceil(n*factor));
memcpy((char*)outputBuffer + n*format.frameSize, buffer + index*format.frameSize, format.frameSize);
idx += factor;
}
free(buffer);
return tp;
}
@ -157,12 +173,21 @@ void Stream::resetBuffers()
bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBufferDacTime, unsigned long framesPerBuffer)
{
/*if (playedSamples == 0)
playedSamplesTime = chronos::hrc::now() + outputBufferDacTime;
playedSamples += framesPerBuffer;
chronos::msec since = std::chrono::duration_cast<msec>(chronos::hrc::now() + outputBufferDacTime - playedSamplesTime);
if (since.count() > 0)
cout << (double)playedSamples / (double)since.count() << "\n";
*/
if (outputBufferDacTime > bufferMs)
return false;
if (!chunk && !chunks.try_pop(chunk, outputBufferDacTime))
return false;
playedFrames += framesPerBuffer;
chronos::usec age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - chunk->start() - bufferMs + outputBufferDacTime);
if ((sleep.count() == 0) && (chronos::abs(age) > chronos::msec(200)))
{
@ -196,7 +221,12 @@ bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBuffe
{
cout << "sleep > chunk->getDuration(): " << sleep.count() << " > " << chunk->duration<chronos::msec>().count() << ", chunks: " << chunks.size() << ", out: " << outputBufferDacTime.count() << ", needed: " << bufferDuration.count() << "\n";
if (!chunks.try_pop(chunk, outputBufferDacTime))
{
cout << "no chunks available\n";
chunk = NULL;
sleep = chronos::usec(0);
return false;
}
sleep = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - chunk->start() - bufferMs + outputBufferDacTime);
}
@ -221,15 +251,34 @@ bool Stream::getPlayerChunk(void* outputBuffer, const chronos::usec& outputBuffe
}
}
age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, correction) - bufferMs + outputBufferDacTime);
long framesCorrection = correction.count()*format.usRate();
if ((correctAfterXFrames != 0) && (playedFrames >= (unsigned long)abs(correctAfterXFrames)))
{
framesCorrection += (correctAfterXFrames > 0)?1:-1;
playedFrames -= abs(correctAfterXFrames);
}
age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, outputBufferDacTime, framesPerBuffer, framesCorrection) - bufferMs + outputBufferDacTime);
// setRealSampleRate(format.rate);
if (sleep.count() == 0)
{
if (buffer.full() && (chronos::usec(abs(median)) > chronos::msec(1)))
if (buffer.full())
{
cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n";
sleep = chronos::usec(median);
}
if (chronos::usec(abs(median)) > chronos::msec(1))
{
cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n";
sleep = chronos::usec(shortMedian);
}
/* else if (chronos::usec(median) > chronos::usec(300))
{
setRealSampleRate(format.rate - format.rate / 1000);
}
else if (chronos::usec(median) < -chronos::usec(300))
{
setRealSampleRate(format.rate + format.rate / 1000);
}
*/ }
else if (shortBuffer.full() && (chronos::usec(abs(shortMedian)) > chronos::msec(5)))
{
cout << "pShortBuffer->full() && (abs(shortMedian) > 5): " << shortMedian << "\n";

View file

@ -27,18 +27,23 @@ public:
const SampleFormat& format;
private:
chronos::time_point_hrc getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer, const chronos::usec& correction = chronos::usec(0));
chronos::time_point_hrc getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer);
chronos::time_point_hrc getNextPlayerChunk(void* outputBuffer, const chronos::usec& timeout, unsigned long framesPerBuffer, long framesCorrection);
chronos::time_point_hrc getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer);
chronos::time_point_hrc seek(long ms);
// time_point_ms seekTo(const time_point_ms& to);
void updateBuffers(int age);
void resetBuffers();
void setRealSampleRate(double sampleRate);
SampleFormat format_;
long lastTick;
chronos::usec sleep;
unsigned long playedSamples;
chronos::time_point_hrc playedSamplesTime;
Queue<std::shared_ptr<PcmChunk>> chunks;
// DoubleBuffer<chronos::usec::rep> cardBuffer;
DoubleBuffer<chronos::usec::rep> miniBuffer;
@ -50,6 +55,8 @@ private:
int shortMedian;
time_t lastUpdate;
chronos::msec bufferMs;
unsigned long playedFrames;
long correctAfterXFrames;
};

View file

@ -1,7 +1,7 @@
VERSION = 0.01
CC = /usr/bin/g++
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg -lFLAC
OBJ = snapServer.o controlServer.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o
BIN = snapserver