pcmDevice and chronos in stream

git-svn-id: svn://elaine/murooma/trunk@298 d8a302eb-03bc-478d-80e4-98257eca68ef
This commit is contained in:
(no author) 2014-09-27 12:13:47 +00:00
parent fe79a78efe
commit d0c07e3b67
13 changed files with 239 additions and 118 deletions

View file

@ -2,13 +2,12 @@
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <iostream> #include <iostream>
#define PCM_DEVICE "default"
#define BUFFER_TIME 100000 #define BUFFER_TIME 100000
using namespace std; using namespace std;
Player::Player(Stream* stream) : active_(false), stream_(stream) Player::Player(const PcmDevice& pcmDevice, Stream* stream) : active_(false), stream_(stream), pcmDevice_(pcmDevice)
{ {
} }
@ -25,8 +24,8 @@ void Player::start()
/* Open the PCM device in playback mode */ /* Open the PCM device in playback mode */
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) if ((pcm = snd_pcm_open(&pcm_handle, pcmDevice_.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
cout << "ERROR: Can't open " << PCM_DEVICE << " PCM device. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't open " << pcmDevice_.name << " PCM device. " << snd_strerror(pcm) << "\n";
/* struct snd_pcm_playback_info_t pinfo; /* struct snd_pcm_playback_info_t pinfo;
if ( (pcm = snd_pcm_playback_info( pcm_handle, &pinfo )) < 0 ) if ( (pcm = snd_pcm_playback_info( pcm_handle, &pinfo )) < 0 )
@ -149,3 +148,55 @@ void Player::worker()
} }
vector<PcmDevice> Player::pcm_list(void)
{
void **hints, **n;
char *name, *descr, *io;
vector<PcmDevice> result;
PcmDevice pcmDevice;
if (snd_device_name_hint(-1, "pcm", &hints) < 0)
return result;
n = hints;
size_t idx(0);
while (*n != NULL) {
name = snd_device_name_get_hint(*n, "NAME");
descr = snd_device_name_get_hint(*n, "DESC");
io = snd_device_name_get_hint(*n, "IOID");
if (io != NULL && strcmp(io, "Output") != 0)
goto __end;
pcmDevice.name = name;
pcmDevice.description = descr;
pcmDevice.idx = idx++;
result.push_back(pcmDevice);
// printf("%s\n", name);
//cout << "Name: " << name << "\n";
//cout << "Desc: " << descr << "\n";
/*
if ((descr1 = descr) != NULL) {
printf(" ");
while (*descr1) {
if (*descr1 == '\n')
printf("\n ");
else
putchar(*descr1);
descr1++;
}
putchar('\n');
}
*/
__end:
if (name != NULL)
free(name);
if (descr != NULL)
free(descr);
if (io != NULL)
free(io);
n++;
}
snd_device_name_free_hint(hints);
return result;
}

View file

@ -4,16 +4,19 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <vector>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include "stream.h" #include "stream.h"
#include "pcmDevice.h"
class Player class Player
{ {
public: public:
Player(Stream* stream); Player(const PcmDevice& pcmDevice, Stream* stream);
void start(); void start();
void stop(); void stop();
static std::vector<PcmDevice> pcm_list(void);
private: private:
void worker(); void worker();
@ -23,6 +26,7 @@ private:
std::atomic<bool> active_; std::atomic<bool> active_;
Stream* stream_; Stream* stream_;
std::thread* playerThread; std::thread* playerThread;
PcmDevice pcmDevice_;
}; };

View file

@ -47,9 +47,10 @@ void Controller::onMessageReceived(ClientConnection* connection, const BaseMessa
} }
void Controller::start(const std::string& _ip, size_t _port) void Controller::start(const PcmDevice& pcmDevice, const std::string& _ip, size_t _port)
{ {
ip = _ip; ip = _ip;
pcmDevice_ = pcmDevice;
clientConnection = new ClientConnection(this, ip, _port); clientConnection = new ClientConnection(this, ip, _port);
controllerThread = new thread(&Controller::worker, this); controllerThread = new thread(&Controller::worker, this);
} }
@ -92,25 +93,22 @@ void Controller::worker()
decoder->setHeader(headerChunk.get()); decoder->setHeader(headerChunk.get());
RequestMsg timeReq("time"); RequestMsg timeReq("time");
for (size_t n=0; n<30; ++n) for (size_t n=0; n<50; ++n)
{ {
shared_ptr<TimeMsg> reply = clientConnection->sendReq<TimeMsg>(&timeReq, 2000); shared_ptr<TimeMsg> reply = clientConnection->sendReq<TimeMsg>(&timeReq, 2000);
if (reply) if (reply)
{ {
double latency = (reply->received.sec - reply->sent.sec) + (reply->received.usec - reply->sent.usec) / 1000000.; double latency = (reply->received.sec - reply->sent.sec) + (reply->received.usec - reply->sent.usec) / 1000000.;
TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2); TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2);
/*cout << TimeProvider::sinceEpoche<chronos::usec>(chronos::hrc::now()).count() << "\n"; usleep(1000);
cout << TimeProvider::sinceEpoche<chronos::msec>(TimeProvider::now()).count() << "\n";
cout << TimeProvider::sinceEpoche<chronos::msec>(TimeProvider::serverNow()).count() << "\n";
cout << "Received: " << TimeProvider::sinceEpoche<chronos::msec>(TimeProvider::toTimePoint(reply->received)).count() << "\n\n";
*/ usleep(1000);
} }
} }
cout << "diff to server [ms]: " << TimeProvider::getInstance().getDiffToServer<chronos::msec>().count() << "\n";
stream = new Stream(*sampleFormat); stream = new Stream(*sampleFormat);
stream->setBufferLen(serverSettings->bufferMs); stream->setBufferLen(serverSettings->bufferMs);
Player player(stream); Player player(pcmDevice_, stream);
player.start(); player.start();
RequestMsg startStream("startStream"); RequestMsg startStream("startStream");

