diff --git a/client/snapClient.cpp b/client/snapClient.cpp index 8beafd64..cee9fe6f 100644 --- a/client/snapClient.cpp +++ b/client/snapClient.cpp @@ -29,10 +29,27 @@ namespace po = boost::program_options; int deviceIdx; +uint16_t sampleRate; +short channels; +uint16_t bps; Stream* stream; +void socketRead(tcp::socket* socket, void* to, size_t bytes) +{ + size_t toRead = bytes; + size_t len = 0; + do + { + len += socket->read_some(boost::asio::buffer((char*)to + len, toRead)); + toRead = bytes - len; + } + while (toRead > 0); +} + + + void player(const std::string& ip, int port) { try @@ -51,17 +68,25 @@ cout << "connect\n"; s.connect(*iterator); while (true) { - void* wireChunk = (void*)malloc(sizeof(WireChunk)); + WireChunk* wireChunk = new WireChunk(); + socketRead(&s, wireChunk, Chunk::getHeaderSize()); +// cout << "WireChunk length: " << wireChunk->length << ", sec: " << wireChunk->tv_sec << ", usec: " << wireChunk->tv_usec << "\n"; + + wireChunk->payload = (char*)malloc(wireChunk->length); + socketRead(&s, wireChunk->payload, wireChunk->length); + +/* void* wireChunk = (void*)malloc(sizeof(WireChunk)); size_t toRead = sizeof(WireChunk); size_t len = 0; do { len += s.read_some(boost::asio::buffer((char*)wireChunk + len, toRead)); toRead = sizeof(WireChunk) - len; -// cout << "len: " << len << "\ttoRead: " << toRead << "\n"; + cout << "len: " << len << "\ttoRead: " << toRead << "\n"; } while (toRead > 0); - stream->addChunk(new Chunk((WireChunk*)wireChunk)); +*/ + stream->addChunk(new Chunk(sampleRate, channels, bps, wireChunk)); } } catch (std::exception& e) @@ -104,13 +129,11 @@ static int paStreamCallback( const void *inputBuffer, void *outputBuffer, -PaStream* initAudio(PaError& err) +PaStream* initAudio(PaError& err, uint16_t sampleRate, short channels, uint16_t bps) { PaStreamParameters outputParameters; PaStream *paStream = NULL; -// PaError err; - - printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); +// printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); err = Pa_Initialize(); if( err != paNoError ) goto error; @@ -137,8 +160,16 @@ PaStream* initAudio(PaError& err) fprintf(stderr,"Error: No default output device.\n"); goto error; } - outputParameters.channelCount = CHANNELS; /* stereo output */ - outputParameters.sampleFormat = paInt16; /* 32 bit floating point output */ + outputParameters.channelCount = channels; /* stereo output */ + if (bps == 16) + outputParameters.sampleFormat = paInt16; /* 32 bit floating point output */ + else if (bps == 8) + outputParameters.sampleFormat = paUInt8; /* 32 bit floating point output */ + else if (bps == 32) + outputParameters.sampleFormat = paInt32; /* 32 bit floating point output */ + else if (bps == 24) + outputParameters.sampleFormat = paInt24; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; std::cerr << "HighLatency: " << outputParameters.suggestedLatency << "\t LowLatency: " << Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency << "\n"; @@ -146,7 +177,7 @@ PaStream* initAudio(PaError& err) &paStream, NULL, /* no input */ &outputParameters, - SAMPLE_RATE, + sampleRate, paFramesPerBufferUnspecified, //FRAMES_PER_BUFFER, paClipOff, /* we won't output out of range samples so don't bother clipping them */ paStreamCallback, @@ -191,6 +222,9 @@ int main (int argc, char *argv[]) ("port,p", po::value(&port)->default_value(98765), "port where the server listens on") ("ip,i", po::value(&ip)->default_value("192.168.0.2"), "server IP") ("soundcard,s", po::value(&deviceIdx)->default_value(-1), "index of the soundcard") + ("channels,c", po::value(&channels)->default_value(2), "number of channels") + ("samplerate,r", po::value(&sampleRate)->default_value(48000), "sample rate") + ("bps", po::value(&bps)->default_value(16), "bit per sample") ("buffer,b", po::value(&bufferMs)->default_value(300), "buffer size [ms]") ("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize") ; @@ -212,10 +246,10 @@ int main (int argc, char *argv[]) std::clog << kLogNotice << "daemon started" << std::endl; } - stream = new Stream(); + stream = new Stream(sampleRate, channels, bps); stream->setBufferLen(bufferMs); PaError paError; - PaStream* paStream = initAudio(paError); + PaStream* paStream = initAudio(paError, sampleRate, channels, bps); stream->setLatency(1000*Pa_GetStreamInfo(paStream)->outputLatency); std::thread playerThread(player, ip, port); diff --git a/client/stream.cpp b/client/stream.cpp index 9c6ce5d7..e62329d4 100644 --- a/client/stream.cpp +++ b/client/stream.cpp @@ -5,7 +5,7 @@ using namespace std; -Stream::Stream() : sleep(0), median(0), shortMedian(0), lastUpdate(0), latencyMs(0) +Stream::Stream(size_t hz, size_t channels, size_t bps) : hz_(hz), channels_(channels), bytesPerSample_(bps/8), sleep(0), median(0), shortMedian(0), lastUpdate(0), latencyMs(0) { pBuffer = new DoubleBuffer(1000); pShortBuffer = new DoubleBuffer(200); @@ -25,16 +25,17 @@ void Stream::setBufferLen(size_t bufferLenMs) void Stream::addChunk(Chunk* chunk) { - while (chunks.size() * WIRE_CHUNK_MS > 10000) +// cout << "new chunk: " << chunk->getDuration() << "\n"; + while (chunks.size() * chunk->getDuration() > 10000) chunks.pop(); chunks.push(shared_ptr(chunk)); } -void Stream::getSilentPlayerChunk(short* outputBuffer, unsigned long framesPerBuffer) +void Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer) { - memset(outputBuffer, 0, sizeof(short)*framesPerBuffer * CHANNELS); + memset(outputBuffer, 0, framesPerBuffer * channels_ * bytesPerSample_);//CHANNELS); } @@ -44,25 +45,25 @@ void Stream::setLatency(size_t latency) } -time_point_ms Stream::getNextPlayerChunk(short* outputBuffer, unsigned long framesPerBuffer, int correction) +time_point_ms Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, int correction) { if (!chunk) chunk = chunks.pop(); time_point_ms tp = chunk->timePoint(); int read = 0; - int toRead = framesPerBuffer*CHANNELS + correction*PLAYER_CHUNK_MS_SIZE; - short* buffer; + int toRead = framesPerBuffer*channels_ + correction*(hz_*channels_/1000); + char* buffer; if (correction != 0) { - int msBuffer = floor(framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE); + int msBuffer = floor(framesPerBuffer*2 / (hz_*channels_/1000)); if (abs(correction) > msBuffer / 2) correction = copysign(msBuffer / 2, correction); - buffer = (short*)malloc(toRead * sizeof(short)); + buffer = (char*)malloc(toRead * bytesPerSample_); } else - buffer = outputBuffer; + buffer = (char*)outputBuffer; while (read < toRead) { @@ -73,20 +74,72 @@ time_point_ms Stream::getNextPlayerChunk(short* outputBuffer, unsigned long fram if (correction != 0) { - float factor = (float)toRead / (float)(framesPerBuffer*CHANNELS); + float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_); +//float factor = 0.9; +// std::cout << "correction: " << correction << ", factor: " << factor << "\n"; + float idx = 0; + for (size_t n=0; nframeSize_, buffer + index*chunk->frameSize_, chunk->frameSize_); + idx += factor; +// memcpy((char*)outputBuffer + n*bytesPerSample_*channels_, (char*)(chunk->wireChunk->payload) + index*bytesPerSample_*channels_, bytesPerSample_*channels_); + } + free(buffer); +/* float factor = (float)toRead / (float)(framesPerBuffer*channels_); std::cout << "correction: " << correction << ", factor: " << factor << "\n"; for (size_t n=0; nwireChunk->payload) + index*bytesPerSample_*channels_, bytesPerSample_*channels_); +// memcpy((char*)outputBuffer + n*bytesPerSample_*channels_, (char*)(chunk->wireChunk->payload) + index*bytesPerSample_*channels_, bytesPerSample_*channels_); } free(buffer); - } +*/ } return tp; } +/* +time_point_ms Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, int correction) +{ +correction = 0; + if (!chunk) + chunk = chunks.pop(); + + time_point_ms tp = chunk->timePoint(); + int read = 0; + int toRead = framesPerBuffer / 1.5; + char* buffer; +//cout << "Framesize: " << chunk->frameSize_ << "\n"; + buffer = (char*)malloc(toRead * chunk->frameSize_); + + do + { + read += chunk->read(buffer + read, toRead - read); + if (chunk->isEndOfChunk()) + chunk = chunks.pop(); + } + while (read < toRead); + + float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_); +//float factor = 0.9; +// std::cout << "correction: " << correction << ", factor: " << factor << "\n"; + float idx = 0; + for (size_t n=0; nframeSize_, buffer + index*chunk->frameSize_, chunk->frameSize_); + idx += factor; +// memcpy((char*)outputBuffer + n*bytesPerSample_*channels_, (char*)(chunk->wireChunk->payload) + index*bytesPerSample_*channels_, bytesPerSample_*channels_); + } + free(buffer); + + return tp; +} +*/ void Stream::updateBuffers(int age) { @@ -104,10 +157,11 @@ void Stream::resetBuffers() } -void Stream::getPlayerChunk(short* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer) +void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer) { //cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n"; - int msBuffer = floor(framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE); +sleep = 0; + int msBuffer = floor(framesPerBuffer*2 / (hz_*channels_/1000)); int ticks = 0; long currentTick = getTickCount(); @@ -191,7 +245,7 @@ void Stream::getPlayerChunk(short* outputBuffer, double outputBufferDacTime, uns } else if (pMiniBuffer->full() && (abs(pMiniBuffer->median()) > 50)) { - cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << pMiniBuffer->median() << "\n"; +// cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << pMiniBuffer->median() << "\n"; sleep = pMiniBuffer->mean(); } } diff --git a/client/stream.h b/client/stream.h index 47a9596c..56de5eb3 100644 --- a/client/stream.h +++ b/client/stream.h @@ -16,18 +16,22 @@ class Stream { public: - Stream(); + Stream(size_t hz, size_t channels, size_t bps); void addChunk(Chunk* chunk); - void getPlayerChunk(short* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer); + void getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer); void setBufferLen(size_t bufferLenMs); void setLatency(size_t latency); private: - time_point_ms getNextPlayerChunk(short* outputBuffer, unsigned long framesPerBuffer, int correction = 0); - void getSilentPlayerChunk(short* outputBuffer, unsigned long framesPerBuffer); + time_point_ms getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, int correction = 0); + void getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer); void updateBuffers(int age); void resetBuffers(); + size_t hz_; + size_t channels_; + size_t bytesPerSample_; + long lastTick; int sleep;