diff --git a/client/clientConnection.h b/client/clientConnection.h index 8de4dfb2..fe0cd155 100644 --- a/client/clientConnection.h +++ b/client/clientConnection.h @@ -37,6 +37,7 @@ using boost::asio::ip::tcp; class ClientConnection; +/// Used to synchronize server requests (wait for server response) struct PendingRequest { PendingRequest(uint16_t reqId) : id(reqId), response(NULL) {}; @@ -47,6 +48,7 @@ struct PendingRequest }; +/// Interface: callback for a received message and error reporting class MessageReceiver { public: @@ -55,16 +57,26 @@ public: }; +/// Endpoint of the server connection +/** + * Server connection endpoint. + * Messages are sent to the server with the "send" method (async). + * Messages are sent sync to server with the sendReq method. + */ class ClientConnection { public: + /// ctor. Received message from the server are passed to MessageReceiver ClientConnection(MessageReceiver* receiver, const std::string& ip, size_t port); virtual ~ClientConnection(); virtual void start(); virtual void stop(); virtual bool send(const msg::BaseMessage* message) const; + + /// Send request to the server and wait for answer virtual std::shared_ptr sendRequest(const msg::BaseMessage* message, const chronos::msec& timeout = chronos::msec(1000)); + /// Send request to the server and wait for answer of type T template std::shared_ptr sendReq(const msg::BaseMessage* message, const chronos::msec& timeout = chronos::msec(1000)) { diff --git a/client/controller.cpp b/client/controller.cpp index 41878b1f..7c07abaa 100644 --- a/client/controller.cpp +++ b/client/controller.cpp @@ -55,11 +55,12 @@ void Controller::onMessageReceived(ClientConnection* connection, const msg::Base { msg::PcmChunk* pcmChunk = new msg::PcmChunk(*sampleFormat_, 0); pcmChunk->deserialize(baseMessage, buffer); -//logD << "chunk: " << pcmChunk->payloadSize; + //logD << "chunk: " << pcmChunk->payloadSize; if (decoder_->decode(pcmChunk)) { +//TODO: do decoding in thread? stream_->addChunk(pcmChunk); -//logD << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec << ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n"; + //logD << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec << ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n"; } else delete pcmChunk; diff --git a/client/controller.h b/client/controller.h index 064fb65c..730e2b6d 100644 --- a/client/controller.h +++ b/client/controller.h @@ -28,13 +28,25 @@ #include "pcmDevice.h" +/// Forwards PCM data to the audio player +/** + * Sets up a connection to the server (using ClientConnection) + * Sets up the audio decoder and player. Decodes audio feeds PCM to the audio stream buffer + * Does timesync with the server + */ class Controller : public MessageReceiver { public: Controller(); void start(const PcmDevice& pcmDevice, const std::string& ip, size_t port, size_t latency); void stop(); + + /// Implementation of MessageReceiver. + /// ClientConnection passes messages from the server through these callbacks virtual void onMessageReceived(ClientConnection* connection, const msg::BaseMessage& baseMessage, char* buffer); + + /// Implementation of MessageReceiver. + /// Used for async exception reporting virtual void onException(ClientConnection* connection, const std::exception& exception); private: diff --git a/client/stream.cpp b/client/stream.cpp index 061b3750..11b3e54b 100644 --- a/client/stream.cpp +++ b/client/stream.cpp @@ -27,13 +27,12 @@ using namespace std; namespace cs = chronos; -Stream::Stream(const msg::SampleFormat& sampleFormat) : format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0) +Stream::Stream(const msg::SampleFormat& sampleFormat) : format_(sampleFormat), sleep_(0), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0), bufferMs_(cs::msec(500)) { buffer_.setSize(500); shortBuffer_.setSize(100); miniBuffer_.setSize(20); // cardBuffer_.setSize(50); - bufferMs_ = cs::msec(500); /* 48000 x @@ -278,7 +277,7 @@ bool Stream::getPlayerChunk(void* outputBuffer, const cs::usec& outputBufferDacT // framesCorrection = number of frames to be read more or less to get in-sync long framesCorrection = correction.count()*format_.usRate(); - + // sample rate correction if ((correctAfterXFrames_ != 0) && (playedFrames_ >= (unsigned long)abs(correctAfterXFrames_))) { diff --git a/client/stream.h b/client/stream.h index 4c1f05b6..a9b73df8 100644 --- a/client/stream.h +++ b/client/stream.h @@ -34,14 +34,27 @@ #include "common/queue.h" +/// Time synchronized audio stream +/** + * Queue with PCM data. + * Returns "online" server-time-synchronized PCM data + */ class Stream { public: Stream(const msg::SampleFormat& format); + + /// Adds PCM data to the queue void addChunk(msg::PcmChunk* chunk); void clearChunks(); + + /// Get PCM data, which will be played out in "outputBufferDacTime" time + /// frame = (num_channels) * (1 sample in bytes) = (2 channels) * (2 bytes (16 bits) per sample) = 4 bytes (32 bits) bool getPlayerChunk(void* outputBuffer, const chronos::usec& outputBufferDacTime, unsigned long framesPerBuffer); + + /// "Server buffer": playout latency, e.g. 1000ms void setBufferLen(size_t bufferLenMs); + const msg::SampleFormat& getFormat() const { return format_; @@ -72,9 +85,9 @@ private: int median_; int shortMedian_; time_t lastUpdate_; - chronos::msec bufferMs_; unsigned long playedFrames_; long correctAfterXFrames_; + chronos::msec bufferMs_; }; diff --git a/client/timeProvider.h b/client/timeProvider.h index 679d8629..1a633f73 100644 --- a/client/timeProvider.h +++ b/client/timeProvider.h @@ -26,6 +26,12 @@ #include "common/timeDefs.h" +/// Provides local and server time +/** + * Stores time difference to the server + * Returns server's local system time. + * Clients are using the server time to play audio in sync, independent of the client's system time + */ class TimeProvider { public: @@ -49,7 +55,7 @@ public: */ template - static T sinceEpoche(const chronos::time_point_hrc& point) + static T sinceEpoche(const chronos::time_point_hrc& point) { return std::chrono::duration_cast(point.time_since_epoch()); } @@ -70,7 +76,7 @@ public: } private: - TimeProvider(); + TimeProvider(); TimeProvider(TimeProvider const&); // Don't Implement void operator=(TimeProvider const&); // Don't implement