View file

@ -7,13 +7,14 @@
#include "clientConnection.h" #include "clientConnection.h"
#include "decoder.h" #include "decoder.h"
#include "stream.h" #include "stream.h"
#include "pcmDevice.h"
class Controller : public MessageReceiver class Controller : public MessageReceiver
{ {
public: public:
Controller(); Controller();
void start(const std::string& _ip, size_t _port); void start(const PcmDevice& pcmDevice, const std::string& _ip, size_t _port);
void stop(); void stop();
virtual void onMessageReceived(ClientConnection* connection, const BaseMessage& baseMessage, char* buffer); virtual void onMessageReceived(ClientConnection* connection, const BaseMessage& baseMessage, char* buffer);
virtual void onException(ClientConnection* connection, const std::exception& exception); virtual void onException(ClientConnection* connection, const std::exception& exception);
@ -27,6 +28,7 @@ private:
std::string ip; std::string ip;
std::shared_ptr<SampleFormat> sampleFormat; std::shared_ptr<SampleFormat> sampleFormat;
Decoder* decoder; Decoder* decoder;
PcmDevice pcmDevice_;
}; };

18
client/pcmDevice.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef PCM_DEVICE_H
#define PCM_DEVICE_H
#include <string>
class PcmDevice
{
public:
PcmDevice() : idx(-1){};
int idx;
std::string name;
std::string description;
};
#endif

View file

