configurable PCM format

git-svn-id: svn://elaine/murooma/trunk@194 d8a302eb-03bc-478d-80e4-98257eca68ef
This commit is contained in:
(no author) 2014-08-18 19:13:42 +00:00
parent 5938890297
commit c05af700eb
4 changed files with 125 additions and 65 deletions

View file

@ -3,40 +3,50 @@
#include <iostream> #include <iostream>
Chunk::Chunk(WireChunk* _wireChunk) : idx(0), wireChunk(_wireChunk) Chunk::Chunk(size_t hz, size_t channels, size_t bitPerSample, WireChunk* _wireChunk) : wireChunk(_wireChunk), hz_(hz), channels_(channels), bytesPerSample_(bitPerSample/8), frameSize_(bytesPerSample_*channels_), idx(0)
{ {
} }
Chunk::Chunk(size_t hz, size_t channels, size_t bitPerSample, size_t ms) : hz_(hz), channels_(channels), bytesPerSample_(bitPerSample/8), frameSize_(bytesPerSample_*channels_), idx(0)
{
wireChunk = new WireChunk;
wireChunk->length = hz*channels*bytesPerSample_*ms / 1000;
wireChunk->payload = (char*)malloc(wireChunk->length);
}
Chunk::~Chunk() Chunk::~Chunk()
{ {
free(wireChunk->payload);
delete wireChunk; delete wireChunk;
} }
bool Chunk::isEndOfChunk() bool Chunk::isEndOfChunk() const
{ {
return idx >= WIRE_CHUNK_SIZE; return idx >= (wireChunk->length / frameSize_);
} }
bool Chunk::getNext(int16_t& _result)
double Chunk::getDuration() const
{ {
if (isEndOfChunk()) // std::cout << "len: " << wireChunk->length << ", channels: " << channels_ << ", bytesPerSample: " << bytesPerSample_ << ", hz: " << hz_ << "\n";
return false; return wireChunk->length / (channels_ * bytesPerSample_ * hz_ / 1000.);
_result = wireChunk->payload[idx++];
return true;
} }
int Chunk::read(short* _outputBuffer, int _count)
{
int result = _count;
if (idx + _count > WIRE_CHUNK_SIZE)
result = WIRE_CHUNK_SIZE - idx;
if (_outputBuffer != NULL) int Chunk::read(void* outputBuffer, size_t frameCount)
memcpy(_outputBuffer, &wireChunk->payload[idx], sizeof(int16_t)*result); {
//std::cout << "read: " << frameCount << std::endl;
int result = frameCount;
if (idx + frameCount > wireChunk->length / frameSize_)
result = (wireChunk->length / frameSize_) - idx;
if (outputBuffer != NULL)
memcpy(outputBuffer, wireChunk->payload + frameSize_*idx, frameSize_*result);
idx += result; idx += result;
return result; return result;

View file

@ -2,20 +2,8 @@
#define CHUNK_H #define CHUNK_H
#include <chrono> #include <chrono>
#include <cstdlib>
#define SAMPLE_RATE (48000)
//#define SAMPLE_BIT (16)
#define CHANNELS (2)
#define WIRE_CHUNK_MS (50)
#define WIRE_CHUNK_SIZE ((SAMPLE_RATE*CHANNELS*WIRE_CHUNK_MS)/1000)
#define WIRE_CHUNK_MS_SIZE ((SAMPLE_RATE*CHANNELS)/1000)
#define SAMPLE_SIZE (CHANNELS)
#define PLAYER_CHUNK_MS (20)
#define PLAYER_CHUNK_SIZE ((SAMPLE_RATE*CHANNELS*PLAYER_CHUNK_MS)/1000)
#define PLAYER_CHUNK_MS_SIZE ((SAMPLE_RATE*CHANNELS)/1000)
#define FRAMES_PER_BUFFER ((SAMPLE_RATE*PLAYER_CHUNK_MS)/1000)
typedef std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::milliseconds> time_point_ms; typedef std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::milliseconds> time_point_ms;
@ -25,7 +13,8 @@ struct WireChunk
{ {
int32_t tv_sec; int32_t tv_sec;
int32_t tv_usec; int32_t tv_usec;
int16_t payload[WIRE_CHUNK_SIZE]; uint32_t length;
char* payload;
}; };
@ -33,27 +22,39 @@ struct WireChunk
class Chunk class Chunk
{ {
public: public:
Chunk(WireChunk* _wireChunk); Chunk(size_t hz, size_t channels, size_t bitPerSample, WireChunk* _wireChunk);
Chunk(size_t hz, size_t channels, size_t bitPerSample, size_t ms);
~Chunk(); ~Chunk();
int read(short* _outputBuffer, int _count); /* static WireChunk* make_chunk(size_t size, size_t bytesPerSample)
bool isEndOfChunk(); {
WireChunk* wireChunk = new WireChunk(bytesPerSample*size);
wireChunk->length = bytesPerSample*size;
wireChunk->payload = (char*)malloc(wireChunk->length);
return wireChunk;
}
*/
static size_t getHeaderSize()
{
return sizeof(WireChunk::tv_sec) + sizeof(WireChunk::tv_usec) + sizeof(WireChunk::length);
}
bool getNext(int16_t& _result); int read(void* outputBuffer, size_t frameCount);
bool isEndOfChunk() const;
inline time_point_ms timePoint() inline time_point_ms timePoint() const
{ {
time_point_ms tp; time_point_ms tp;
return tp + std::chrono::seconds(wireChunk->tv_sec) + std::chrono::milliseconds(wireChunk->tv_usec / 1000) + std::chrono::milliseconds(idx / WIRE_CHUNK_MS_SIZE); return tp + std::chrono::seconds(wireChunk->tv_sec) + std::chrono::milliseconds(wireChunk->tv_usec / 1000) + std::chrono::milliseconds(idx / (hz_*channels_/1000));
} }
template<typename T> template<typename T>
inline T getAge() inline T getAge() const
{ {
return getAge<T>(timePoint()); return getAge<T>(timePoint());
} }
inline long getAge() inline long getAge() const
{ {
return getAge<std::chrono::milliseconds>().count(); return getAge<std::chrono::milliseconds>().count();
} }
@ -69,9 +70,17 @@ public:
return std::chrono::duration_cast<T>(std::chrono::high_resolution_clock::now() - time_point); return std::chrono::duration_cast<T>(std::chrono::high_resolution_clock::now() - time_point);
} }
private: double getDuration() const;
int32_t idx;
WireChunk* wireChunk; WireChunk* wireChunk;
size_t hz_;
size_t channels_;
size_t bytesPerSample_;
size_t frameSize_;
private:
int32_t idx;
}; };

