From d4fcf84fb838d24345b8d546b1ecf31e21ab7e79 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@d8a302eb-03bc-478d-80e4-98257eca68ef> Date: Fri, 22 Aug 2014 20:17:46 +0000 Subject: [PATCH] alsa git-svn-id: svn://elaine/murooma/trunk@204 d8a302eb-03bc-478d-80e4-98257eca68ef --- client/Makefile | 2 +- client/snapClient.cpp | 113 ++++++++++++++++++++++++++++++++++++++++-- client/stream.cpp | 20 ++++---- client/stream.h | 8 +++ 4 files changed, 128 insertions(+), 15 deletions(-) diff --git a/client/Makefile b/client/Makefile index 29d7d00a..65abca46 100644 --- a/client/Makefile +++ b/client/Makefile @@ -1,7 +1,7 @@ VERSION = 0.01 CC = /usr/bin/g++ CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I.. -LDFLAGS = -lrt -lpthread -lportaudio -lboost_system -lboost_program_options +LDFLAGS = -lrt -lpthread -lportaudio -lboost_system -lboost_program_options -lasound OBJ = snapClient.o stream.o ../common/chunk.o ../common/log.o BIN = snapclient diff --git a/client/snapClient.cpp b/client/snapClient.cpp index 5c0effbe..6351e01d 100644 --- a/client/snapClient.cpp +++ b/client/snapClient.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "common/chunk.h" #include "common/utils.h" @@ -34,6 +35,7 @@ short channels; uint16_t bps; Stream* stream; +#define PCM_DEVICE "default" void socketRead(tcp::socket* socket, void* to, size_t bytes) @@ -50,7 +52,7 @@ void socketRead(tcp::socket* socket, void* to, size_t bytes) -void player(const std::string& ip, int port) +void receiver(const std::string& ip, int port) { try { @@ -109,6 +111,106 @@ void player(const std::string& ip, int port) } +void player(Stream* stream) +{ + unsigned int pcm, tmp, dir, rate; + int channels, seconds; + snd_pcm_t *pcm_handle; + snd_pcm_hw_params_t *params; + snd_pcm_uframes_t frames; + char *buff; + int buff_size; + + rate = stream->getSampleRate(); + channels = stream->getChannels(); + + /* Open the PCM device in playback mode */ + if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, + SND_PCM_STREAM_PLAYBACK, 0) < 0) + printf("ERROR: Can't open \"%s\" PCM device. %s\n", + PCM_DEVICE, snd_strerror(pcm)); + + /* Allocate parameters object and fill it with default values*/ + snd_pcm_hw_params_alloca(¶ms); + + snd_pcm_hw_params_any(pcm_handle, params); + + /* Set parameters */ + if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params, + SND_PCM_ACCESS_RW_INTERLEAVED) < 0) + printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); + + if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params, + SND_PCM_FORMAT_S16_LE) < 0) + printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); + + if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0) + printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); + + if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) + printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); + + long unsigned int periodsize = 2*rate / 50; + if (pcm = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, params, &periodsize) < 0) + printf("Unable to set buffer size %li: %s\n", (long int)periodsize, snd_strerror(pcm)); + + /* Write parameters */ + if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0) + printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); + + /* Resume information */ + printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle)); + + printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle))); + + snd_pcm_hw_params_get_channels(params, &tmp); + printf("channels: %i ", tmp); + + if (tmp == 1) + printf("(mono)\n"); + else if (tmp == 2) + printf("(stereo)\n"); + + snd_pcm_hw_params_get_rate(params, &tmp, 0); + printf("rate: %d bps\n", tmp); + + printf("seconds: %d\n", seconds); + + /* Allocate buffer to hold single period */ + snd_pcm_hw_params_get_period_size(params, &frames, 0); + printf("frames: %d\n", frames); + + buff_size = frames * channels * 2 /* 2 -> sample size */; + buff = (char *) malloc(buff_size); + + snd_pcm_hw_params_get_period_time(params, &tmp, NULL); + printf("period time: %d\n", tmp); + + while (true) + { +/* if (pcm = read(0, buff, buff_size) == 0) { + printf("Early end of file.\n"); + return 0; + } +*/ + snd_pcm_sframes_t avail; + snd_pcm_sframes_t delay; + snd_pcm_avail_delay(pcm_handle, &avail, &delay); + + stream->getPlayerChunk(buff, (float)delay / 48000.f, frames); + + if (pcm = snd_pcm_writei(pcm_handle, buff, frames) == -EPIPE) { + printf("XRUN.\n"); + snd_pcm_prepare(pcm_handle); + } else if (pcm < 0) { + printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); + } + } + + snd_pcm_drain(pcm_handle); + snd_pcm_close(pcm_handle); + free(buff); +} /* This routine will be called by the PortAudio engine when audio is needed. @@ -256,11 +358,12 @@ int main (int argc, char *argv[]) stream = new Stream(sampleRate, channels, bps); stream->setBufferLen(bufferMs); - PaError paError; - PaStream* paStream = initAudio(paError, sampleRate, channels, bps); - stream->setLatency(1000*Pa_GetStreamInfo(paStream)->outputLatency); +// PaError paError; +// PaStream* paStream = initAudio(paError, sampleRate, channels, bps); +// stream->setLatency(1000*Pa_GetStreamInfo(paStream)->outputLatency); - std::thread playerThread(player, ip, port); + std::thread receiverThread(receiver, ip, port); + std::thread playerThread(player, stream); std::string cmd; while (true && (argc > 3)) diff --git a/client/stream.cpp b/client/stream.cpp index 9178fa93..f20c3bb0 100644 --- a/client/stream.cpp +++ b/client/stream.cpp @@ -122,9 +122,14 @@ void Stream::resetBuffers() void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer) { + if (outputBufferDacTime > 1) + outputBufferDacTime = 0; + else + outputBufferDacTime *= 1000; + //cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n"; -// int msBuffer = floor(framesPerBuffer / (hz_/1000)); -//cout << msBuffer << " ms, " << framesPerBuffer << "\n"; +int msBuffer = framesPerBuffer / (hz_/1000); +//cout << msBuffer << " ms, " << framesPerBuffer << "\t" << hz_/1000 << "\n"; int ticks = 0; long currentTick = getTickCount(); if (lastTick == 0) @@ -144,7 +149,7 @@ void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsi resetBuffers(); if (sleep < -10) { - sleep = Chunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + latencyMs; + sleep = Chunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + latencyMs + outputBufferDacTime; std::cerr << "Sleep: " << sleep << ", chunks: " << chunks.size() << "\n"; // std::clog << kLogNotice << "sleep: " << sleep << std::endl; // if (sleep > -msBuffer/2) @@ -156,7 +161,7 @@ void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsi // std::clog << kLogNotice << "sleep: " << sleep << std::endl; while (true) { - sleep = Chunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + latencyMs; + sleep = Chunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + latencyMs + outputBufferDacTime; usleep(100); // std::clog << kLogNotice << "age: " << age << std::endl; if (sleep < 0) @@ -179,12 +184,9 @@ void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsi - int age = Chunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer, correction)) - bufferMs + latencyMs;// + outputBufferDacTime*1000; + int age = Chunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer, correction)) - bufferMs + latencyMs + outputBufferDacTime;// + outputBufferDacTime*1000; - if (outputBufferDacTime < 1) - age += outputBufferDacTime*1000; - // if (pCardBuffer->full()) // age += 4*cardBuffer; @@ -226,7 +228,7 @@ void Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsi lastUpdate = now; median = pBuffer->median(); shortMedian = pShortBuffer->median(); - std::cerr << "Chunk: " << age << "\t" << pMiniBuffer->median() << "\t" << shortMedian << "\t" << median << "\t" << pBuffer->size() << "\t" << cardBuffer << "\t" << outputBufferDacTime*1000 << "\n"; + std::cerr << "Chunk: " << age << "\t" << pMiniBuffer->median() << "\t" << shortMedian << "\t" << median << "\t" << pBuffer->size() << "\t" << cardBuffer << "\t" << outputBufferDacTime << "\n"; } } diff --git a/client/stream.h b/client/stream.h index 568e1f6f..f7d20d5f 100644 --- a/client/stream.h +++ b/client/stream.h @@ -22,6 +22,14 @@ public: void getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer); void setBufferLen(size_t bufferLenMs); void setLatency(size_t latency); + size_t getSampleRate() const + { + return hz_; + } + size_t getChannels() const + { + return channels_; + } private: time_point_ms getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, int correction = 0);