@ -12,31 +12,57 @@
#include "common/utils.h" #include "common/utils.h"
#include "common/log.h" #include "common/log.h"
#include "controller.h" #include "controller.h"
#include "alsaPlayer.h"
using namespace std; using namespace std;
namespace po = boost::program_options; namespace po = boost::program_options;
PcmDevice getPcmDevice(const std::string& soundcard)
{
vector<PcmDevice> pcmDevices = Player::pcm_list();
int soundcardIdx = -1;
try
{
soundcardIdx = boost::lexical_cast<int>(soundcard);
for (auto dev: pcmDevices)
if (dev.idx == soundcardIdx)
return dev;
}
catch(...)
{
}
for (auto dev: pcmDevices)
if (dev.name.find(soundcard) != string::npos)
return dev;
PcmDevice pcmDevice;
return pcmDevice;
}
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
int deviceIdx; string soundcard;
string ip; string ip;
// int bufferMs; // int bufferMs;
size_t port; size_t port;
bool runAsDaemon; bool runAsDaemon;
bool listPcmDevices;
// string sampleFormat; // string sampleFormat;
po::options_description desc("Allowed options"); po::options_description desc("Allowed options");
desc.add_options() desc.add_options()
("help,h", "produce help message") ("help,h", "produce help message")
("port,p", po::value<size_t>(&port)->default_value(98765), "port where the server listens on") ("port,p", po::value<size_t>(&port)->default_value(98765), "port where the server listens on")
("ip,i", po::value<string>(&ip)->default_value("192.168.0.2"), "server IP") ("ip,i", po::value<string>(&ip)->default_value("192.168.0.2"), "server IP")
("soundcard,s", po::value<int>(&deviceIdx)->default_value(-1), "index of the soundcard") ("soundcard,s", po::value<string>(&soundcard)->default_value("default"), "index or name of the soundcard")
// ("sampleformat,f", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format") // ("sampleformat,f", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format")
// ("buffer,b", po::value<int>(&bufferMs)->default_value(300), "buffer size [ms]") // ("buffer,b", po::value<int>(&bufferMs)->default_value(300), "buffer size [ms]")
("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize") ("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize")
("list,l", po::bool_switch(&listPcmDevices)->default_value(false), "list pcm devices")
; ;
po::variables_map vm; po::variables_map vm;
@ -49,6 +75,26 @@ int main (int argc, char *argv[])
return 1; return 1;
} }
if (listPcmDevices)
{
vector<PcmDevice> pcmDevices = Player::pcm_list();
for (auto dev: pcmDevices)
{
cout << dev.idx << ": " << dev.name << "\n";
cout << dev.description << "\n\n";
}
return 1;
}
PcmDevice pcmDevice = getPcmDevice(soundcard);
if (pcmDevice.idx != -1)
cout << pcmDevice.idx << ": " << pcmDevice.name << "\n";
else
{
cout << "soundcard \"" << soundcard << "\" not found\n";
return 1;
}
std::clog.rdbuf(new Log("snapclient", LOG_DAEMON)); std::clog.rdbuf(new Log("snapclient", LOG_DAEMON));
if (runAsDaemon) if (runAsDaemon)
{ {
@ -56,8 +102,9 @@ int main (int argc, char *argv[])
std::clog << kLogNotice << "daemon started" << std::endl; std::clog << kLogNotice << "daemon started" << std::endl;
} }
Controller controller; Controller controller;
controller.start(ip, port); controller.start(pcmDevice, ip, port);
while(true) while(true)
usleep(10000); usleep(10000);

View file

