diff --git a/chunk.h b/chunk.h index 3d8cb0b8..bea8374e 100644 --- a/chunk.h +++ b/chunk.h @@ -1,19 +1,22 @@ #ifndef CHUNK_H #define CHUNK_H -#define MS (40) -//44100 / 20 = 2205 #define SAMPLE_RATE (44100) -#define SIZE (SAMPLE_RATE*4*MS/1000) -int bufferMs; -#define FRAMES_PER_BUFFER (SIZE/4) +#define SAMPLE_BIT (16) +#define CHANNELS (2) +#define CHUNK_MS (40) +//44100 / 20 = 2205 +#define CHUNK_SIZE (SAMPLE_RATE*CHANNELS*SAMPLE_BIT/8*CHUNK_MS/1000) +#define FRAMES_PER_BUFFER (CHUNK_SIZE/4) + +int bufferMs; struct Chunk { int32_t tv_sec; int32_t tv_usec; - char payload[SIZE]; + char payload[CHUNK_SIZE]; }; #endif diff --git a/client.cpp b/client.cpp index b6515df5..0784e3ed 100644 --- a/client.cpp +++ b/client.cpp @@ -19,60 +19,16 @@ #include #include "chunk.h" #include "doubleBuffer.h" +#include "timeUtils.h" -DoubleBuffer buffer(30000 / MS); +DoubleBuffer buffer(30000 / CHUNK_MS); std::deque chunks; std::deque timeDiffs; std::mutex mtx; std::mutex mutex; std::condition_variable cv; -std::string timeToStr(const timeval& timestamp) -{ - char tmbuf[64], buf[64]; - struct tm *nowtm; - time_t nowtime; - nowtime = timestamp.tv_sec; - nowtm = localtime(&nowtime); - strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm); - snprintf(buf, sizeof buf, "%s.%06d", tmbuf, (int)timestamp.tv_usec); - return buf; -} - - -std::string chunkTime(const Chunk& chunk) -{ - timeval ts; - ts.tv_sec = chunk.tv_sec; - ts.tv_usec = chunk.tv_usec; - return timeToStr(ts); -} - - -int diff_ms(const timeval& t1, const timeval& t2) -{ - return (((t1.tv_sec - t2.tv_sec) * 1000000) + - (t1.tv_usec - t2.tv_usec))/1000; -} - - -int getAge(const Chunk& chunk) -{ - timeval now; - gettimeofday(&now, NULL); - timeval ts; - ts.tv_sec = chunk.tv_sec; - ts.tv_usec = chunk.tv_usec; - return diff_ms(now, ts); -} - -long getTickCount() -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return now.tv_sec*1000 + now.tv_nsec / 1000000; -} void player() { @@ -109,12 +65,12 @@ void player() { long now = getTickCount(); // std::cerr << "Before: " << now << "\n"; - for (size_t n=0; npayload[n];// << std::flush; std::cout << std::flush; long after = getTickCount(); // std::cerr << "After: " << after << " (" << after - now << ")\n"; - if (after - now > MS / 2) + if (after - now > CHUNK_MS / 2) usleep(((after - now) / 2) * 1000); // int age = getAge(*chunk); @@ -154,6 +110,12 @@ void player() } +void sleepMs(int ms) +{ + if (ms > 0) + usleep(ms * 1000); +} + /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything @@ -189,37 +151,46 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, int median = buffer.median(); std::cerr << "age: " << getAge(*chunk) << "\t" << age << "\t" << median << "\t" << buffer.size() << "\t" << timeInfo->outputBufferDacTime*1000 << "\n"; - if (/*!buffer.full() &&*/ (age > bufferMs + std::max(100, 2*MS))) + int maxDiff = 10; + if (/*!buffer.full() &&*/ (age > bufferMs + std::max(100, 2*CHUNK_MS))) { chunks->pop_front(); delete chunk; std::cerr << "packe too old, dropping\n"; usleep(100); } - else if (/*!buffer.full() &&*/ (age < bufferMs - std::max(100, 2*MS))) + else if (/*!buffer.full() &&*/ (age < bufferMs - std::max(100, 2*CHUNK_MS))) { chunk = new Chunk(); - memset(&(chunk->payload[0]), 0, SIZE); + memset(&(chunk->payload[0]), 0, CHUNK_SIZE); std::cerr << "age < bufferMs (" << age << " < " << bufferMs << "), playing silence\n"; usleep(10 * 1000); break; } - else if (buffer.full() && (median > bufferMs + MS)) + else if (buffer.full() && (median > bufferMs + maxDiff)) { - std::cerr << "median > bufferMs + MS (" << median << " > " << bufferMs + MS << "), dropping chunk\n"; + std::cerr << "median > bufferMs + CHUNK_MS (" << median << " > " << bufferMs + maxDiff << "), dropping chunk\n"; buffer.clear(); chunks->pop_front(); - usleep((median - (bufferMs + MS)) * 1000); delete chunk; + sleepMs(median - bufferMs); } - else if (buffer.full() && (median + MS < bufferMs)) + else if (buffer.full() && (median + maxDiff < bufferMs)) { - std::cerr << "median + MS < bufferMs (" << median + MS << " < " << bufferMs << "), playing silence\n"; + std::cerr << "median + CHUNK_MS < bufferMs (" << median + maxDiff << " < " << bufferMs << "), playing silence\n"; buffer.clear(); - chunk = new Chunk(); - memset(&(chunk->payload[0]), 0, SIZE); - usleep((bufferMs - (median + MS)) * 1000); - break; + if (bufferMs - median > CHUNK_MS) + { + chunk = new Chunk(); + memset(&(chunk->payload[0]), 0, CHUNK_SIZE); + sleepMs(bufferMs - median - CHUNK_MS + 10); + break; + } + else + { + sleepMs(bufferMs - median + 10); + } +// delete chunk; } else { diff --git a/server.cpp b/server.cpp index c37ed55f..546a1040 100644 --- a/server.cpp +++ b/server.cpp @@ -15,24 +15,12 @@ #include #include #include "chunk.h" +#include "timeUtils.h" + using namespace std; -void addMs(timeval& tv, int ms) -{ - tv.tv_usec += ms*1000; - tv.tv_sec += (tv.tv_usec / 1000000); - tv.tv_usec %= 1000000; -} - - -int diff_ms(const timeval& t1, const timeval& t2) -{ - return (((t1.tv_sec - t2.tv_sec) * 1000000) + - (t1.tv_usec - t2.tv_usec))/1000; -} - int main () { // Prepare our context and publisher @@ -54,7 +42,7 @@ int main () { { // read(fd, &msg[0], size); chunk.payload[idx++] = c; - if (idx == SIZE) + if (idx == CHUNK_SIZE) { timeval now; gettimeofday(&now, NULL); @@ -74,7 +62,7 @@ int main () { // snprintf ((char *) message.data(), size, "%05d %d", zipcode, c); // message.data()[0] = c; publisher.send(message); - addMs(ts, MS); + addMs(ts, CHUNK_MS); idx = 0; // msg[0] = '0'; } diff --git a/timeUtils.h b/timeUtils.h new file mode 100644 index 00000000..94fa03f7 --- /dev/null +++ b/timeUtils.h @@ -0,0 +1,65 @@ +#ifndef TIME_UTILS_H +#define TIME_UTILS_H + +#include "chunk.h" + +std::string timeToStr(const timeval& timestamp) +{ + char tmbuf[64], buf[64]; + struct tm *nowtm; + time_t nowtime; + nowtime = timestamp.tv_sec; + nowtm = localtime(&nowtime); + strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm); + snprintf(buf, sizeof buf, "%s.%06d", tmbuf, (int)timestamp.tv_usec); + return buf; +} + + +std::string chunkTime(const Chunk& chunk) +{ + timeval ts; + ts.tv_sec = chunk.tv_sec; + ts.tv_usec = chunk.tv_usec; + return timeToStr(ts); +} + + +int diff_ms(const timeval& t1, const timeval& t2) +{ + return (((t1.tv_sec - t2.tv_sec) * 1000000) + + (t1.tv_usec - t2.tv_usec))/1000; +} + + +int getAge(const Chunk& chunk) +{ + timeval now; + gettimeofday(&now, NULL); + timeval ts; + ts.tv_sec = chunk.tv_sec; + ts.tv_usec = chunk.tv_usec; + return diff_ms(now, ts); +} + + +long getTickCount() +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_sec*1000 + now.tv_nsec / 1000000; +} + + +void addMs(timeval& tv, int ms) +{ + tv.tv_usec += ms*1000; + tv.tv_sec += (tv.tv_usec / 1000000); + tv.tv_usec %= 1000000; +} + + + +#endif + +