View file

@ -3,7 +3,7 @@ CC = /usr/bin/g++
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I.. CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
LDFLAGS = -lrt -lpthread -lportaudio -lboost_system -lboost_program_options LDFLAGS = -lrt -lpthread -lportaudio -lboost_system -lboost_program_options
OBJ = snapServer.o OBJ = snapServer.o ../common/chunk.o
BIN = snapserver BIN = snapserver
all: server all: server

View file

@ -66,13 +66,23 @@ public:
{ {
for (;;) for (;;)
{ {
shared_ptr<WireChunk> chunk(chunks.pop()); shared_ptr<Chunk> chunk(chunks.pop());
size_t written = 0; size_t written = 0;
size_t toWrite = Chunk::getHeaderSize();// + chunk->length;
WireChunk* wireChunk = chunk->wireChunk;
do do
{ {
written += boost::asio::write(*socket_, boost::asio::buffer(chunk.get() + written, sizeof(WireChunk) - written));//, error); written += boost::asio::write(*socket_, boost::asio::buffer(wireChunk + written, toWrite - written));//, error);
} }
while (written < sizeof(WireChunk)); while (written < toWrite);
written = 0;
toWrite = wireChunk->length;
do
{
written += boost::asio::write(*socket_, boost::asio::buffer(wireChunk->payload + written, toWrite - written));//, error);
}
while (written < toWrite);
} }
} }
catch (std::exception& e) catch (std::exception& e)
@ -89,9 +99,9 @@ public:
// readerThread.join(); // readerThread.join();
} }
void send(shared_ptr<WireChunk> chunk) void send(shared_ptr<Chunk> chunk)
{ {
while (chunks.size() * WIRE_CHUNK_MS > 10000) while (chunks.size() * chunk->getDuration() > 10000)
chunks.pop(); chunks.pop();
chunks.push(chunk); chunks.push(chunk);
} }
@ -105,7 +115,7 @@ private:
bool active_; bool active_;
socket_ptr socket_; socket_ptr socket_;
thread* senderThread; thread* senderThread;
Queue<shared_ptr<WireChunk>> chunks; Queue<shared_ptr<Chunk>> chunks;
}; };
@ -130,7 +140,7 @@ public:
} }
} }
void send(shared_ptr<WireChunk> chunk) void send(shared_ptr<Chunk> chunk)
{ {
for (std::set<shared_ptr<Session>>::iterator it = sessions.begin(); it != sessions.end(); ) for (std::set<shared_ptr<Session>>::iterator it = sessions.begin(); it != sessions.end(); )
{ {
@ -165,11 +175,35 @@ private:
}; };
class ServerException : public std::exception
{
public:
ServerException(const std::string& what) : what_(what)
{
}
virtual ~ServerException() throw()
{
}
virtual const char* what() const throw()
{
return what_.c_str();
}
private:
std::string what_;
};
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
try try
{ {
uint16_t sampleRate;
short channels;
uint16_t bps;
size_t port; size_t port;
string fifoName; string fifoName;
bool runAsDaemon; bool runAsDaemon;
@ -178,6 +212,9 @@ int main(int argc, char* argv[])
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 to listen on") ("port,p", po::value<size_t>(&port)->default_value(98765), "port to listen on")
("channels,c", po::value<short>(&channels)->default_value(2), "number of channels")
("samplerate,r", po::value<uint16_t>(&sampleRate)->default_value(48000), "sample rate")
("bps,b", po::value<uint16_t>(&bps)->default_value(16), "bit per sample")
("fifo,f", po::value<string>(&fifoName)->default_value("/tmp/snapfifo"), "name of fifo file") ("fifo,f", po::value<string>(&fifoName)->default_value("/tmp/snapfifo"), "name of fifo file")
("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize") ("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize")
; ;
@ -207,8 +244,11 @@ int main(int argc, char* argv[])
} }
*/ */
if (runAsDaemon) // if (runAsDaemon)
daemonize(); {
// daemonize();
// syslog (LOG_NOTICE, "First daemon started.");
}
openlog ("firstdaemon", LOG_PID, LOG_DAEMON); openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
@ -221,37 +261,38 @@ int main(int argc, char* argv[])
long nextTick = getTickCount(); long nextTick = getTickCount();
mkfifo(fifoName.c_str(), 0777); mkfifo(fifoName.c_str(), 0777);
size_t duration = 50;
while (!g_terminated) while (!g_terminated)
{ {
syslog (LOG_NOTICE, "First daemon started.");
int fd = open(fifoName.c_str(), O_RDONLY); int fd = open(fifoName.c_str(), O_RDONLY);
try try
{ {
shared_ptr<WireChunk> chunk;//(new WireChunk()); shared_ptr<Chunk> chunk;//(new WireChunk());
while (true)//cin.good()) while (true)//cin.good())
{ {
chunk.reset(new WireChunk()); chunk.reset(new Chunk(sampleRate, channels, bps, duration));//2*WIRE_CHUNK_SIZE));
int toRead = sizeof(WireChunk::payload); WireChunk* wireChunk = chunk->wireChunk;
int toRead = wireChunk->length;
// cout << "tr: " << toRead << ", size: " << WIRE_CHUNK_SIZE << "\t"; // cout << "tr: " << toRead << ", size: " << WIRE_CHUNK_SIZE << "\t";
char* payload = (char*)(&chunk->payload[0]); // char* payload = (char*)(&chunk->payload[0]);
int len = 0; int len = 0;
do do
{ {
int count = read(fd, payload + len, toRead - len); int count = read(fd, wireChunk->payload + len, toRead - len);
cout.flush();
if (count <= 0) if (count <= 0)
throw new std::exception(); throw ServerException("count = " + boost::lexical_cast<string>(count));
len += count; len += count;
} }
while (len < toRead); while (len < toRead);
chunk->tv_sec = tvChunk.tv_sec; wireChunk->tv_sec = tvChunk.tv_sec;
chunk->tv_usec = tvChunk.tv_usec; wireChunk->tv_usec = tvChunk.tv_usec;
server->send(chunk); server->send(chunk);
addMs(tvChunk, WIRE_CHUNK_MS); addMs(tvChunk, duration);
nextTick += WIRE_CHUNK_MS; nextTick += duration;
long currentTick = getTickCount(); long currentTick = getTickCount();
if (nextTick > currentTick) if (nextTick > currentTick)
{ {
@ -265,18 +306,18 @@ syslog (LOG_NOTICE, "First daemon started.");
} }
} }
} }
catch(const std::exception&) catch(const std::exception& e)
{ {
cout << "Exception\n"; std::cerr << "Exception: " << e.what() << std::endl;
} }
close(fd); close(fd);
} }
server->stop(); server->stop();
} }
catch (std::exception& e) catch (const std::exception& e)
{ {
std::cerr << "Exception: " << e.what() << "\n"; std::cerr << "Exception: " << e.what() << std::endl;
} }
syslog (LOG_NOTICE, "First daemon terminated."); syslog (LOG_NOTICE, "First daemon terminated.");