@ -48,7 +48,7 @@ time_point_hrc Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long fr
{ {
if (!chunk) if (!chunk)
chunk = chunks.pop(); chunk = chunks.pop();
time_point_hrc tp = chunk->timePoint(); time_point_hrc tp = chunk->start();
memset(outputBuffer, 0, framesPerBuffer * format.frameSize); memset(outputBuffer, 0, framesPerBuffer * format.frameSize);
return tp; return tp;
} }
@ -78,7 +78,7 @@ time_point_hrc Stream::seek(long ms)
chunk = chunks.pop(); chunk = chunks.pop();
if (ms <= 0) if (ms <= 0)
return chunk->timePoint(); return chunk->start();
// time_point_ms tp = chunk->timePoint(); // time_point_ms tp = chunk->timePoint();
while (ms > chunk->duration<chronos::msec>().count()) while (ms > chunk->duration<chronos::msec>().count())
@ -87,27 +87,27 @@ time_point_hrc Stream::seek(long ms)
ms -= min(ms, (long)chunk->durationLeft<chronos::msec>().count()); ms -= min(ms, (long)chunk->durationLeft<chronos::msec>().count());
} }
chunk->seek(ms * format.msRate()); chunk->seek(ms * format.msRate());
return chunk->timePoint(); return chunk->start();
} }
time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction) time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, const chronos::usec& correction)
{ {
if (!chunk) if (!chunk)
if (!chunks.try_pop(chunk, chronos::msec(timeout))) if (!chunks.try_pop(chunk, chronos::msec(timeout)))
throw 0; throw 0;
//cout << "duration: " << chunk->duration<chronos::msec>().count() << ", " << chunk->duration<chronos::usec>().count() << ", " << chunk->duration<chronos::nsec>().count() << "\n"; //cout << "duration: " << chunk->duration<chronos::msec>().count() << ", " << chunk->duration<chronos::usec>().count() << ", " << chunk->duration<chronos::nsec>().count() << "\n";
time_point_hrc tp = chunk->timePoint(); time_point_hrc tp = chunk->start();
int read = 0; int read = 0;
int toRead = framesPerBuffer + correction*format.msRate(); int toRead = framesPerBuffer + correction.count()*format.usRate();
char* buffer; char* buffer;
if (correction != 0) if (correction.count() != 0)
{ {
int msBuffer = floor(framesPerBuffer / format.msRate()); // chronos::usec usBuffer = (chronos::usec::rep)(framesPerBuffer / format.usRate());
if (abs(correction) > msBuffer / 2) // if (abs(correction) > usBuffer / 2)
correction = copysign(msBuffer / 2, correction); // correction = copysign(usBuffer / 2, correction);
buffer = (char*)malloc(toRead * format.frameSize); buffer = (char*)malloc(toRead * format.frameSize);
} }
else else
@ -121,10 +121,10 @@ time_point_hrc Stream::getNextPlayerChunk(void* outputBuffer, unsigned long fram
throw 0; throw 0;
} }
if (correction != 0) if (correction.count() != 0)
{ {
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_); float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
std::cout << "correction: " << correction << ", factor: " << factor << "\n"; std::cout << "correction: " << correction.count() << ", factor: " << factor << "\n";
float idx = 0; float idx = 0;
for (size_t n=0; n<framesPerBuffer; ++n) for (size_t n=0; n<framesPerBuffer; ++n)
{ {
@ -156,128 +156,113 @@ void Stream::resetBuffers()
} }
bool Stream::getPlayerChunk(void* outputBuffer, chronos::usec outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout) bool Stream::getPlayerChunk(void* outputBuffer, chronos::usec outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout)
{ {
try try
{ {
//cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n"; //cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n";
int msBuffer = framesPerBuffer / format_.msRate(); chronos::nsec bufferDuration = chronos::nsec(chronos::usec::rep(framesPerBuffer / format_.nsRate()));
//cout << msBuffer << " ms, " << framesPerBuffer << "\t" << format_.rate/1000 << "\n"; // cout << "buffer duration: " << bufferDuration.count() << "\n";
int ticks = 0;
long currentTick = getTickCount(); chronos::usec correction = chronos::usec(0);
if (lastTick == 0) if (sleep.count() != 0)
lastTick = currentTick;
ticks = currentTick - lastTick;
lastTick = currentTick;
/*
pShortBuffer->full() && (abs(shortMedian) > 5): 25
Sleep: 25
Chunk: 25 25 25 25 23 105941
Chunk: 25 25 25 25 55 107210
Chunk: 25 25 25 25 88 104671
pShortBuffer->full() && (abs(shortMedian) > 5): 25
Sleep: 25
Chunk: 25 25 25 25 20 99614
Chunk: 25 25 25 25 53 96802
Chunk: 25 25 25 25 86 117732
*/
int correction = 0;
if (sleep != 0)
{ {
// cout << "Sleep " << sleep.count() << "\n";
resetBuffers(); resetBuffers();
if (sleep < -msBuffer/2) if (sleep < -bufferDuration/2)
{ {
cout << "Sleep " << sleep; usec age = chrono::duration_cast<usec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs + outputBufferDacTime);
msec age = chrono::duration_cast<msec>(TimeProvider::serverNow() - getSilentPlayerChunk(outputBuffer, framesPerBuffer) - bufferMs + outputBufferDacTime); sleep = age;
sleep = age.count();
// sleep = PcmChunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs(); // sleep = PcmChunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs();
std::cerr << " after: " << sleep << ", chunks: " << chunks.size() << "\n"; std::cerr << " after: " << sleep.count() << ", chunks: " << chunks.size() << "\n";
// std::clog << kLogNotice << "sleep: " << sleep << std::endl; // std::clog << kLogNotice << "sleep: " << sleep << std::endl;
// if (sleep > -msBuffer/2) // if (sleep > -msBuffer/2)
// sleep = 0; // sleep = 0;
if (sleep < -msBuffer/2) if (sleep < -bufferDuration/2)
return true; return true;
} }
else if (sleep > msBuffer/2) else if (sleep > bufferDuration/2)
{ {
if (!chunk) if (!chunk)
if (!chunks.try_pop(chunk, chronos::msec(timeout))) if (!chunks.try_pop(chunk, chronos::msec(timeout)))
throw 0; throw 0;
while (sleep > chunk->duration<chronos::msec>().count()) while (sleep > chunk->duration<chronos::msec>())
{ {
cout << "sleep > chunk->getDuration(): " << sleep << " > " << chunk->duration<chronos::msec>().count() << ", chunks: " << chunks.size() << ", out: " << outputBufferDacTime.count() << ", needed: " << msBuffer << "\n"; 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, chronos::msec(timeout))) if (!chunks.try_pop(chunk, chronos::msec(timeout)))
throw 0; throw 0;
msec age = std::chrono::duration_cast<msec>(TimeProvider::serverNow() - chunk->timePoint() - bufferMs + outputBufferDacTime); msec age = std::chrono::duration_cast<msec>(TimeProvider::serverNow() - chunk->start() - bufferMs + outputBufferDacTime);
sleep = age.count(); sleep = age;
usleep(1000); usleep(1000);
} }
// cout << "seek: " << PcmChunk::getAge(seek(sleep)) - bufferMs + outputBufferDacTime << "\n"; // cout << "seek: " << PcmChunk::getAge(seek(sleep)) - bufferMs + outputBufferDacTime << "\n";
sleep = 0; sleep = chronos::usec(0);
} }
else if (sleep < 0) else if (sleep < -chronos::usec(100))
{ {
++sleep; sleep += chronos::usec(100);
correction = -1; correction = -chronos::usec(100);
} }
else if (sleep > 0) else if (sleep > chronos::usec(100))
{ {
--sleep; sleep -= chronos::usec(100);
correction = 1; correction = chronos::usec(100);
}
else
{
cout << "Sleep " << sleep.count() << "\n";
correction = sleep;
sleep = chronos::usec(0);
} }
} }
long age(0); chronos::usec age = std::chrono::duration_cast<usec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, framesPerBuffer, timeout, correction) - bufferMs + outputBufferDacTime);
age = std::chrono::duration_cast<msec>(TimeProvider::serverNow() - getNextPlayerChunk(outputBuffer, framesPerBuffer, timeout, correction) - bufferMs + outputBufferDacTime).count();
if (sleep.count() == 0)
if (sleep == 0)
{ {
if (buffer.full() && (abs(median) > 1)) if (buffer.full() && (chronos::usec(abs(median)) > chronos::msec(1)))
{ {
cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n"; cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n";
sleep = median; sleep = chronos::usec(median);
} }
else if (shortBuffer.full() && (abs(shortMedian) > 5)) else if (shortBuffer.full() && (chronos::usec(abs(shortMedian)) > chronos::msec(5)))
{ {
cout << "pShortBuffer->full() && (abs(shortMedian) > 5): " << shortMedian << "\n"; cout << "pShortBuffer->full() && (abs(shortMedian) > 5): " << shortMedian << "\n";
sleep = shortMedian; sleep = chronos::usec(shortMedian);
} }
else if (miniBuffer.full() && (abs(miniBuffer.median()) > 50)) else if (miniBuffer.full() && (chronos::usec(abs(miniBuffer.median())) > chronos::msec(50)))
{ {
cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer.median() << "\n"; cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer.median() << "\n";
sleep = miniBuffer.mean(); sleep = chronos::usec((chronos::msec::rep)miniBuffer.mean());
} }
else if (abs(age) > 200) else if (chronos::abs(age) > chronos::msec(200))
{ {
cout << "age > 50: " << age << "\n"; cout << "age > 50: " << age.count() << "\n";
sleep = age; sleep = age;
} }
} }
if (sleep != 0) if (sleep.count() != 0)
std::cerr << "Sleep: " << sleep << "\n"; std::cerr << "Sleep: " << sleep.count() << "\n";
updateBuffers(age.count());
// std::cerr << "Chunk: " << age << "\t" << outputBufferDacTime*1000 << "\n"; // std::cerr << "Chunk: " << age << "\t" << outputBufferDacTime*1000 << "\n";
if (ticks > 2)
{
// cout << age << "\n";
updateBuffers(age);
}
time_t now = time(NULL); time_t now = time(NULL);
if (now != lastUpdate) if (now != lastUpdate)
{ {
lastUpdate = now; lastUpdate = now;
median = buffer.median(); median = buffer.median();
shortMedian = shortBuffer.median(); shortMedian = shortBuffer.median();
std::cerr << "Chunk: " << age << "\t" << miniBuffer.median() << "\t" << shortMedian << "\t" << median << "\t" << buffer.size() << "\t" << /*cardBuffer << "\t" <<*/ outputBufferDacTime.count() << "\n"; std::cerr << "Chunk: " << age.count()/100 << "\t" << miniBuffer.median()/100 << "\t" << shortMedian/100 << "\t" << median/100 << "\t" << buffer.size() << "\t" << /*cardBuffer << "\t" <<*/ outputBufferDacTime.count() << "\n";
} }
return true; return true;
} }
catch(int e) catch(int e)
{ {
sleep = 0; sleep = chronos::usec(0);
return false; return false;
} }
} }

View file

@ -27,7 +27,7 @@ public:
const SampleFormat& format; const SampleFormat& format;
private: private:
chronos::time_point_hrc getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction = 0); chronos::time_point_hrc getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, const chronos::usec& correction = chronos::usec(0));
chronos::time_point_hrc getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer); chronos::time_point_hrc getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer);
chronos::time_point_hrc seek(long ms); chronos::time_point_hrc seek(long ms);
// time_point_ms seekTo(const time_point_ms& to); // time_point_ms seekTo(const time_point_ms& to);
@ -37,7 +37,7 @@ private:
SampleFormat format_; SampleFormat format_;
long lastTick; long lastTick;
long sleep; chronos::usec sleep;
Queue<std::shared_ptr<PcmChunk>> chunks; Queue<std::shared_ptr<PcmChunk>> chunks;
DoubleBuffer<long> cardBuffer; DoubleBuffer<long> cardBuffer;

View file

@ -3,7 +3,7 @@
TimeProvider::TimeProvider() : diffToServer(0) TimeProvider::TimeProvider() : diffToServer(0)
{ {
diffBuffer.setSize(120); diffBuffer.setSize(100);
} }
@ -13,22 +13,10 @@ void TimeProvider::setDiffToServer(double ms)
diffToServer = diffBuffer.median(); diffToServer = diffBuffer.median();
} }
/*
long TimeProvider::getDiffToServer()
{
return diffToServer;
}
long TimeProvider::getDiffToServerMs()
{
return diffToServer / 1000;
}
long TimeProvider::getPercentileDiffToServer(size_t percentile) long TimeProvider::getPercentileDiffToServer(size_t percentile)
{ {
return diffBuffer.percentile(percentile); return diffBuffer.percentile(percentile);
} }
*/

View file

@ -18,10 +18,17 @@ public:
} }
void setDiffToServer(double ms); void setDiffToServer(double ms);
long getDiffToServer();
long getPercentileDiffToServer(size_t percentile);
long getDiffToServerMs();
template<typename T>
inline T getDiffToServer() const
{
return std::chrono::duration_cast<T>(chronos::usec(diffToServer));
}
/* chronos::usec::rep getDiffToServer();
chronos::usec::rep getPercentileDiffToServer(size_t percentile);
long getDiffToServerMs();
*/
template<typename T> template<typename T>
static T sinceEpoche(const chronos::time_point_hrc& point) static T sinceEpoche(const chronos::time_point_hrc& point)
@ -41,7 +48,7 @@ public:
inline static chronos::time_point_hrc serverNow() inline static chronos::time_point_hrc serverNow()
{ {
return chronos::hrc::now() + chronos::usec(TimeProvider::getInstance().getDiffToServer()); return chronos::hrc::now() + TimeProvider::getInstance().getDiffToServer<chronos::usec>();
} }
private: private:
@ -49,8 +56,8 @@ private:
TimeProvider(TimeProvider const&); // Don't Implement TimeProvider(TimeProvider const&); // Don't Implement
void operator=(TimeProvider const&); // Don't implement void operator=(TimeProvider const&); // Don't implement
DoubleBuffer<long> diffBuffer; DoubleBuffer<chronos::usec::rep> diffBuffer;
std::atomic<long> diffToServer; std::atomic<chronos::usec::rep> diffToServer;
}; };

View file

@ -5,6 +5,13 @@
namespace chronos namespace chronos
{ {
template <class Rep, class Period>
std::chrono::duration<Rep, Period> abs(std::chrono::duration<Rep, Period> d)
{
Rep x = d.count();
return std::chrono::duration<Rep, Period>(x >= 0 ? x : -x);
}
typedef std::chrono::high_resolution_clock hrc; typedef std::chrono::high_resolution_clock hrc;
typedef std::chrono::time_point<hrc> time_point_hrc; typedef std::chrono::time_point<hrc> time_point_hrc;
typedef std::chrono::seconds sec; typedef std::chrono::seconds sec;

View file

@ -17,8 +17,9 @@ public:
~PcmChunk(); ~PcmChunk();
int readFrames(void* outputBuffer, size_t frameCount); int readFrames(void* outputBuffer, size_t frameCount);
int seek(int frames);
inline chronos::time_point_hrc timePoint() const inline chronos::time_point_hrc start() const
{ {
return chronos::time_point_hrc( return chronos::time_point_hrc(
chronos::sec(timestamp.sec) + chronos::sec(timestamp.sec) +
@ -27,7 +28,10 @@ public:
); );
} }
int seek(int frames); inline chronos::time_point_hrc end() const
{
return start() + durationLeft<chronos::usec>();
}
template<typename T> template<typename T>
inline T duration() const inline T duration() const

View file

@ -22,9 +22,19 @@ public:
uint16_t sampleSize; uint16_t sampleSize;
uint16_t frameSize; uint16_t frameSize;
double msRate() const inline double msRate() const
{ {
return (double)rate/1000.f; return (double)rate/1000.;
}
inline double usRate() const
{
return (double)rate/1000000.;
}
inline double nsRate() const
{
return (double)rate/1000000000.;
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)