git-svn-id: svn://elaine/murooma/trunk@272 d8a302eb-03bc-478d-80e4-98257eca68ef
This commit is contained in:
(no author) 2014-09-17 21:58:38 +00:00
parent 16ef1ae634
commit feabfee936
50 changed files with 1996 additions and 1984 deletions

View file

@ -1,92 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_layout_file> <CodeBlocks_layout_file>
<ActiveTarget name="Release" /> <ActiveTarget name="Release" />
<File name="server/controlServer.h" open="1" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/requestMsg.h" open="1" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/message.h" open="1" top="0" tabpos="16" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/pcmChunk.cpp" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/log.cpp" open="1" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/oggEncoder.h" open="1" top="0" tabpos="25" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/sampleFormat.cpp" open="1" top="0" tabpos="17" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/wireChunk.h" open="1" top="0" tabpos="26" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/serverConnection.cpp" open="1" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/socketConnection.h" open="1" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/headerMessage.h" open="1" top="0" tabpos="22" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/timeMsg.h" open="1" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/socketConnection.cpp" open="1" top="0" tabpos="21" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/socketConnection.cpp" open="1" top="0" tabpos="21" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/oggEncoder.cpp" open="1" top="0" tabpos="28" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/sampleFormat.cpp" open="1" top="0" tabpos="17" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="168" />
</Cursor>
</File>
<File name="server/pcmEncoder.cpp" open="1" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/sampleFormat.h" open="1" top="0" tabpos="30" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/log.h" open="1" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/pcmChunk.h" open="1" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
@ -101,24 +21,34 @@
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="common/timeUtils.h" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/headerMessage.h" open="1" top="0" tabpos="22" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/pcmEncoder.h" open="1" top="0" tabpos="23" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/sampleFormat.h" open="1" top="1" tabpos="48" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="common/serverSettings.h" open="1" top="0" tabpos="29" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/pcmChunk.h" open="1" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/controlServer.cpp" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="server/serverConnection.cpp" open="1" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="215" topLine="82" /> <Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/requestMsg.h" open="1" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/wireChunk.h" open="1" top="0" tabpos="26" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="common/queue.h" open="1" top="0" tabpos="14" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/queue.h" open="1" top="0" tabpos="14" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -126,7 +56,12 @@
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="common/utils.h" open="1" top="0" tabpos="30" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/log.cpp" open="1" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/oggEncoder.cpp" open="1" top="0" tabpos="27" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
@ -136,14 +71,54 @@
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/streamServer.cpp" open="1" top="0" tabpos="24" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="server/pcmEncoder.cpp" open="1" top="0" tabpos="11" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/pcmEncoder.h" open="1" top="0" tabpos="23" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/pcmChunk.cpp" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/message.h" open="1" top="0" tabpos="16" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/snapServer.cpp" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="server/snapServer.cpp" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="4569" topLine="114" /> <Cursor1 position="3872" topLine="138" />
</Cursor>
</File>
<File name="server/streamServer.cpp" open="1" top="0" tabpos="24" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/controlServer.h" open="1" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/timeUtils.h" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/socketConnection.h" open="1" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/log.h" open="1" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/serverConnection.h" open="1" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="server/serverConnection.h" open="1" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
@ -151,4 +126,29 @@
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="server/oggEncoder.h" open="1" top="0" tabpos="25" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="server/controlServer.cpp" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="215" topLine="0" />
</Cursor>
</File>
<File name="common/timeMsg.h" open="1" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/utils.h" open="1" top="0" tabpos="29" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/serverSettings.h" open="1" top="0" tabpos="28" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
</CodeBlocks_layout_file> </CodeBlocks_layout_file>

View file

@ -1,26 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_layout_file> <CodeBlocks_layout_file>
<ActiveTarget name="Release" /> <ActiveTarget name="Release" />
<File name="client/player.cpp" open="1" top="0" tabpos="16" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="client/oggDecoder.cpp" open="1" top="0" tabpos="14" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="client/snapClient.cpp" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1639" topLine="49" />
</Cursor>
</File>
<File name="client/clientConnection.h" open="1" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="client/clientConnection.h" open="1" top="0" tabpos="10" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="client/pcmDecoder.cpp" open="1" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="client/doubleBuffer.h" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="client/stream.cpp" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="767" topLine="20" />
</Cursor>
</File>
<File name="common/utils.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="common/utils.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="707" topLine="26" /> <Cursor1 position="707" topLine="26" />
</Cursor> </Cursor>
</File> </File>
<File name="client/stream.h" open="1" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/clientConnection.cpp" open="1" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/timeProvider.cpp" open="1" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/streamClient.h" open="1" top="0" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/controller.cpp" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/timeUtils.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="999" topLine="39" />
</Cursor>
</File>
<File name="client/controller.h" open="1" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/player.h" open="1" top="1" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/timeProvider.h" open="1" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/pcmDecoder.h" open="1" top="0" tabpos="17" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="client/pcmDecoder.h" open="1" top="0" tabpos="17" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
@ -31,74 +86,19 @@
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="client/timeProvider.cpp" open="1" top="0" tabpos="8" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/controller.cpp" open="1" top="0" tabpos="6" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/clientConnection.cpp" open="1" top="0" tabpos="9" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="common/timeUtils.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="999" topLine="39" />
</Cursor>
</File>
<File name="client/timeProvider.h" open="1" top="0" tabpos="15" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/streamClient.h" open="1" top="0" tabpos="5" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/doubleBuffer.h" open="1" top="0" tabpos="3" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/stream.h" open="1" top="0" tabpos="4" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/snapClient.cpp" open="1" top="0" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="1647" topLine="39" />
</Cursor>
</File>
<File name="client/controller.h" open="1" top="0" tabpos="13" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/oggDecoder.cpp" open="1" top="0" tabpos="14" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/stream.cpp" open="1" top="1" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="767" topLine="20" />
</Cursor>
</File>
<File name="client/player.h" open="1" top="0" tabpos="18" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="11" />
</Cursor>
</File>
<File name="client/oggDecoder.h" open="1" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> <File name="client/oggDecoder.h" open="1" top="0" tabpos="12" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor> <Cursor>
<Cursor1 position="0" topLine="0" /> <Cursor1 position="0" topLine="0" />
</Cursor> </Cursor>
</File> </File>
<File name="client/player.cpp" open="1" top="0" tabpos="16" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
<File name="client/pcmDecoder.cpp" open="1" top="0" tabpos="7" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0">
<Cursor>
<Cursor1 position="0" topLine="0" />
</Cursor>
</File>
</CodeBlocks_layout_file> </CodeBlocks_layout_file>

View file

@ -15,49 +15,52 @@ ClientConnection::ClientConnection(MessageReceiver* _receiver, const std::string
void ClientConnection::start() void ClientConnection::start()
{ {
tcp::resolver resolver(io_service); tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), ip, boost::lexical_cast<string>(port)); tcp::resolver::query query(tcp::v4(), ip, boost::lexical_cast<string>(port));
iterator = resolver.resolve(query); iterator = resolver.resolve(query);
SocketConnection::start(); SocketConnection::start();
} }
void ClientConnection::worker() void ClientConnection::worker()
{ {
active_ = true; active_ = true;
while (active_) while (active_)
{ {
connected_ = false; connected_ = false;
try try
{ {
{ {
// std::unique_lock<std::mutex> mlock(mutex_); // std::unique_lock<std::mutex> mlock(mutex_);
cout << "connecting\n"; cout << "connecting\n";
socket.reset(new tcp::socket(io_service)); socket.reset(new tcp::socket(io_service));
struct timeval tv; struct timeval tv;
tv.tv_sec = 5; tv.tv_sec = 5;
tv.tv_usec = 0; tv.tv_usec = 0;
setsockopt(socket->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); cout << "socket: " << socket->native() << "\n";
socket->connect(*iterator); setsockopt(socket->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
connected_ = true; setsockopt(socket->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
cout << "connected\n"; socket->connect(*iterator);
std::clog << kLogNotice << "connected\n";// to " << ip << ":" << port << std::endl; connected_ = true;
} cout << "connected\n";
while(active_) std::clog << kLogNotice << "connected\n";// to " << ip << ":" << port << std::endl;
{ }
cout << "."; while(active_)
getNextMessage(); {
cout << "|"; // cout << ".";
cout.flush(); // cout.flush();
} getNextMessage();
} // cout << "|";
catch (const std::exception& e) // cout.flush();
{ }
connected_ = false; }
cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl; catch (const std::exception& e)
usleep(1000*1000); {
} connected_ = false;
} cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl;
usleep(1000*1000);
}
}
} }

View file

@ -11,15 +11,15 @@ using boost::asio::ip::tcp;
class ClientConnection : public SocketConnection class ClientConnection : public SocketConnection
{ {
public: public:
ClientConnection(MessageReceiver* _receiver, const std::string& _ip, size_t _port); ClientConnection(MessageReceiver* _receiver, const std::string& _ip, size_t _port);
virtual void start(); virtual void start();
protected: protected:
virtual void worker(); virtual void worker();
private: private:
std::string ip; std::string ip;
size_t port; size_t port;
}; };

View file

@ -21,96 +21,96 @@ Controller::Controller() : MessageReceiver(), active_(false), streamClient(NULL)
void Controller::onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer) void Controller::onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer)
{ {
if (baseMessage.type == message_type::payload) if (baseMessage.type == message_type::payload)
{ {
if ((stream != NULL) && (decoder != NULL)) if ((stream != NULL) && (decoder != NULL))
{ {
PcmChunk* pcmChunk = new PcmChunk(*sampleFormat, 0); PcmChunk* pcmChunk = new PcmChunk(*sampleFormat, 0);
pcmChunk->deserialize(baseMessage, buffer); pcmChunk->deserialize(baseMessage, buffer);
//cout << "chunk: " << pcmChunk->payloadSize; //cout << "chunk: " << pcmChunk->payloadSize;
if (decoder->decode(pcmChunk)) if (decoder->decode(pcmChunk))
{ {
stream->addChunk(pcmChunk); stream->addChunk(pcmChunk);
//cout << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec << ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n"; //cout << ", decoded: " << pcmChunk->payloadSize << ", Duration: " << pcmChunk->getDuration() << ", sec: " << pcmChunk->timestamp.sec << ", usec: " << pcmChunk->timestamp.usec/1000 << ", type: " << pcmChunk->type << "\n";
} }
else else
delete pcmChunk; delete pcmChunk;
} }
} }
} }
void Controller::start(const std::string& _ip, size_t _port, int _bufferMs) void Controller::start(const std::string& _ip, size_t _port, int _bufferMs)
{ {
bufferMs = _bufferMs; bufferMs = _bufferMs;
ip = _ip; ip = _ip;
controlConnection = new ClientConnection(this, ip, _port); controlConnection = new ClientConnection(this, ip, _port);
controlConnection->start(); controlConnection->start();
controllerThread = new thread(&Controller::worker, this); controllerThread = new thread(&Controller::worker, this);
} }
void Controller::stop() void Controller::stop()
{ {
active_ = false; active_ = false;
} }
void Controller::worker() void Controller::worker()
{ {
// Decoder* decoder; // Decoder* decoder;
active_ = true; active_ = true;
decoder = NULL; decoder = NULL;
while (active_) while (active_)
{ {
try try
{ {
RequestMsg requestMsg("serverSettings"); RequestMsg requestMsg("serverSettings");
shared_ptr<ServerSettings> serverSettings(NULL); shared_ptr<ServerSettings> serverSettings(NULL);
while (!(serverSettings = controlConnection->sendReq<ServerSettings>(&requestMsg, 1000))); while (!(serverSettings = controlConnection->sendReq<ServerSettings>(&requestMsg, 1000)));
cout << "ServerSettings port: " << serverSettings->port << "\n"; cout << "ServerSettings port: " << serverSettings->port << "\n";
streamClient = new StreamClient(this, ip, serverSettings->port); streamClient = new StreamClient(this, ip, serverSettings->port);
requestMsg.request = "sampleFormat"; requestMsg.request = "sampleFormat";
while (!(sampleFormat = controlConnection->sendReq<SampleFormat>(&requestMsg, 1000))); while (!(sampleFormat = controlConnection->sendReq<SampleFormat>(&requestMsg, 1000)));
cout << "SampleFormat rate: " << sampleFormat->rate << ", bits: " << sampleFormat->bits << ", channels: " << sampleFormat->channels << "\n"; cout << "SampleFormat rate: " << sampleFormat->rate << ", bits: " << sampleFormat->bits << ", channels: " << sampleFormat->channels << "\n";
decoder = new OggDecoder(); decoder = new OggDecoder();
if (decoder != NULL) if (decoder != NULL)
{ {
requestMsg.request = "headerChunk"; requestMsg.request = "headerChunk";
shared_ptr<HeaderMessage> headerChunk(NULL); shared_ptr<HeaderMessage> headerChunk(NULL);
while (!(headerChunk = controlConnection->sendReq<HeaderMessage>(&requestMsg, 1000))); while (!(headerChunk = controlConnection->sendReq<HeaderMessage>(&requestMsg, 1000)));
decoder->setHeader(headerChunk.get()); decoder->setHeader(headerChunk.get());
} }
RequestMsg timeReq("time"); RequestMsg timeReq("time");
for (size_t n=0; n<10; ++n) for (size_t n=0; n<10; ++n)
{ {
shared_ptr<TimeMsg> reply = controlConnection->sendReq<TimeMsg>(&timeReq, 2000); shared_ptr<TimeMsg> reply = controlConnection->sendReq<TimeMsg>(&timeReq, 2000);
if (reply) if (reply)
{ {
double latency = (reply->received.sec - reply->sent.sec) + (reply->received.usec - reply->sent.usec) / 1000000.; double latency = (reply->received.sec - reply->sent.sec) + (reply->received.usec - reply->sent.usec) / 1000000.;
TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2); TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2);
usleep(1000); usleep(1000);
} }
} }
streamClient->start(); streamClient->start();
stream = new Stream(*sampleFormat); stream = new Stream(*sampleFormat);
stream->setBufferLen(bufferMs); stream->setBufferLen(bufferMs);
Player player(stream); Player player(stream);
player.start(); player.start();
try try
{ {
while (active_) while (active_)
{ {
usleep(1000000); usleep(1000000);
shared_ptr<TimeMsg> reply = controlConnection->sendReq<TimeMsg>(&timeReq, 1000); shared_ptr<TimeMsg> reply = controlConnection->sendReq<TimeMsg>(&timeReq, 1000);
if (reply) if (reply)
{ {
@ -119,31 +119,32 @@ void Controller::worker()
TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2); TimeProvider::getInstance().setDiffToServer((reply->latency - latency) * 1000 / 2);
cout << TimeProvider::getInstance().getDiffToServer() << "\n"; cout << TimeProvider::getInstance().getDiffToServer() << "\n";
} }
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
cout << "Stopping player\n"; cout << "Stopping player\n";
player.stop(); player.stop();
cout << "Stopping streamClient\n"; cout << "Stopping streamClient\n";
streamClient->stop(); streamClient->stop();
delete streamClient; delete streamClient;
streamClient = NULL; streamClient = NULL;
delete stream; cout << "Deleting stream\n";
stream = NULL; delete stream;
cout << "done\n"; stream = NULL;
throw e; cout << "done\n";
} throw e;
} }
catch (const std::exception& e) }
{ catch (const std::exception& e)
cout << "Exception in Controller::worker(): " << e.what() << "\n"; {
if (decoder != NULL) cout << "Exception in Controller::worker(): " << e.what() << "\n";
delete decoder; if (decoder != NULL)
decoder = NULL; delete decoder;
usleep(1000000); decoder = NULL;
} usleep(1000000);
} }
}
} }

View file

@ -13,22 +13,22 @@
class Controller : public MessageReceiver class Controller : public MessageReceiver
{ {
public: public:
Controller(); Controller();
void start(const std::string& _ip, size_t _port, int _bufferMs); void start(const std::string& _ip, size_t _port, int _bufferMs);
void stop(); void stop();
virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer); virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer);
private: private:
void worker(); void worker();
std::atomic<bool> active_; std::atomic<bool> active_;
std::thread* controllerThread; std::thread* controllerThread;
StreamClient* streamClient; StreamClient* streamClient;
ClientConnection* controlConnection; ClientConnection* controlConnection;
Stream* stream; Stream* stream;
int bufferMs; int bufferMs;
std::string ip; std::string ip;
std::shared_ptr<SampleFormat> sampleFormat; std::shared_ptr<SampleFormat> sampleFormat;
Decoder* decoder; Decoder* decoder;
}; };

View file

@ -6,10 +6,10 @@
class Decoder class Decoder
{ {
public: public:
Decoder() {}; Decoder() {};
virtual ~Decoder() {}; virtual ~Decoder() {};
virtual bool decode(PcmChunk* chunk) = 0; virtual bool decode(PcmChunk* chunk) = 0;
virtual bool setHeader(HeaderMessage* chunk) = 0; virtual bool setHeader(HeaderMessage* chunk) = 0;
}; };

View file

@ -8,69 +8,69 @@ template <class T>
class DoubleBuffer class DoubleBuffer
{ {
public: public:
DoubleBuffer(size_t size = 10) : bufferSize(size) DoubleBuffer(size_t size = 10) : bufferSize(size)
{ {
} }
inline void add(const T& element) inline void add(const T& element)
{ {
buffer.push_back(element); buffer.push_back(element);
if (buffer.size() > bufferSize) if (buffer.size() > bufferSize)
buffer.pop_front(); buffer.pop_front();
} }
T median() const T median() const
{ {
if (buffer.empty()) if (buffer.empty())
return 0; return 0;
std::deque<T> tmpBuffer(buffer.begin(), buffer.end()); std::deque<T> tmpBuffer(buffer.begin(), buffer.end());
std::sort(tmpBuffer.begin(), tmpBuffer.end()); std::sort(tmpBuffer.begin(), tmpBuffer.end());
return tmpBuffer[tmpBuffer.size() / 2]; return tmpBuffer[tmpBuffer.size() / 2];
} }
double mean() const double mean() const
{ {
if (buffer.empty()) if (buffer.empty())
return 0; return 0;
double mean = 0.; double mean = 0.;
for (size_t n=0; n<buffer.size(); ++n) for (size_t n=0; n<buffer.size(); ++n)
mean += (float)buffer[n] / (float)buffer.size(); mean += (float)buffer[n] / (float)buffer.size();
return mean; return mean;
} }
T percentil(unsigned int percentil) const T percentil(unsigned int percentil) const
{ {
if (buffer.empty()) if (buffer.empty())
return 0; return 0;
std::deque<T> tmpBuffer(buffer.begin(), buffer.end()); std::deque<T> tmpBuffer(buffer.begin(), buffer.end());
std::sort(tmpBuffer.begin(), tmpBuffer.end()); std::sort(tmpBuffer.begin(), tmpBuffer.end());
return tmpBuffer[(size_t)(tmpBuffer.size() * ((float)percentil / (float)100))]; return tmpBuffer[(size_t)(tmpBuffer.size() * ((float)percentil / (float)100))];
} }
inline bool full() const inline bool full() const
{ {
return (buffer.size() == bufferSize); return (buffer.size() == bufferSize);
} }
inline void clear() inline void clear()
{ {
buffer.clear(); buffer.clear();
} }
inline size_t size() const inline size_t size() const
{ {
return buffer.size(); return buffer.size();
} }
void setSize(size_t size) void setSize(size_t size)
{ {
bufferSize = size; bufferSize = size;
} }
private: private:
size_t bufferSize; size_t bufferSize;
std::deque<T> buffer; std::deque<T> buffer;
}; };

View file

@ -10,205 +10,205 @@ using namespace std;
OggDecoder::OggDecoder() : Decoder() OggDecoder::OggDecoder() : Decoder()
{ {
ogg_sync_init(&oy); /* Now we can read pages */ ogg_sync_init(&oy); /* Now we can read pages */
convsize = 4096; convsize = 4096;
convbuffer = (ogg_int16_t*)malloc(convsize * sizeof(ogg_int16_t)); convbuffer = (ogg_int16_t*)malloc(convsize * sizeof(ogg_int16_t));
} }
OggDecoder::~OggDecoder() OggDecoder::~OggDecoder()
{ {
// ogg_sync_init(&oy); /* Now we can read pages */ // ogg_sync_init(&oy); /* Now we can read pages */
delete convbuffer; delete convbuffer;
} }
bool OggDecoder::decode(PcmChunk* chunk) bool OggDecoder::decode(PcmChunk* chunk)
{ {
/* grab some data at the head of the stream. We want the first page /* grab some data at the head of the stream. We want the first page
(which is guaranteed to be small and only contain the Vorbis (which is guaranteed to be small and only contain the Vorbis
stream initial header) We need the first page to get the stream stream initial header) We need the first page to get the stream
serialno. */ serialno. */
bytes = chunk->payloadSize; bytes = chunk->payloadSize;
buffer=ogg_sync_buffer(&oy, bytes); buffer=ogg_sync_buffer(&oy, bytes);
memcpy(buffer, chunk->payload, bytes); memcpy(buffer, chunk->payload, bytes);
ogg_sync_wrote(&oy,bytes); ogg_sync_wrote(&oy,bytes);
chunk->payloadSize = 0; chunk->payloadSize = 0;
convsize=4096;//bytes/vi.channels; convsize=4096;//bytes/vi.channels;
/* The rest is just a straight decode loop until end of stream */ /* The rest is just a straight decode loop until end of stream */
// while(!eos){ // while(!eos){
while(true) while(true)
{ {
int result=ogg_sync_pageout(&oy,&og); int result=ogg_sync_pageout(&oy,&og);
if (result==0) if (result==0)
break; /* need more data */ break; /* need more data */
if(result<0) if(result<0)
{ {
/* missing or corrupt data at this page position */ /* missing or corrupt data at this page position */
fprintf(stderr,"Corrupt or missing data in bitstream; continuing...\n"); fprintf(stderr,"Corrupt or missing data in bitstream; continuing...\n");
continue; continue;
} }
ogg_stream_pagein(&os,&og); /* can safely ignore errors at ogg_stream_pagein(&os,&og); /* can safely ignore errors at
this point */ this point */
while(1) while(1)
{ {
result=ogg_stream_packetout(&os,&op); result=ogg_stream_packetout(&os,&op);
if(result==0) if(result==0)
break; /* need more data */ break; /* need more data */
if(result<0) if(result<0)
continue; /* missing or corrupt data at this page position */ continue; /* missing or corrupt data at this page position */
/* no reason to complain; already complained above */ /* no reason to complain; already complained above */
/* we have a packet. Decode it */ /* we have a packet. Decode it */
float **pcm; float **pcm;
int samples; int samples;
if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
vorbis_synthesis_blockin(&vd,&vb); vorbis_synthesis_blockin(&vd,&vb);
/* /*
**pcm is a multichannel float vector. In stereo, for **pcm is a multichannel float vector. In stereo, for
example, pcm[0] is left, and pcm[1] is right. samples is example, pcm[0] is left, and pcm[1] is right. samples is
the size of each channel. Convert the float values the size of each channel. Convert the float values
(-1.<=range<=1.) to whatever PCM format and write it out */ (-1.<=range<=1.) to whatever PCM format and write it out */
while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0) while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0)
{ {
int bout=(samples<convsize?samples:convsize); int bout=(samples<convsize?samples:convsize);
//cout << "samples: " << samples << ", convsize: " << convsize << "\n"; //cout << "samples: " << samples << ", convsize: " << convsize << "\n";
/* convert floats to 16 bit signed ints (host order) and /* convert floats to 16 bit signed ints (host order) and
interleave */ interleave */
for(int i=0; i<vi.channels; i++) for(int i=0; i<vi.channels; i++)
{ {
ogg_int16_t *ptr=convbuffer+i; ogg_int16_t *ptr=convbuffer+i;
float *mono=pcm[i]; float *mono=pcm[i];
for(int j=0; j<bout; j++) for(int j=0; j<bout; j++)
{ {
int val=floor(mono[j]*32767.f+.5f); int val=floor(mono[j]*32767.f+.5f);
/* might as well guard against clipping */ /* might as well guard against clipping */
if(val>32767) if(val>32767)
val=32767; val=32767;
else if(val<-32768) else if(val<-32768)
val=-32768; val=-32768;
*ptr=val; *ptr=val;
ptr+=vi.channels; ptr+=vi.channels;
} }
} }
size_t oldSize = chunk->payloadSize; size_t oldSize = chunk->payloadSize;
size_t size = 2*vi.channels * bout; size_t size = 2*vi.channels * bout;
chunk->payloadSize += size; chunk->payloadSize += size;
chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize); chunk->payload = (char*)realloc(chunk->payload, chunk->payloadSize);
memcpy(chunk->payload + oldSize, convbuffer, size); memcpy(chunk->payload + oldSize, convbuffer, size);
/* tell libvorbis how many samples we actually consumed */ /* tell libvorbis how many samples we actually consumed */
vorbis_synthesis_read(&vd,bout); vorbis_synthesis_read(&vd,bout);
} }
} }
} }
// if(ogg_page_eos(&og))eos=1; // if(ogg_page_eos(&og))eos=1;
// ogg_stream_clear(&os); // ogg_stream_clear(&os);
// vorbis_comment_clear(&vc); // vorbis_comment_clear(&vc);
// vorbis_info_clear(&vi); /* must be called last */ // vorbis_info_clear(&vi); /* must be called last */
return true; return true;
} }
bool OggDecoder::setHeader(HeaderMessage* chunk) bool OggDecoder::setHeader(HeaderMessage* chunk)
{ {
bytes = chunk->payloadSize; bytes = chunk->payloadSize;
buffer=ogg_sync_buffer(&oy, bytes); buffer=ogg_sync_buffer(&oy, bytes);
memcpy(buffer, chunk->payload, bytes); memcpy(buffer, chunk->payload, bytes);
ogg_sync_wrote(&oy,bytes); ogg_sync_wrote(&oy,bytes);
if(ogg_sync_pageout(&oy,&og)!=1) if(ogg_sync_pageout(&oy,&og)!=1)
{ {
fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
return false; return false;
} }
ogg_stream_init(&os,ogg_page_serialno(&og)); ogg_stream_init(&os,ogg_page_serialno(&og));
vorbis_info_init(&vi); vorbis_info_init(&vi);
vorbis_comment_init(&vc); vorbis_comment_init(&vc);
if(ogg_stream_pagein(&os,&og)<0) if(ogg_stream_pagein(&os,&og)<0)
{ {
fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); fprintf(stderr,"Error reading first page of Ogg bitstream data.\n");
return false; return false;
} }
if(ogg_stream_packetout(&os,&op)!=1) if(ogg_stream_packetout(&os,&op)!=1)
{ {
fprintf(stderr,"Error reading initial header packet.\n"); fprintf(stderr,"Error reading initial header packet.\n");
return false; return false;
} }
if(vorbis_synthesis_headerin(&vi,&vc,&op)<0) if(vorbis_synthesis_headerin(&vi,&vc,&op)<0)
{ {
fprintf(stderr,"This Ogg bitstream does not contain Vorbis audio data.\n"); fprintf(stderr,"This Ogg bitstream does not contain Vorbis audio data.\n");
return false; return false;
} }
int i(0); int i(0);
while(i<2) while(i<2)
{ {
while(i<2) while(i<2)
{ {
int result=ogg_sync_pageout(&oy,&og); int result=ogg_sync_pageout(&oy,&og);
if(result==0) if(result==0)
break; /* Need more data */ break; /* Need more data */
/* Don't complain about missing or corrupt data yet. We'll /* Don't complain about missing or corrupt data yet. We'll
catch it at the packet output phase */ catch it at the packet output phase */
if(result==1) if(result==1)
{ {
ogg_stream_pagein(&os,&og); /* we can ignore any errors here as they'll also become apparent at packetout */ ogg_stream_pagein(&os,&og); /* we can ignore any errors here as they'll also become apparent at packetout */
while(i<2) while(i<2)
{ {
result=ogg_stream_packetout(&os,&op); result=ogg_stream_packetout(&os,&op);
if(result==0) if(result==0)
break; break;
if(result<0) if(result<0)
{ {
/* Uh oh; data at some point was corrupted or missing! /* Uh oh; data at some point was corrupted or missing!
We can't tolerate that in a header. Die. */ We can't tolerate that in a header. Die. */
fprintf(stderr,"Corrupt secondary header. Exiting.\n"); fprintf(stderr,"Corrupt secondary header. Exiting.\n");
return false; return false;
} }
result=vorbis_synthesis_headerin(&vi,&vc,&op); result=vorbis_synthesis_headerin(&vi,&vc,&op);
if(result<0) if(result<0)
{ {
fprintf(stderr,"Corrupt secondary header. Exiting.\n"); fprintf(stderr,"Corrupt secondary header. Exiting.\n");
return false; return false;
} }
i++; i++;
} }
} }
} }
} }
/* Throw the comments plus a few lines about the bitstream we're decoding */ /* Throw the comments plus a few lines about the bitstream we're decoding */
char **ptr=vc.user_comments; char **ptr=vc.user_comments;
while(*ptr) while(*ptr)
{ {
fprintf(stderr,"%s\n",*ptr); fprintf(stderr,"%s\n",*ptr);
++ptr; ++ptr;
} }
fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate); fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
fprintf(stderr,"Encoded by: %s\n\n",vc.vendor); fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
/* OK, got and parsed all three headers. Initialize the Vorbis /* OK, got and parsed all three headers. Initialize the Vorbis
packet->PCM decoder. */ packet->PCM decoder. */
if(vorbis_synthesis_init(&vd,&vi)==0) /* central decode state */ if(vorbis_synthesis_init(&vd,&vi)==0) /* central decode state */
vorbis_block_init(&vd,&vb); /* local state for most of the decode vorbis_block_init(&vd,&vb); /* local state for most of the decode
so multiple block decodes can so multiple block decodes can
proceed in parallel. We could init proceed in parallel. We could init
multiple vorbis_block structures multiple vorbis_block structures
for vd here */ for vd here */
return false; return false;
} }

View file

@ -7,31 +7,31 @@
class OggDecoder : public Decoder class OggDecoder : public Decoder
{ {
public: public:
OggDecoder(); OggDecoder();
virtual ~OggDecoder(); virtual ~OggDecoder();
virtual bool decode(PcmChunk* chunk); virtual bool decode(PcmChunk* chunk);
virtual bool setHeader(HeaderMessage* chunk); virtual bool setHeader(HeaderMessage* chunk);
private: private:
bool decodePayload(PcmChunk* chunk); bool decodePayload(PcmChunk* chunk);
ogg_sync_state oy; /* sync and verify incoming physical bitstream */ ogg_sync_state oy; /* sync and verify incoming physical bitstream */
ogg_stream_state os; /* take physical pages, weld into a logical ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */ stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */ ogg_packet op; /* one raw packet of data for decode */
vorbis_info vi; /* struct that stores all the static vorbis bitstream vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */ settings */
vorbis_comment vc; /* struct that stores all the bitstream user comments */ vorbis_comment vc; /* struct that stores all the bitstream user comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */ vorbis_block vb; /* local working space for packet->PCM decode */
ogg_int16_t* convbuffer; /* take 8k out of the data segment, not the stack */ ogg_int16_t* convbuffer; /* take 8k out of the data segment, not the stack */
int convsize; int convsize;
char *buffer; char *buffer;
int bytes; int bytes;
}; };

View file

@ -7,17 +7,17 @@ PcmDecoder::PcmDecoder() : Decoder()
bool PcmDecoder::decode(PcmChunk* chunk) bool PcmDecoder::decode(PcmChunk* chunk)
{ {
/* WireChunk* wireChunk = chunk->wireChunk; /* WireChunk* wireChunk = chunk->wireChunk;
for (size_t n=0; n<wireChunk->length; ++n) for (size_t n=0; n<wireChunk->length; ++n)
wireChunk->payload[n] *= 1; wireChunk->payload[n] *= 1;
*/ */
return true; return true;
} }
bool PcmDecoder::setHeader(HeaderMessage* chunk) bool PcmDecoder::setHeader(HeaderMessage* chunk)
{ {
return true; return true;
} }

View file

@ -6,9 +6,9 @@
class PcmDecoder : public Decoder class PcmDecoder : public Decoder
{ {
public: public:
PcmDecoder(); PcmDecoder();
virtual bool decode(PcmChunk* chunk); virtual bool decode(PcmChunk* chunk);
virtual bool setHeader(HeaderMessage* chunk); virtual bool setHeader(HeaderMessage* chunk);
}; };

View file

@ -15,137 +15,137 @@ Player::Player(Stream* stream) : active_(false), stream_(stream)
void Player::start() void Player::start()
{ {
unsigned int pcm, tmp, rate; unsigned int pcm, tmp, rate;
int channels; int channels;
snd_pcm_hw_params_t *params; snd_pcm_hw_params_t *params;
int buff_size; int buff_size;
rate = stream_->format.rate; rate = stream_->format.rate;
channels = stream_->format.channels; channels = stream_->format.channels;
/* Open the PCM device in playback mode */ /* Open the PCM device in playback mode */
if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) if ((pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
cout << "ERROR: Can't open " << PCM_DEVICE << " PCM device. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't open " << PCM_DEVICE << " PCM device. " << snd_strerror(pcm) << "\n";
/* struct snd_pcm_playback_info_t pinfo; /* struct snd_pcm_playback_info_t pinfo;
if ( (pcm = snd_pcm_playback_info( pcm_handle, &pinfo )) < 0 ) if ( (pcm = snd_pcm_playback_info( pcm_handle, &pinfo )) < 0 )
fprintf( stderr, "Error: playback info error: %s\n", snd_strerror( err ) ); fprintf( stderr, "Error: playback info error: %s\n", snd_strerror( err ) );
printf("buffer: '%d'\n", pinfo.buffer_size); printf("buffer: '%d'\n", pinfo.buffer_size);
*/ */
/* Allocate parameters object and fill it with default values*/ /* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(&params); snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params); snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */ /* Set parameters */
if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) if ((pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
cout << "ERROR: Can't set interleaved mode. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't set interleaved mode. " << snd_strerror(pcm) << "\n";
if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE)) < 0) if ((pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE)) < 0)
cout << "ERROR: Can't set format. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't set format. " << snd_strerror(pcm) << "\n";
if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0) if ((pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0)
cout << "ERROR: Can't set channels number. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't set channels number. " << snd_strerror(pcm) << "\n";
if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0) if ((pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0)
cout << "ERROR: Can't set rate. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't set rate. " << snd_strerror(pcm) << "\n";
unsigned int buffer_time; unsigned int buffer_time;
snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
if (buffer_time > BUFFER_TIME) if (buffer_time > BUFFER_TIME)
buffer_time = BUFFER_TIME; buffer_time = BUFFER_TIME;
unsigned int period_time = buffer_time / 4; unsigned int period_time = buffer_time / 4;
snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &period_time, 0); snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &period_time, 0);
snd_pcm_hw_params_set_buffer_time_near(pcm_handle, params, &buffer_time, 0); snd_pcm_hw_params_set_buffer_time_near(pcm_handle, params, &buffer_time, 0);
// long unsigned int periodsize = stream_->format.msRate() * 50;//2*rate/50; // long unsigned int periodsize = stream_->format.msRate() * 50;//2*rate/50;
// if ((pcm = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, params, &periodsize)) < 0) // if ((pcm = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, params, &periodsize)) < 0)
// cout << "Unable to set buffer size " << (long int)periodsize << ": " << snd_strerror(pcm) << "\n"; // cout << "Unable to set buffer size " << (long int)periodsize << ": " << snd_strerror(pcm) << "\n";
/* Write parameters */ /* Write parameters */
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0) if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0)
cout << "ERROR: Can't set harware parameters. " << snd_strerror(pcm) << "\n"; cout << "ERROR: Can't set harware parameters. " << snd_strerror(pcm) << "\n";
/* Resume information */ /* Resume information */
cout << "PCM name: " << snd_pcm_name(pcm_handle) << "\n"; cout << "PCM name: " << snd_pcm_name(pcm_handle) << "\n";
cout << "PCM state: " << snd_pcm_state_name(snd_pcm_state(pcm_handle)) << "\n"; cout << "PCM state: " << snd_pcm_state_name(snd_pcm_state(pcm_handle)) << "\n";
snd_pcm_hw_params_get_channels(params, &tmp); snd_pcm_hw_params_get_channels(params, &tmp);
cout << "channels: " << tmp << "\n"; cout << "channels: " << tmp << "\n";
if (tmp == 1) if (tmp == 1)
printf("(mono)\n"); printf("(mono)\n");
else if (tmp == 2) else if (tmp == 2)
printf("(stereo)\n"); printf("(stereo)\n");
snd_pcm_hw_params_get_rate(params, &tmp, 0); snd_pcm_hw_params_get_rate(params, &tmp, 0);
cout << "rate: " << tmp << " bps\n"; cout << "rate: " << tmp << " bps\n";
/* Allocate buffer to hold single period */ /* Allocate buffer to hold single period */
snd_pcm_hw_params_get_period_size(params, &frames, 0); snd_pcm_hw_params_get_period_size(params, &frames, 0);
cout << "frames: " << frames << "\n"; cout << "frames: " << frames << "\n";
buff_size = frames * channels * 2 /* 2 -> sample size */; buff_size = frames * channels * 2 /* 2 -> sample size */;
buff = (char *) malloc(buff_size); buff = (char *) malloc(buff_size);
snd_pcm_hw_params_get_period_time(params, &tmp, NULL); snd_pcm_hw_params_get_period_time(params, &tmp, NULL);
cout << "period time: " << tmp << "\n"; cout << "period time: " << tmp << "\n";
snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_t *swparams;
snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_alloca(&swparams);
snd_pcm_sw_params_current(pcm_handle, swparams); snd_pcm_sw_params_current(pcm_handle, swparams);
snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames); snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, frames); snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, frames);
// snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, frames); // snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, frames);
snd_pcm_sw_params(pcm_handle, swparams); snd_pcm_sw_params(pcm_handle, swparams);
playerThread = new thread(&Player::worker, this); playerThread = new thread(&Player::worker, this);
} }
void Player::stop() void Player::stop()
{ {
active_ = false; active_ = false;
playerThread->join(); playerThread->join();
delete playerThread; delete playerThread;
} }
void Player::worker() void Player::worker()
{ {
unsigned int pcm; unsigned int pcm;
snd_pcm_sframes_t avail; snd_pcm_sframes_t avail;
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay;
active_ = true; active_ = true;
while (active_) while (active_)
{ {
snd_pcm_avail_delay(pcm_handle, &avail, &delay); snd_pcm_avail_delay(pcm_handle, &avail, &delay);
if (stream_->getPlayerChunk(buff, (float)delay / stream_->format.msRate(), frames, 500)) if (stream_->getPlayerChunk(buff, (float)delay / stream_->format.msRate(), frames, 500))
{ {
if ((pcm = snd_pcm_writei(pcm_handle, buff, frames)) == -EPIPE) if ((pcm = snd_pcm_writei(pcm_handle, buff, frames)) == -EPIPE)
{ {
printf("XRUN.\n"); printf("XRUN.\n");
snd_pcm_prepare(pcm_handle); snd_pcm_prepare(pcm_handle);
} }
else if (pcm < 0) else if (pcm < 0)
{ {
printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm));
} }
} }
} }
snd_pcm_drain(pcm_handle); snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle); snd_pcm_close(pcm_handle);
free(buff); free(buff);
} }

View file

@ -11,18 +11,18 @@
class Player class Player
{ {
public: public:
Player(Stream* stream); Player(Stream* stream);
void start(); void start();
void stop(); void stop();
private: private:
void worker(); void worker();
snd_pcm_t* pcm_handle; snd_pcm_t* pcm_handle;
snd_pcm_uframes_t frames; snd_pcm_uframes_t frames;
char *buff; char *buff;
std::atomic<bool> active_; std::atomic<bool> active_;
Stream* stream_; Stream* stream_;
std::thread* playerThread; std::thread* playerThread;
}; };

View file

@ -22,47 +22,47 @@ namespace po = boost::program_options;
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
int deviceIdx; int deviceIdx;
string ip; string ip;
int bufferMs; int bufferMs;
size_t port; size_t port;
bool runAsDaemon; bool runAsDaemon;
// string sampleFormat; // string sampleFormat;
po::options_description desc("Allowed options"); po::options_description desc("Allowed options");
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 where the server listens on") ("port,p", po::value<size_t>(&port)->default_value(98765), "port where the server listens on")
("ip,i", po::value<string>(&ip)->default_value("192.168.0.2"), "server IP") ("ip,i", po::value<string>(&ip)->default_value("192.168.0.2"), "server IP")
("soundcard,s", po::value<int>(&deviceIdx)->default_value(-1), "index of the soundcard") ("soundcard,s", po::value<int>(&deviceIdx)->default_value(-1), "index of the soundcard")
// ("sampleformat,f", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format") // ("sampleformat,f", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format")
("buffer,b", po::value<int>(&bufferMs)->default_value(300), "buffer size [ms]") ("buffer,b", po::value<int>(&bufferMs)->default_value(300), "buffer size [ms]")
("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize") ("daemon,d", po::bool_switch(&runAsDaemon)->default_value(false), "daemonize")
; ;
po::variables_map vm; po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm); po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm); po::notify(vm);
if (vm.count("help")) if (vm.count("help"))
{ {
cout << desc << "\n"; cout << desc << "\n";
return 1; return 1;
} }
std::clog.rdbuf(new Log("snapclient", LOG_DAEMON)); std::clog.rdbuf(new Log("snapclient", LOG_DAEMON));
if (runAsDaemon) if (runAsDaemon)
{ {
daemonize(); daemonize();
std::clog << kLogNotice << "daemon started" << std::endl; std::clog << kLogNotice << "daemon started" << std::endl;
} }
Controller controller; Controller controller;
controller.start(ip, port, bufferMs); controller.start(ip, port, bufferMs);
while(true) while(true)
usleep(10000); usleep(10000);
return 0; return 0;
} }

View file

@ -9,34 +9,34 @@ using namespace std;
Stream::Stream(const SampleFormat& sampleFormat) : format(format_), format_(sampleFormat), sleep(0), median(0), shortMedian(0), lastUpdate(0) Stream::Stream(const SampleFormat& sampleFormat) : format(format_), format_(sampleFormat), sleep(0), median(0), shortMedian(0), lastUpdate(0)
{ {
buffer.setSize(500); buffer.setSize(500);
shortBuffer.setSize(100); shortBuffer.setSize(100);
miniBuffer.setSize(20); miniBuffer.setSize(20);
cardBuffer.setSize(50); cardBuffer.setSize(50);
bufferMs = 500; bufferMs = 500;
} }
void Stream::setBufferLen(size_t bufferLenMs) void Stream::setBufferLen(size_t bufferLenMs)
{ {
bufferMs = bufferLenMs; bufferMs = bufferLenMs;
} }
void Stream::clearChunks() void Stream::clearChunks()
{ {
while (chunks.size() > 0) while (chunks.size() > 0)
chunks.pop(); chunks.pop();
} }
void Stream::addChunk(PcmChunk* chunk) void Stream::addChunk(PcmChunk* chunk)
{ {
while (chunks.size() * chunk->getDuration() > 10000) while (chunks.size() * chunk->getDuration() > 10000)
chunks.pop(); chunks.pop();
chunks.push(shared_ptr<PcmChunk>(chunk)); chunks.push(shared_ptr<PcmChunk>(chunk));
// cout << "new chunk: " << chunk->getDuration() << ", Chunks: " << chunks.size() << "\n"; // cout << "new chunk: " << chunk->getDuration() << ", Chunks: " << chunks.size() << "\n";
} }
@ -44,11 +44,11 @@ void Stream::addChunk(PcmChunk* chunk)
time_point_ms Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer) time_point_ms Stream::getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer)
{ {
if (!chunk) if (!chunk)
chunk = chunks.pop(); chunk = chunks.pop();
time_point_ms tp = chunk->timePoint(); time_point_ms tp = chunk->timePoint();
memset(outputBuffer, 0, framesPerBuffer * format.frameSize); memset(outputBuffer, 0, framesPerBuffer * format.frameSize);
return tp; return tp;
} }
@ -72,204 +72,204 @@ time_point_ms Stream::seekTo(const time_point_ms& to)
time_point_ms Stream::seek(long ms) time_point_ms Stream::seek(long ms)
{ {
if (!chunk) if (!chunk)
chunk = chunks.pop(); chunk = chunks.pop();
if (ms <= 0) if (ms <= 0)
return chunk->timePoint(); return chunk->timePoint();
// time_point_ms tp = chunk->timePoint(); // time_point_ms tp = chunk->timePoint();
while (ms > chunk->getTimeLeft()) while (ms > chunk->getTimeLeft())
{ {
chunk = chunks.pop(); chunk = chunks.pop();
ms -= min(ms, (long)chunk->getTimeLeft()); ms -= min(ms, (long)chunk->getTimeLeft());
} }
chunk->seek(ms * format.msRate()); chunk->seek(ms * format.msRate());
return chunk->timePoint(); return chunk->timePoint();
} }
time_point_ms Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction) time_point_ms Stream::getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction)
{ {
if (!chunk) if (!chunk)
if (!chunks.try_pop(chunk, std::chrono::milliseconds(timeout))) if (!chunks.try_pop(chunk, std::chrono::milliseconds(timeout)))
throw 0; throw 0;
time_point_ms tp = chunk->timePoint(); time_point_ms tp = chunk->timePoint();
int read = 0; int read = 0;
int toRead = framesPerBuffer + correction*format.msRate(); int toRead = framesPerBuffer + correction*format.msRate();
char* buffer; char* buffer;
if (correction != 0) if (correction != 0)
{ {
int msBuffer = floor(framesPerBuffer / format.msRate()); int msBuffer = floor(framesPerBuffer / format.msRate());
if (abs(correction) > msBuffer / 2) if (abs(correction) > msBuffer / 2)
correction = copysign(msBuffer / 2, correction); correction = copysign(msBuffer / 2, correction);
buffer = (char*)malloc(toRead * format.frameSize); buffer = (char*)malloc(toRead * format.frameSize);
} }
else else
buffer = (char*)outputBuffer; buffer = (char*)outputBuffer;
while (read < toRead) while (read < toRead)
{ {
read += chunk->readFrames(buffer + read*format.frameSize, toRead - read); read += chunk->readFrames(buffer + read*format.frameSize, toRead - read);
if (chunk->isEndOfChunk()) if (chunk->isEndOfChunk())
if (!chunks.try_pop(chunk, std::chrono::milliseconds(timeout))) if (!chunks.try_pop(chunk, std::chrono::milliseconds(timeout)))
throw 0; throw 0;
} }
if (correction != 0) if (correction != 0)
{ {
float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_); float factor = (float)toRead / framesPerBuffer;//(float)(framesPerBuffer*channels_);
std::cout << "correction: " << correction << ", factor: " << factor << "\n"; std::cout << "correction: " << correction << ", factor: " << factor << "\n";
float idx = 0; float idx = 0;
for (size_t n=0; n<framesPerBuffer; ++n) for (size_t n=0; n<framesPerBuffer; ++n)
{ {
size_t index(floor(idx));// = (int)(ceil(n*factor)); size_t index(floor(idx));// = (int)(ceil(n*factor));
memcpy((char*)outputBuffer + n*format.frameSize, buffer + index*format.frameSize, format.frameSize); memcpy((char*)outputBuffer + n*format.frameSize, buffer + index*format.frameSize, format.frameSize);
idx += factor; idx += factor;
} }
free(buffer); free(buffer);
} }
return tp; return tp;
} }
void Stream::updateBuffers(int age) void Stream::updateBuffers(int age)
{ {
buffer.add(age); buffer.add(age);
miniBuffer.add(age); miniBuffer.add(age);
shortBuffer.add(age); shortBuffer.add(age);
} }
void Stream::resetBuffers() void Stream::resetBuffers()
{ {
buffer.clear(); buffer.clear();
miniBuffer.clear(); miniBuffer.clear();
shortBuffer.clear(); shortBuffer.clear();
} }
bool Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout) bool Stream::getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout)
{ {
//cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n"; //cout << "framesPerBuffer: " << framesPerBuffer << "\tms: " << framesPerBuffer*2 / PLAYER_CHUNK_MS_SIZE << "\t" << PLAYER_CHUNK_SIZE << "\n";
int msBuffer = framesPerBuffer / format_.msRate(); int msBuffer = framesPerBuffer / format_.msRate();
//cout << msBuffer << " ms, " << framesPerBuffer << "\t" << format_.rate/1000 << "\n"; //cout << msBuffer << " ms, " << framesPerBuffer << "\t" << format_.rate/1000 << "\n";
int ticks = 0; int ticks = 0;
long currentTick = getTickCount(); long currentTick = getTickCount();
if (lastTick == 0) if (lastTick == 0)
lastTick = currentTick; lastTick = currentTick;
ticks = currentTick - lastTick; ticks = currentTick - lastTick;
lastTick = currentTick; lastTick = currentTick;
int correction = 0; int correction = 0;
if (sleep != 0) if (sleep != 0)
{ {
resetBuffers(); resetBuffers();
if (sleep < -msBuffer/2) if (sleep < -msBuffer/2)
{ {
cout << "Sleep " << sleep; cout << "Sleep " << sleep;
sleep = PcmChunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs(); sleep = PcmChunk::getAge(getSilentPlayerChunk(outputBuffer, framesPerBuffer)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs();
std::cerr << " after: " << sleep << ", chunks: " << chunks.size() << "\n"; std::cerr << " after: " << sleep << ", chunks: " << chunks.size() << "\n";
// std::clog << kLogNotice << "sleep: " << sleep << std::endl; // std::clog << kLogNotice << "sleep: " << sleep << std::endl;
// if (sleep > -msBuffer/2) // if (sleep > -msBuffer/2)
// sleep = 0; // sleep = 0;
if (sleep < -msBuffer/2) if (sleep < -msBuffer/2)
return true; return true;
} }
else if (sleep > msBuffer/2) else if (sleep > msBuffer/2)
{ {
/* cout << "Sleep " << sleep; /* cout << "Sleep " << sleep;
time_point_ms ms(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch())); time_point_ms ms(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()));
ms -= std::chrono::milliseconds((long int)(bufferMs - outputBufferDacTime)); ms -= std::chrono::milliseconds((long int)(bufferMs - outputBufferDacTime));
cout << "\nms: " << Chunk::getAge(ms) << "\t chunk: " << chunk->getAge() << "\n"; cout << "\nms: " << Chunk::getAge(ms) << "\t chunk: " << chunk->getAge() << "\n";
sleep = Chunk::getAge(seekTo(ms)) - bufferMs + outputBufferDacTime; sleep = Chunk::getAge(seekTo(ms)) - bufferMs + outputBufferDacTime;
cout << " after: " << sleep << "\n"; cout << " after: " << sleep << "\n";
*/ */
if (!chunk) if (!chunk)
chunk = chunks.pop(); chunk = chunks.pop();
while (sleep > chunk->getDuration()) while (sleep > chunk->getDuration())
{ {
chunk = chunks.pop(); chunk = chunks.pop();
sleep = chunk->getAge() - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs(); sleep = chunk->getAge() - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs();
// cout << "chunk->getAge() > chunk->getDuration(): " << chunk->getAge() - bufferMs + outputBufferDacTime << " > " << chunk->getDuration() << ", chunks: " << chunks.size() << ", out: " << outputBufferDacTime << ", needed: " << msBuffer << ", sleep: " << sleep << "\n"; // cout << "chunk->getAge() > chunk->getDuration(): " << chunk->getAge() - bufferMs + outputBufferDacTime << " > " << chunk->getDuration() << ", chunks: " << chunks.size() << ", out: " << outputBufferDacTime << ", needed: " << msBuffer << ", sleep: " << sleep << "\n";
usleep(1000); usleep(1000);
} }
cout << "seek: " << PcmChunk::getAge(seek(sleep)) - bufferMs + outputBufferDacTime << "\n"; cout << "seek: " << PcmChunk::getAge(seek(sleep)) - bufferMs + outputBufferDacTime << "\n";
sleep = 0; sleep = 0;
} }
else if (sleep < 0) else if (sleep < 0)
{ {
++sleep; ++sleep;
correction = -1; correction = -1;
} }
else if (sleep > 0) else if (sleep > 0)
{ {
--sleep; --sleep;
correction = 1; correction = 1;
} }
} }
long age(0); long age(0);
try try
{ {
age = PcmChunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer, timeout, correction)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs(); age = PcmChunk::getAge(getNextPlayerChunk(outputBuffer, framesPerBuffer, timeout, correction)) - bufferMs + outputBufferDacTime + TimeProvider::getInstance().getDiffToServerMs();
} }
catch(int e) catch(int e)
{ {
return false; return false;
} }
if (sleep == 0) if (sleep == 0)
{ {
if (buffer.full() && (abs(median) > 1)) if (buffer.full() && (abs(median) > 1))
{ {
cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n"; cout << "pBuffer->full() && (abs(median) > 1): " << median << "\n";
sleep = median; sleep = median;
} }
else if (shortBuffer.full() && (abs(shortMedian) > 5)) else if (shortBuffer.full() && (abs(shortMedian) > 5))
{ {
cout << "pShortBuffer->full() && (abs(shortMedian) > 5): " << shortMedian << "\n"; cout << "pShortBuffer->full() && (abs(shortMedian) > 5): " << shortMedian << "\n";
sleep = shortMedian; sleep = shortMedian;
} }
else if (miniBuffer.full() && (abs(miniBuffer.median()) > 50)) else if (miniBuffer.full() && (abs(miniBuffer.median()) > 50))
{ {
cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer.median() << "\n"; cout << "pMiniBuffer->full() && (abs(pMiniBuffer->mean()) > 50): " << miniBuffer.median() << "\n";
sleep = miniBuffer.mean(); sleep = miniBuffer.mean();
} }
else if (abs(age) > 200) else if (abs(age) > 200)
{ {
cout << "age > 50: " << age << "\n"; cout << "age > 50: " << age << "\n";
sleep = age; sleep = age;
} }
} }
if (sleep != 0) if (sleep != 0)
std::cerr << "Sleep: " << sleep << "\n"; std::cerr << "Sleep: " << sleep << "\n";
// std::cerr << "Chunk: " << age << "\t" << outputBufferDacTime*1000 << "\n"; // std::cerr << "Chunk: " << age << "\t" << outputBufferDacTime*1000 << "\n";
if (ticks > 2) if (ticks > 2)
{ {
// cout << age << "\n"; // cout << age << "\n";
updateBuffers(age); updateBuffers(age);
} }
time_t now = time(NULL); time_t now = time(NULL);
if (now != lastUpdate) if (now != lastUpdate)
{ {
lastUpdate = now; lastUpdate = now;
median = buffer.median(); median = buffer.median();
shortMedian = shortBuffer.median(); shortMedian = shortBuffer.median();
std::cerr << "Chunk: " << age << "\t" << miniBuffer.median() << "\t" << shortMedian << "\t" << median << "\t" << buffer.size() << "\t" << /*cardBuffer << "\t" <<*/ outputBufferDacTime << "\n"; std::cerr << "Chunk: " << age << "\t" << miniBuffer.median() << "\t" << shortMedian << "\t" << median << "\t" << buffer.size() << "\t" << /*cardBuffer << "\t" <<*/ outputBufferDacTime << "\n";
} }
return true; return true;
} }

View file

@ -18,37 +18,37 @@
class Stream class Stream
{ {
public: public:
Stream(const SampleFormat& format); Stream(const SampleFormat& format);
void addChunk(PcmChunk* chunk); void addChunk(PcmChunk* chunk);
void clearChunks(); void clearChunks();
bool getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout); bool getPlayerChunk(void* outputBuffer, double outputBufferDacTime, unsigned long framesPerBuffer, size_t timeout);
void setBufferLen(size_t bufferLenMs); void setBufferLen(size_t bufferLenMs);
const SampleFormat& format; const SampleFormat& format;
private: private:
time_point_ms getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction = 0); time_point_ms getNextPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer, size_t timeout, int correction = 0);
time_point_ms getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer); time_point_ms getSilentPlayerChunk(void* outputBuffer, unsigned long framesPerBuffer);
time_point_ms seek(long ms); time_point_ms seek(long ms);
// time_point_ms seekTo(const time_point_ms& to); // time_point_ms seekTo(const time_point_ms& to);
void updateBuffers(int age); void updateBuffers(int age);
void resetBuffers(); void resetBuffers();
SampleFormat format_; SampleFormat format_;
long lastTick; long lastTick;
long sleep; long sleep;
Queue<std::shared_ptr<PcmChunk>> chunks; Queue<std::shared_ptr<PcmChunk>> chunks;
DoubleBuffer<long> cardBuffer; DoubleBuffer<long> cardBuffer;
DoubleBuffer<long> miniBuffer; DoubleBuffer<long> miniBuffer;
DoubleBuffer<long> buffer; DoubleBuffer<long> buffer;
DoubleBuffer<long> shortBuffer; DoubleBuffer<long> shortBuffer;
std::shared_ptr<PcmChunk> chunk; std::shared_ptr<PcmChunk> chunk;
int median; int median;
int shortMedian; int shortMedian;
time_t lastUpdate; time_t lastUpdate;
int bufferMs; int bufferMs;
}; };

View file

@ -10,8 +10,8 @@ using boost::asio::ip::tcp;
class StreamClient : public ClientConnection class StreamClient : public ClientConnection
{ {
public: public:
StreamClient(MessageReceiver* _receiver, const std::string& _ip, size_t _port); StreamClient(MessageReceiver* _receiver, const std::string& _ip, size_t _port);
virtual ~StreamClient(); virtual ~StreamClient();
}; };

View file

@ -3,26 +3,26 @@
TimeProvider::TimeProvider() : diffToServer(0) TimeProvider::TimeProvider() : diffToServer(0)
{ {
diffBuffer.setSize(60); diffBuffer.setSize(60);
} }
void TimeProvider::setDiffToServer(double ms) void TimeProvider::setDiffToServer(double ms)
{ {
diffBuffer.add(ms * 1000); diffBuffer.add(ms * 1000);
diffToServer = diffBuffer.median(); diffToServer = diffBuffer.median();
} }
long TimeProvider::getDiffToServer() long TimeProvider::getDiffToServer()
{ {
return diffToServer; return diffToServer;
} }
long TimeProvider::getDiffToServerMs() long TimeProvider::getDiffToServerMs()
{ {
return diffToServer / 1000; return diffToServer / 1000;
} }

View file

@ -6,26 +6,26 @@
class TimeProvider class TimeProvider
{ {
public: public:
static TimeProvider& getInstance() static TimeProvider& getInstance()
{ {
static TimeProvider instance; static TimeProvider instance;
return instance; return instance;
} }
void setDiffToServer(double ms); void setDiffToServer(double ms);
long getDiffToServer(); long getDiffToServer();
long getDiffToServerMs(); long getDiffToServerMs();
private: private:
TimeProvider(); // Constructor? (the {} brackets) are needed here. TimeProvider(); // Constructor? (the {} brackets) are needed here.
// Dont forget to declare these two. You want to make sure they // Dont forget to declare these two. You want to make sure they
// are unaccessable otherwise you may accidently get copies of // are unaccessable otherwise you may accidently get copies of
// your singleton appearing. // your singleton appearing.
TimeProvider(TimeProvider const&); // Don't Implement TimeProvider(TimeProvider const&); // Don't Implement
void operator=(TimeProvider const&); // Don't implement void operator=(TimeProvider const&); // Don't implement
DoubleBuffer<long> diffBuffer; DoubleBuffer<long> diffBuffer;
long diffToServer; long diffToServer;
}; };

View file

@ -8,37 +8,37 @@
class HeaderMessage : public BaseMessage class HeaderMessage : public BaseMessage
{ {
public: public:
HeaderMessage(size_t size = 0) : BaseMessage(message_type::header), payloadSize(size) HeaderMessage(size_t size = 0) : BaseMessage(message_type::header), payloadSize(size)
{ {
payload = (char*)malloc(size); payload = (char*)malloc(size);
} }
virtual ~HeaderMessage() virtual ~HeaderMessage()
{ {
free(payload); free(payload);
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t)); stream.read(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t));
payload = (char*)realloc(payload, payloadSize); payload = (char*)realloc(payload, payloadSize);
stream.read(payload, payloadSize); stream.read(payload, payloadSize);
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return sizeof(uint32_t) + payloadSize; return sizeof(uint32_t) + payloadSize;
} }
uint32_t payloadSize; uint32_t payloadSize;
char* payload; char* payload;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t)); stream.write(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t));
stream.write(payload, payloadSize); stream.write(payload, payloadSize);
} }
}; };

View file

@ -2,47 +2,47 @@
Log::Log(std::string ident, int facility) Log::Log(std::string ident, int facility)
{ {
facility_ = facility; facility_ = facility;
priority_ = LOG_DEBUG; priority_ = LOG_DEBUG;
strncpy(ident_, ident.c_str(), sizeof(ident_)); strncpy(ident_, ident.c_str(), sizeof(ident_));
ident_[sizeof(ident_)-1] = '\0'; ident_[sizeof(ident_)-1] = '\0';
openlog(ident_, LOG_PID, facility_); openlog(ident_, LOG_PID, facility_);
} }
int Log::sync() int Log::sync()
{ {
if (buffer_.length()) if (buffer_.length())
{ {
if (priority_ == dbg) if (priority_ == dbg)
std::cout << buffer_.c_str(); std::cout << buffer_.c_str();
else else
syslog(priority_, "%s", buffer_.c_str()); syslog(priority_, "%s", buffer_.c_str());
buffer_.erase(); buffer_.erase();
priority_ = LOG_DEBUG; // default to debug for each message priority_ = LOG_DEBUG; // default to debug for each message
} }
return 0; return 0;
} }
int Log::overflow(int c) int Log::overflow(int c)
{ {
if (c != EOF) if (c != EOF)
{ {
buffer_ += static_cast<char>(c); buffer_ += static_cast<char>(c);
} }
else else
{ {
sync(); sync();
} }
return c; return c;
} }
std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority) std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority)
{ {
static_cast<Log *>(os.rdbuf())->priority_ = (int)log_priority; static_cast<Log *>(os.rdbuf())->priority_ = (int)log_priority;
if (log_priority == dbg) if (log_priority == dbg)
os.flush(); os.flush();
return os; return os;
} }

View file

@ -9,15 +9,15 @@
enum LogPriority enum LogPriority
{ {
kLogEmerg = LOG_EMERG, // system is unusable kLogEmerg = LOG_EMERG, // system is unusable
kLogAlert = LOG_ALERT, // action must be taken immediately kLogAlert = LOG_ALERT, // action must be taken immediately
kLogCrit = LOG_CRIT, // critical conditions kLogCrit = LOG_CRIT, // critical conditions
kLogErr = LOG_ERR, // error conditions kLogErr = LOG_ERR, // error conditions
kLogWarning = LOG_WARNING, // warning conditions kLogWarning = LOG_WARNING, // warning conditions
kLogNotice = LOG_NOTICE, // normal, but significant, condition kLogNotice = LOG_NOTICE, // normal, but significant, condition
kLogInfo = LOG_INFO, // informational message kLogInfo = LOG_INFO, // informational message
kLogDebug = LOG_DEBUG, // debug-level message kLogDebug = LOG_DEBUG, // debug-level message
dbg dbg
}; };
std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority); std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority);
@ -25,18 +25,18 @@ std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority);
class Log : public std::basic_streambuf<char, std::char_traits<char> > class Log : public std::basic_streambuf<char, std::char_traits<char> >
{ {
public: public:
explicit Log(std::string ident, int facility); explicit Log(std::string ident, int facility);
protected: protected:
int sync(); int sync();
int overflow(int c); int overflow(int c);
private: private:
friend std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority); friend std::ostream& operator<< (std::ostream& os, const LogPriority& log_priority);
std::string buffer_; std::string buffer_;
int facility_; int facility_;
int priority_; int priority_;
char ident_[50]; char ident_[50];
}; };

View file

@ -12,171 +12,171 @@ template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT> class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT>
{ {
public: public:
vectorwrapbuf(std::vector<CharT> &vec) vectorwrapbuf(std::vector<CharT> &vec)
{ {
this->setg(vec.data(), vec.data(), vec.data() + vec.size()); this->setg(vec.data(), vec.data(), vec.data() + vec.size());
} }
}; };
struct membuf : public std::basic_streambuf<char> struct membuf : public std::basic_streambuf<char>
{ {
membuf(char* begin, char* end) membuf(char* begin, char* end)
{ {
this->setg(begin, begin, end); this->setg(begin, begin, end);
} }
}; };
enum message_type enum message_type
{ {
base = 0, base = 0,
header = 1, header = 1,
payload = 2, payload = 2,
sampleformat = 3, sampleformat = 3,
serversettings = 4, serversettings = 4,
timemsg = 5, timemsg = 5,
requestmsg = 6 requestmsg = 6
}; };
struct tv struct tv
{ {
tv() tv()
{ {
timeval t; timeval t;
gettimeofday(&t, NULL); gettimeofday(&t, NULL);
sec = t.tv_sec; sec = t.tv_sec;
usec = t.tv_usec; usec = t.tv_usec;
} }
tv(timeval tv) : sec(tv.tv_sec), usec(tv.tv_usec) {}; tv(timeval tv) : sec(tv.tv_sec), usec(tv.tv_usec) {};
tv(int32_t _sec, int32_t _usec) : sec(_sec), usec(_usec) {}; tv(int32_t _sec, int32_t _usec) : sec(_sec), usec(_usec) {};
int32_t sec; int32_t sec;
int32_t usec; int32_t usec;
/* /*
5.3 - 6.2 = -0.9 5.3 - 6.2 = -0.9
-1 -1
0.1 0.1
5.3 - 6.4 = -1.1 5.3 - 6.4 = -1.1
-1 -1
-0.1 -0.1
*/ */
//(timeMsg.received.sec - timeMsg.sent.sec) * 1000000 + (timeMsg.received.usec - timeMsg.sent.usec) //(timeMsg.received.sec - timeMsg.sent.sec) * 1000000 + (timeMsg.received.usec - timeMsg.sent.usec)
tv operator-(const tv& other) tv operator-(const tv& other)
{ {
tv result(*this); tv result(*this);
result.sec -= other.sec; result.sec -= other.sec;
result.usec -= other.usec; result.usec -= other.usec;
if (result.usec > 0) if (result.usec > 0)
{ {
result.sec += 1; result.sec += 1;
result.usec = 1000000 - result.usec; result.usec = 1000000 - result.usec;
} }
else if (result.usec < 0) else if (result.usec < 0)
{ {
result.usec *= -1; result.usec *= -1;
} }
/* else if (result.usec >= 1000000) /* else if (result.usec >= 1000000)
{ {
result.usec -= 1000000; result.usec -= 1000000;
result.sec += 1; result.sec += 1;
} }
*/ return result; */ return result;
} }
}; };
struct BaseMessage struct BaseMessage
{ {
BaseMessage() : type(base), id(0), refersTo(0) BaseMessage() : type(base), id(0), refersTo(0)
{ {
} }
BaseMessage(message_type type_) : type(type_), id(0), refersTo(0) BaseMessage(message_type type_) : type(type_), id(0), refersTo(0)
{ {
} }
virtual ~BaseMessage() virtual ~BaseMessage()
{ {
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char*>(&type), sizeof(uint16_t)); stream.read(reinterpret_cast<char*>(&type), sizeof(uint16_t));
stream.read(reinterpret_cast<char*>(&id), sizeof(uint16_t)); stream.read(reinterpret_cast<char*>(&id), sizeof(uint16_t));
stream.read(reinterpret_cast<char*>(&refersTo), sizeof(uint16_t)); stream.read(reinterpret_cast<char*>(&refersTo), sizeof(uint16_t));
stream.read(reinterpret_cast<char *>(&sent.sec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&sent.sec), sizeof(int32_t));
stream.read(reinterpret_cast<char *>(&sent.usec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&sent.usec), sizeof(int32_t));
stream.read(reinterpret_cast<char *>(&received.sec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&received.sec), sizeof(int32_t));
stream.read(reinterpret_cast<char *>(&received.usec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&received.usec), sizeof(int32_t));
stream.read(reinterpret_cast<char*>(&size), sizeof(uint32_t)); stream.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
} }
void deserialize(char* payload) void deserialize(char* payload)
{ {
membuf databuf(payload, payload + BaseMessage::getSize()); membuf databuf(payload, payload + BaseMessage::getSize());
std::istream is(&databuf); std::istream is(&databuf);
read(is); read(is);
} }
void deserialize(const BaseMessage& baseMessage, char* payload) void deserialize(const BaseMessage& baseMessage, char* payload)
{ {
type = baseMessage.type; type = baseMessage.type;
id = baseMessage.id; id = baseMessage.id;
refersTo = baseMessage.refersTo; refersTo = baseMessage.refersTo;
sent = baseMessage.sent; sent = baseMessage.sent;
received = baseMessage.received; received = baseMessage.received;
size = baseMessage.size; size = baseMessage.size;
membuf databuf(payload, payload + size); membuf databuf(payload, payload + size);
std::istream is(&databuf); std::istream is(&databuf);
read(is); read(is);
} }
virtual void serialize(std::ostream& stream) virtual void serialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char*>(&type), sizeof(uint16_t)); stream.write(reinterpret_cast<char*>(&type), sizeof(uint16_t));
stream.write(reinterpret_cast<char*>(&id), sizeof(uint16_t)); stream.write(reinterpret_cast<char*>(&id), sizeof(uint16_t));
stream.write(reinterpret_cast<char*>(&refersTo), sizeof(uint16_t)); stream.write(reinterpret_cast<char*>(&refersTo), sizeof(uint16_t));
stream.write(reinterpret_cast<char *>(&sent.sec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&sent.sec), sizeof(int32_t));
stream.write(reinterpret_cast<char *>(&sent.usec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&sent.usec), sizeof(int32_t));
stream.write(reinterpret_cast<char *>(&received.sec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&received.sec), sizeof(int32_t));
stream.write(reinterpret_cast<char *>(&received.usec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&received.usec), sizeof(int32_t));
size = getSize(); size = getSize();
stream.write(reinterpret_cast<char*>(&size), sizeof(uint32_t)); stream.write(reinterpret_cast<char*>(&size), sizeof(uint32_t));
doserialize(stream); doserialize(stream);
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return 3*sizeof(uint16_t) + 2*sizeof(tv) + sizeof(uint32_t); return 3*sizeof(uint16_t) + 2*sizeof(tv) + sizeof(uint32_t);
}; };
uint16_t type; uint16_t type;
uint16_t id; uint16_t id;
uint16_t refersTo; uint16_t refersTo;
tv sent; tv sent;
tv received; tv received;
uint32_t size; uint32_t size;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
}; };
}; };
struct SerializedMessage struct SerializedMessage
{ {
~SerializedMessage() ~SerializedMessage()
{ {
free(buffer); free(buffer);
} }
BaseMessage message; BaseMessage message;
char* buffer; char* buffer;
}; };

View file

@ -24,56 +24,56 @@ PcmChunk::~PcmChunk()
bool PcmChunk::isEndOfChunk() const bool PcmChunk::isEndOfChunk() const
{ {
return idx >= getFrameCount(); return idx >= getFrameCount();
} }
double PcmChunk::getFrameCount() const double PcmChunk::getFrameCount() const
{ {
return (payloadSize / format.frameSize); return (payloadSize / format.frameSize);
} }
double PcmChunk::getDuration() const double PcmChunk::getDuration() const
{ {
return getFrameCount() / format.msRate(); return getFrameCount() / format.msRate();
} }
double PcmChunk::getTimeLeft() const double PcmChunk::getTimeLeft() const
{ {
return (getFrameCount() - idx) / format.msRate(); return (getFrameCount() - idx) / format.msRate();
} }
int PcmChunk::seek(int frames) int PcmChunk::seek(int frames)
{ {
idx += frames; idx += frames;
if (idx > getFrameCount()) if (idx > getFrameCount())
idx = getFrameCount(); idx = getFrameCount();
if (idx < 0) if (idx < 0)
idx = 0; idx = 0;
return idx; return idx;
} }
int PcmChunk::readFrames(void* outputBuffer, size_t frameCount) int PcmChunk::readFrames(void* outputBuffer, size_t frameCount)
{ {
//logd << "read: " << frameCount << ", total: " << (wireChunk->length / format.frameSize) << ", idx: " << idx;// << std::endl; //logd << "read: " << frameCount << ", total: " << (wireChunk->length / format.frameSize) << ", idx: " << idx;// << std::endl;
int result = frameCount; int result = frameCount;
if (idx + frameCount > (payloadSize / format.frameSize)) if (idx + frameCount > (payloadSize / format.frameSize))
result = (payloadSize / format.frameSize) - idx; result = (payloadSize / format.frameSize) - idx;
//logd << ", from: " << format.frameSize*idx << ", to: " << format.frameSize*idx + format.frameSize*result; //logd << ", from: " << format.frameSize*idx << ", to: " << format.frameSize*idx + format.frameSize*result;
if (outputBuffer != NULL) if (outputBuffer != NULL)
memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize*idx, format.frameSize*result); memcpy((char*)outputBuffer, (char*)(payload) + format.frameSize*idx, format.frameSize*result);
idx += result; idx += result;
//logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize << "\n";//std::endl; //logd << ", new idx: " << idx << ", result: " << result << ", wireChunk->length: " << wireChunk->length << ", format.frameSize: " << format.frameSize << "\n";//std::endl;
return result; return result;
} }

View file

@ -13,57 +13,57 @@ typedef std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono:
class PcmChunk : public WireChunk class PcmChunk : public WireChunk
{ {
public: public:
PcmChunk(const SampleFormat& sampleFormat, size_t ms); PcmChunk(const SampleFormat& sampleFormat, size_t ms);
PcmChunk(); PcmChunk();
~PcmChunk(); ~PcmChunk();
int readFrames(void* outputBuffer, size_t frameCount); int readFrames(void* outputBuffer, size_t frameCount);
bool isEndOfChunk() const; bool isEndOfChunk() const;
inline time_point_ms timePoint() const inline time_point_ms timePoint() const
{ {
time_point_ms tp; time_point_ms tp;
std::chrono::milliseconds::rep relativeIdxTp = ((double)idx / ((double)format.rate/1000.)); std::chrono::milliseconds::rep relativeIdxTp = ((double)idx / ((double)format.rate/1000.));
return return
tp + tp +
std::chrono::seconds(timestamp.sec) + std::chrono::seconds(timestamp.sec) +
std::chrono::milliseconds(timestamp.usec / 1000) + std::chrono::milliseconds(timestamp.usec / 1000) +
std::chrono::milliseconds(relativeIdxTp); std::chrono::milliseconds(relativeIdxTp);
} }
template<typename T> template<typename T>
inline T getAge() const inline T getAge() const
{ {
return getAge<T>(timePoint()); return getAge<T>(timePoint());
} }
inline long getAge() const inline long getAge() const
{ {
return getAge<std::chrono::milliseconds>().count(); return getAge<std::chrono::milliseconds>().count();
} }
inline static long getAge(const time_point_ms& time_point) inline static long getAge(const time_point_ms& time_point)
{ {
return getAge<std::chrono::milliseconds>(time_point).count(); return getAge<std::chrono::milliseconds>(time_point).count();
} }
template<typename T, typename U> template<typename T, typename U>
static inline T getAge(const std::chrono::time_point<U>& time_point) static inline T getAge(const std::chrono::time_point<U>& time_point)
{ {
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);
} }
int seek(int frames); int seek(int frames);
double getDuration() const; double getDuration() const;
double getDurationUs() const; double getDurationUs() const;
double getTimeLeft() const; double getTimeLeft() const;
double getFrameCount() const; double getFrameCount() const;
SampleFormat format; SampleFormat format;
private: private:
// SampleFormat format_; // SampleFormat format_;
uint32_t idx; uint32_t idx;
}; };

View file

@ -11,81 +11,81 @@ class Queue
{ {
public: public:
T pop() T pop()
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty()) while (queue_.empty())
{ {
cond_.wait(mlock); cond_.wait(mlock);
} }
auto val = queue_.front(); auto val = queue_.front();
queue_.pop(); queue_.pop();
return val; return val;
} }
T front() T front()
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty()) while (queue_.empty())
cond_.wait(mlock); cond_.wait(mlock);
return queue_.front(); return queue_.front();
} }
bool try_pop(T& item, std::chrono::milliseconds timeout) bool try_pop(T& item, std::chrono::milliseconds timeout)
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
if(!cond_.wait_for(mlock, timeout, [this] { return !queue_.empty(); })) if(!cond_.wait_for(mlock, timeout, [this] { return !queue_.empty(); }))
return false; return false;
item = std::move(queue_.front()); item = std::move(queue_.front());
queue_.pop(); queue_.pop();
return true; return true;
} }
void pop(T& item) void pop(T& item)
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty()) while (queue_.empty())
{ {
cond_.wait(mlock); cond_.wait(mlock);
} }
item = queue_.front(); item = queue_.front();
queue_.pop(); queue_.pop();
} }
void push(const T& item) void push(const T& item)
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(item); queue_.push(item);
mlock.unlock(); mlock.unlock();
cond_.notify_one(); cond_.notify_one();
} }
void push(T&& item) void push(T&& item)
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
queue_.push(std::move(item)); queue_.push(std::move(item));
mlock.unlock(); mlock.unlock();
cond_.notify_one(); cond_.notify_one();
} }
size_t size() const size_t size() const
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
return queue_.size(); return queue_.size();
} }
Queue()=default; Queue()=default;
Queue(const Queue&) = delete; // disable copying Queue(const Queue&) = delete; // disable copying
Queue& operator=(const Queue&) = delete; // disable assignment Queue& operator=(const Queue&) = delete; // disable assignment
private: private:
std::queue<T> queue_; std::queue<T> queue_;
mutable std::mutex mutex_; mutable std::mutex mutex_;
std::condition_variable cond_; std::condition_variable cond_;
}; };

View file

@ -8,40 +8,40 @@
class RequestMsg : public BaseMessage class RequestMsg : public BaseMessage
{ {
public: public:
RequestMsg() : BaseMessage(message_type::requestmsg) RequestMsg() : BaseMessage(message_type::requestmsg)
{ {
} }
RequestMsg(const std::string& _request) : BaseMessage(message_type::requestmsg), request(_request) RequestMsg(const std::string& _request) : BaseMessage(message_type::requestmsg), request(_request)
{ {
} }
virtual ~RequestMsg() virtual ~RequestMsg()
{ {
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
int16_t size; int16_t size;
stream.read(reinterpret_cast<char *>(&size), sizeof(int16_t)); stream.read(reinterpret_cast<char *>(&size), sizeof(int16_t));
request.resize(size); request.resize(size);
stream.read(&request[0], size); stream.read(&request[0], size);
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return sizeof(int16_t) + request.size(); return sizeof(int16_t) + request.size();
} }
std::string request; std::string request;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
int16_t size(request.size()); int16_t size(request.size());
stream.write(reinterpret_cast<char *>(&size), sizeof(int16_t)); stream.write(reinterpret_cast<char *>(&size), sizeof(int16_t));
stream.write(request.c_str(), size); stream.write(request.c_str(), size);
} }
}; };

View file

@ -12,37 +12,37 @@ SampleFormat::SampleFormat() : BaseMessage(message_type::sampleformat)
SampleFormat::SampleFormat(const std::string& format) : BaseMessage(message_type::sampleformat) SampleFormat::SampleFormat(const std::string& format) : BaseMessage(message_type::sampleformat)
{ {
setFormat(format); setFormat(format);
} }
SampleFormat::SampleFormat(uint16_t sampleRate, uint16_t bitsPerSample, uint16_t channelCount) : BaseMessage(message_type::sampleformat) SampleFormat::SampleFormat(uint16_t sampleRate, uint16_t bitsPerSample, uint16_t channelCount) : BaseMessage(message_type::sampleformat)
{ {
setFormat(sampleRate, bitsPerSample, channelCount); setFormat(sampleRate, bitsPerSample, channelCount);
} }
void SampleFormat::setFormat(const std::string& format) void SampleFormat::setFormat(const std::string& format)
{ {
std::vector<std::string> strs; std::vector<std::string> strs;
boost::split(strs, format, boost::is_any_of(":")); boost::split(strs, format, boost::is_any_of(":"));
if (strs.size() == 3) if (strs.size() == 3)
setFormat( setFormat(
boost::lexical_cast<uint16_t>(strs[0]), boost::lexical_cast<uint16_t>(strs[0]),
boost::lexical_cast<uint16_t>(strs[1]), boost::lexical_cast<uint16_t>(strs[1]),
boost::lexical_cast<uint16_t>(strs[2])); boost::lexical_cast<uint16_t>(strs[2]));
} }
void SampleFormat::setFormat(uint16_t rate, uint16_t bits, uint16_t channels) void SampleFormat::setFormat(uint16_t rate, uint16_t bits, uint16_t channels)
{ {
this->rate = rate; this->rate = rate;
this->bits = bits; this->bits = bits;
this->channels = channels; this->channels = channels;
sampleSize = bits / 8; sampleSize = bits / 8;
if (bits == 24) if (bits == 24)
sampleSize = 4; sampleSize = 4;
frameSize = channels*sampleSize; frameSize = channels*sampleSize;
} }

View file

@ -8,56 +8,56 @@
class SampleFormat : public BaseMessage class SampleFormat : public BaseMessage
{ {
public: public:
SampleFormat(); SampleFormat();
SampleFormat(const std::string& format); SampleFormat(const std::string& format);
SampleFormat(uint16_t rate, uint16_t bits, uint16_t channels); SampleFormat(uint16_t rate, uint16_t bits, uint16_t channels);
void setFormat(const std::string& format); void setFormat(const std::string& format);
void setFormat(uint16_t rate, uint16_t bits, uint16_t channels); void setFormat(uint16_t rate, uint16_t bits, uint16_t channels);
uint16_t rate; uint16_t rate;
uint16_t bits; uint16_t bits;
uint16_t channels; uint16_t channels;
uint16_t sampleSize; uint16_t sampleSize;
uint16_t frameSize; uint16_t frameSize;
float msRate() const float msRate() const
{ {
return (float)rate/1000.f; return (float)rate/1000.f;
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char *>(&rate), sizeof(uint16_t)); stream.read(reinterpret_cast<char *>(&rate), sizeof(uint16_t));
stream.read(reinterpret_cast<char *>(&bits), sizeof(uint16_t)); stream.read(reinterpret_cast<char *>(&bits), sizeof(uint16_t));
stream.read(reinterpret_cast<char *>(&channels), sizeof(uint16_t)); stream.read(reinterpret_cast<char *>(&channels), sizeof(uint16_t));
stream.read(reinterpret_cast<char *>(&sampleSize), sizeof(uint16_t)); stream.read(reinterpret_cast<char *>(&sampleSize), sizeof(uint16_t));
stream.read(reinterpret_cast<char *>(&frameSize), sizeof(uint16_t)); stream.read(reinterpret_cast<char *>(&frameSize), sizeof(uint16_t));
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return 5*sizeof(int16_t); return 5*sizeof(int16_t);
} }
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char *>(&rate), sizeof(uint16_t)); stream.write(reinterpret_cast<char *>(&rate), sizeof(uint16_t));
stream.write(reinterpret_cast<char *>(&bits), sizeof(uint16_t)); stream.write(reinterpret_cast<char *>(&bits), sizeof(uint16_t));
stream.write(reinterpret_cast<char *>(&channels), sizeof(uint16_t)); stream.write(reinterpret_cast<char *>(&channels), sizeof(uint16_t));
stream.write(reinterpret_cast<char *>(&sampleSize), sizeof(uint16_t)); stream.write(reinterpret_cast<char *>(&sampleSize), sizeof(uint16_t));
stream.write(reinterpret_cast<char *>(&frameSize), sizeof(uint16_t)); stream.write(reinterpret_cast<char *>(&frameSize), sizeof(uint16_t));
} }
/*private: /*private:
uint16_t rate_; uint16_t rate_;
uint16_t bits_; uint16_t bits_;
uint16_t channels_; uint16_t channels_;
uint16_t bytes_; uint16_t bytes_;
uint16_t frameSize_; uint16_t frameSize_;
*/ */
}; };

View file

@ -8,31 +8,31 @@
class ServerSettings : public BaseMessage class ServerSettings : public BaseMessage
{ {
public: public:
ServerSettings(size_t _port = 0) : BaseMessage(message_type::serversettings), port(_port) ServerSettings(size_t _port = 0) : BaseMessage(message_type::serversettings), port(_port)
{ {
} }
virtual ~ServerSettings() virtual ~ServerSettings()
{ {
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char *>(&port), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&port), sizeof(int32_t));
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return sizeof(int32_t); return sizeof(int32_t);
} }
int32_t port; int32_t port;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char *>(&port), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&port), sizeof(int32_t));
} }
}; };

View file

@ -9,19 +9,19 @@ extern bool g_terminated;
void signal_handler(int sig) void signal_handler(int sig)
{ {
switch(sig) switch(sig)
{ {
case SIGHUP: case SIGHUP:
syslog(LOG_WARNING, "Received SIGHUP signal."); syslog(LOG_WARNING, "Received SIGHUP signal.");
break; break;
case SIGTERM: case SIGTERM:
syslog(LOG_WARNING, "Received SIGTERM signal."); syslog(LOG_WARNING, "Received SIGTERM signal.");
g_terminated = true; g_terminated = true;
break; break;
default: default:
syslog(LOG_WARNING, "Unhandled signal "); syslog(LOG_WARNING, "Unhandled signal ");
break; break;
} }
} }
#endif #endif

View file

@ -23,27 +23,35 @@ SocketConnection::~SocketConnection()
void SocketConnection::socketRead(void* _to, size_t _bytes) void SocketConnection::socketRead(void* _to, size_t _bytes)
{ {
// std::unique_lock<std::mutex> mlock(mutex_); // std::unique_lock<std::mutex> mlock(mutex_);
size_t toRead = _bytes; size_t toRead = _bytes;
size_t len = 0; size_t len = 0;
do do
{ {
len += socket->read_some(boost::asio::buffer((char*)_to + len, toRead)); // cout << "/";
toRead = _bytes - len; // cout.flush();
} boost::system::error_code error;
while (toRead > 0); len += socket->read_some(boost::asio::buffer((char*)_to + len, toRead), error);
//cout << "len: " << len << ", error: " << error << endl;
toRead = _bytes - len;
// cout << "\\";
// cout.flush();
}
while (toRead > 0);
} }
void SocketConnection::start() void SocketConnection::start()
{ {
receiverThread = new thread(&SocketConnection::worker, this); receiverThread = new thread(&SocketConnection::worker, this);
} }
void SocketConnection::stop() void SocketConnection::stop()
{ {
active_ = false; active_ = false;
receiverThread->join(); socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket->close();
receiverThread->join();
} }
@ -51,87 +59,87 @@ bool SocketConnection::send(BaseMessage* message)
{ {
// std::unique_lock<std::mutex> mlock(mutex_); // std::unique_lock<std::mutex> mlock(mutex_);
//cout << "send: " << message->type << ", size: " << message->getSize() << "\n"; //cout << "send: " << message->type << ", size: " << message->getSize() << "\n";
if (!connected()) if (!connected())
return false; return false;
//cout << "send: " << message->type << ", size: " << message->getSize() << "\n"; //cout << "send: " << message->type << ", size: " << message->getSize() << "\n";
boost::asio::streambuf streambuf; boost::asio::streambuf streambuf;
std::ostream stream(&streambuf); std::ostream stream(&streambuf);
tv t; tv t;
message->sent = t; message->sent = t;
message->serialize(stream); message->serialize(stream);
boost::asio::write(*socket.get(), streambuf); boost::asio::write(*socket.get(), streambuf);
return true; return true;
} }
shared_ptr<SerializedMessage> SocketConnection::sendRequest(BaseMessage* message, size_t timeout) shared_ptr<SerializedMessage> SocketConnection::sendRequest(BaseMessage* message, size_t timeout)
{ {
shared_ptr<SerializedMessage> response(NULL); shared_ptr<SerializedMessage> response(NULL);
if (++reqId == 0) if (++reqId == 0)
++reqId; ++reqId;
message->id = reqId; message->id = reqId;
shared_ptr<PendingRequest> pendingRequest(new PendingRequest(reqId)); shared_ptr<PendingRequest> pendingRequest(new PendingRequest(reqId));
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
pendingRequests.insert(pendingRequest); pendingRequests.insert(pendingRequest);
} }
// std::mutex mtx; // std::mutex mtx;
std::unique_lock<std::mutex> lck(m); std::unique_lock<std::mutex> lck(m);
send(message); send(message);
if (pendingRequest->cv.wait_for(lck,std::chrono::milliseconds(timeout)) == std::cv_status::no_timeout) if (pendingRequest->cv.wait_for(lck,std::chrono::milliseconds(timeout)) == std::cv_status::no_timeout)
{ {
response = pendingRequest->response; response = pendingRequest->response;
} }
else else
{ {
cout << "timeout while waiting for response to: " << reqId << "\n"; cout << "timeout while waiting for response to: " << reqId << "\n";
} }
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
pendingRequests.erase(pendingRequest); pendingRequests.erase(pendingRequest);
} }
return response; return response;
} }
void SocketConnection::getNextMessage() void SocketConnection::getNextMessage()
{ {
//cout << "getNextMessage\n"; //cout << "getNextMessage\n";
BaseMessage baseMessage; BaseMessage baseMessage;
size_t baseMsgSize = baseMessage.getSize(); size_t baseMsgSize = baseMessage.getSize();
vector<char> buffer(baseMsgSize); vector<char> buffer(baseMsgSize);
socketRead(&buffer[0], baseMsgSize); socketRead(&buffer[0], baseMsgSize);
baseMessage.deserialize(&buffer[0]); baseMessage.deserialize(&buffer[0]);
//cout << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n"; //cout << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n";
if (baseMessage.size > buffer.size()) if (baseMessage.size > buffer.size())
buffer.resize(baseMessage.size); buffer.resize(baseMessage.size);
socketRead(&buffer[0], baseMessage.size); socketRead(&buffer[0], baseMessage.size);
tv t; tv t;
baseMessage.received = t; baseMessage.received = t;
{ {
std::unique_lock<std::mutex> mlock(mutex_); std::unique_lock<std::mutex> mlock(mutex_);
for (auto req: pendingRequests) for (auto req: pendingRequests)
{ {
if (req->id == baseMessage.refersTo) if (req->id == baseMessage.refersTo)
{ {
//cout << "getNextMessage response: " << baseMessage.type << ", size: " << baseMessage.size << "\n"; //cout << "getNextMessage response: " << baseMessage.type << ", size: " << baseMessage.size << "\n";
//long latency = (baseMessage.received.sec - baseMessage.sent.sec) * 1000000 + (baseMessage.received.usec - baseMessage.sent.usec); //long latency = (baseMessage.received.sec - baseMessage.sent.sec) * 1000000 + (baseMessage.received.usec - baseMessage.sent.usec);
//cout << "latency: " << latency << "\n"; //cout << "latency: " << latency << "\n";
req->response.reset(new SerializedMessage()); req->response.reset(new SerializedMessage());
req->response->message = baseMessage; req->response->message = baseMessage;
req->response->buffer = (char*)malloc(baseMessage.size); req->response->buffer = (char*)malloc(baseMessage.size);
memcpy(req->response->buffer, &buffer[0], baseMessage.size); memcpy(req->response->buffer, &buffer[0], baseMessage.size);
std::unique_lock<std::mutex> lck(m); std::unique_lock<std::mutex> lck(m);
req->cv.notify_one(); req->cv.notify_one();
return; return;
} }
} }
} }
if (messageReceiver != NULL) if (messageReceiver != NULL)
messageReceiver->onMessageReceived(this, baseMessage, &buffer[0]); messageReceiver->onMessageReceived(this, baseMessage, &buffer[0]);
} }

View file

@ -20,71 +20,71 @@ class SocketConnection;
struct PendingRequest struct PendingRequest
{ {
PendingRequest(uint16_t reqId) : id(reqId), response(NULL) {}; PendingRequest(uint16_t reqId) : id(reqId), response(NULL) {};
uint16_t id; uint16_t id;
std::shared_ptr<SerializedMessage> response; std::shared_ptr<SerializedMessage> response;
std::condition_variable cv; std::condition_variable cv;
}; };
class MessageReceiver class MessageReceiver
{ {
public: public:
virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer) = 0; virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer) = 0;
}; };
class SocketConnection class SocketConnection
{ {
public: public:
SocketConnection(MessageReceiver* _receiver); SocketConnection(MessageReceiver* _receiver);
virtual ~SocketConnection(); virtual ~SocketConnection();
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool send(BaseMessage* _message); virtual bool send(BaseMessage* _message);
virtual std::shared_ptr<SerializedMessage> sendRequest(BaseMessage* message, size_t timeout); virtual std::shared_ptr<SerializedMessage> sendRequest(BaseMessage* message, size_t timeout);
template <typename T> template <typename T>
std::shared_ptr<T> sendReq(BaseMessage* message, size_t timeout) std::shared_ptr<T> sendReq(BaseMessage* message, size_t timeout)
{ {
std::shared_ptr<SerializedMessage> reply = sendRequest(message, timeout); std::shared_ptr<SerializedMessage> reply = sendRequest(message, timeout);
if (!reply) if (!reply)
return NULL; return NULL;
std::shared_ptr<T> msg(new T); std::shared_ptr<T> msg(new T);
msg->deserialize(reply->message, reply->buffer); msg->deserialize(reply->message, reply->buffer);
return msg; return msg;
} }
virtual bool active() virtual bool active()
{ {
return active_; return active_;
} }
virtual bool connected() virtual bool connected()
{ {
return (socket != 0); return (socket != 0);
// return (connected_ && socket); // return (connected_ && socket);
} }
protected: protected:
virtual void worker() = 0; virtual void worker() = 0;
void socketRead(void* _to, size_t _bytes); void socketRead(void* _to, size_t _bytes);
std::shared_ptr<tcp::socket> socket; std::shared_ptr<tcp::socket> socket;
// boost::asio::ip::tcp::endpoint endpt; // boost::asio::ip::tcp::endpoint endpt;
std::atomic<bool> active_; std::atomic<bool> active_;
std::atomic<bool> connected_; std::atomic<bool> connected_;
MessageReceiver* messageReceiver; MessageReceiver* messageReceiver;
void getNextMessage(); void getNextMessage();
boost::asio::io_service io_service; boost::asio::io_service io_service;
tcp::resolver::iterator iterator; tcp::resolver::iterator iterator;
std::thread* receiverThread; std::thread* receiverThread;
mutable std::mutex mutex_; mutable std::mutex mutex_;
std::mutex m; std::mutex m;
std::set<std::shared_ptr<PendingRequest>> pendingRequests; std::set<std::shared_ptr<PendingRequest>> pendingRequests;
uint16_t reqId; uint16_t reqId;
}; };

View file

@ -7,31 +7,31 @@
class TimeMsg : public BaseMessage class TimeMsg : public BaseMessage
{ {
public: public:
TimeMsg() : BaseMessage(message_type::timemsg) TimeMsg() : BaseMessage(message_type::timemsg)
{ {
} }
virtual ~TimeMsg() virtual ~TimeMsg()
{ {
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char *>(&latency), sizeof(double)); stream.read(reinterpret_cast<char *>(&latency), sizeof(double));
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return sizeof(double); return sizeof(double);
} }
double latency; double latency;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char *>(&latency), sizeof(double)); stream.write(reinterpret_cast<char *>(&latency), sizeof(double));
} }
}; };

View file

@ -48,32 +48,32 @@ inline static long getAge(const time_point_ms& time_point)
static void addMs(timeval& tv, int ms) static void addMs(timeval& tv, int ms)
{ {
if (ms < 0) if (ms < 0)
{ {
timeval t; timeval t;
t.tv_sec = -ms / 1000; t.tv_sec = -ms / 1000;
t.tv_usec = (-ms % 1000) * 1000; t.tv_usec = (-ms % 1000) * 1000;
timersub(&tv, &t, &tv); timersub(&tv, &t, &tv);
return; return;
} }
tv.tv_usec += ms*1000; tv.tv_usec += ms*1000;
tv.tv_sec += (tv.tv_usec / 1000000); tv.tv_sec += (tv.tv_usec / 1000000);
tv.tv_usec %= 1000000; tv.tv_usec %= 1000000;
} }
static void addUs(timeval& tv, int us) static void addUs(timeval& tv, int us)
{ {
if (us < 0) if (us < 0)
{ {
timeval t; timeval t;
t.tv_sec = -us / 1000000; t.tv_sec = -us / 1000000;
t.tv_usec = (-us % 1000000); t.tv_usec = (-us % 1000000);
timersub(&tv, &t, &tv); timersub(&tv, &t, &tv);
return; return;
} }
tv.tv_usec += us; tv.tv_usec += us;
tv.tv_sec += (tv.tv_usec / 1000000); tv.tv_sec += (tv.tv_usec / 1000000);
tv.tv_usec %= 1000000; tv.tv_usec %= 1000000;
} }
@ -86,17 +86,17 @@ static void addUs(timeval& tv, int us)
static long getTickCount() static long getTickCount()
{ {
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec*1000 + now.tv_nsec / 1000000; return now.tv_sec*1000 + now.tv_nsec / 1000000;
} }
static long getuTickCount() static long getuTickCount()
{ {
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec*1000000 + now.tv_nsec / 1000; return now.tv_sec*1000000 + now.tv_nsec / 1000;
} }

View file

@ -15,81 +15,81 @@
// trim from start // trim from start
static inline std::string &ltrim(std::string &s) static inline std::string &ltrim(std::string &s)
{ {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace)))); s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
return s; return s;
} }
// trim from end // trim from end
static inline std::string &rtrim(std::string &s) static inline std::string &rtrim(std::string &s)
{ {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s; return s;
} }
// trim from both ends // trim from both ends
static inline std::string &trim(std::string &s) static inline std::string &trim(std::string &s)
{ {
return ltrim(rtrim(s)); return ltrim(rtrim(s));
} }
static std::string getMacAddress() static std::string getMacAddress()
{ {
std::ifstream t("/sys/class/net/eth0/address"); std::ifstream t("/sys/class/net/eth0/address");
std::string str((std::istreambuf_iterator<char>(t)), std::string str((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>()); std::istreambuf_iterator<char>());
return trim(str); return trim(str);
} }
std::vector<std::string> split(const std::string& str) std::vector<std::string> split(const std::string& str)
{ {
std::istringstream iss(str); std::istringstream iss(str);
std::vector<std::string> splitStr; std::vector<std::string> splitStr;
std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter<std::vector<std::string> >(splitStr)); std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter<std::vector<std::string> >(splitStr));
return splitStr; return splitStr;
} }
static void daemonize() static void daemonize()
{ {
/* Our process ID and Session ID */ /* Our process ID and Session ID */
pid_t pid, sid; pid_t pid, sid;
/* Fork off the parent process */ /* Fork off the parent process */
pid = fork(); pid = fork();
if (pid < 0) if (pid < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* If we got a good PID, then /* If we got a good PID, then
we can exit the parent process. */ we can exit the parent process. */
if (pid > 0) if (pid > 0)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
/* Change the file mode mask */ /* Change the file mode mask */
umask(0); umask(0);
/* Open any logs here */ /* Open any logs here */
/* Create a new SID for the child process */ /* Create a new SID for the child process */
sid = setsid(); sid = setsid();
if (sid < 0) if (sid < 0)
{ {
/* Log the failure */ /* Log the failure */
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Change the current working directory */ /* Change the current working directory */
if ((chdir("/")) < 0) if ((chdir("/")) < 0)
{ {
/* Log the failure */ /* Log the failure */
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Close out the standard file descriptors */ /* Close out the standard file descriptors */
close(STDIN_FILENO); close(STDIN_FILENO);
close(STDOUT_FILENO); close(STDOUT_FILENO);
close(STDERR_FILENO); close(STDERR_FILENO);
} }

View file

@ -13,42 +13,42 @@
class WireChunk : public BaseMessage class WireChunk : public BaseMessage
{ {
public: public:
WireChunk(size_t size = 0) : BaseMessage(message_type::payload), payloadSize(size) WireChunk(size_t size = 0) : BaseMessage(message_type::payload), payloadSize(size)
{ {
payload = (char*)malloc(size); payload = (char*)malloc(size);
} }
virtual ~WireChunk() virtual ~WireChunk()
{ {
free(payload); free(payload);
} }
virtual void read(std::istream& stream) virtual void read(std::istream& stream)
{ {
stream.read(reinterpret_cast<char *>(&timestamp.sec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&timestamp.sec), sizeof(int32_t));
stream.read(reinterpret_cast<char *>(&timestamp.usec), sizeof(int32_t)); stream.read(reinterpret_cast<char *>(&timestamp.usec), sizeof(int32_t));
stream.read(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t)); stream.read(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t));
payload = (char*)realloc(payload, payloadSize); payload = (char*)realloc(payload, payloadSize);
stream.read(payload, payloadSize); stream.read(payload, payloadSize);
} }
virtual uint32_t getSize() virtual uint32_t getSize()
{ {
return sizeof(int32_t) + sizeof(int32_t) + sizeof(uint32_t) + payloadSize; return sizeof(int32_t) + sizeof(int32_t) + sizeof(uint32_t) + payloadSize;
} }
tv timestamp; tv timestamp;
uint32_t payloadSize; uint32_t payloadSize;
char* payload; char* payload;
protected: protected:
virtual void doserialize(std::ostream& stream) virtual void doserialize(std::ostream& stream)
{ {
stream.write(reinterpret_cast<char *>(&timestamp.sec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&timestamp.sec), sizeof(int32_t));
stream.write(reinterpret_cast<char *>(&timestamp.usec), sizeof(int32_t)); stream.write(reinterpret_cast<char *>(&timestamp.usec), sizeof(int32_t));
stream.write(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t)); stream.write(reinterpret_cast<char *>(&payloadSize), sizeof(uint32_t));
stream.write(payload, payloadSize); stream.write(payload, payloadSize);
} }
}; };

View file

@ -12,63 +12,63 @@ ControlServer::ControlServer(unsigned short port) : port_(port), headerChunk(NUL
void ControlServer::onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer) void ControlServer::onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer)
{ {
// cout << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," << baseMessage.received.usec << "\n"; // cout << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," << baseMessage.received.usec << "\n";
if (baseMessage.type == message_type::requestmsg) if (baseMessage.type == message_type::requestmsg)
{ {
RequestMsg requestMsg; RequestMsg requestMsg;
requestMsg.deserialize(baseMessage, buffer); requestMsg.deserialize(baseMessage, buffer);
cout << "request: " << requestMsg.request << "\n"; cout << "request: " << requestMsg.request << "\n";
if (requestMsg.request == "time") if (requestMsg.request == "time")
{ {
// timeMsg.latency = (timeMsg.received.sec - timeMsg.sent.sec) * 1000000 + (timeMsg.received.usec - timeMsg.sent.usec); // timeMsg.latency = (timeMsg.received.sec - timeMsg.sent.sec) * 1000000 + (timeMsg.received.usec - timeMsg.sent.usec);
TimeMsg timeMsg; TimeMsg timeMsg;
timeMsg.refersTo = requestMsg.id; timeMsg.refersTo = requestMsg.id;
timeMsg.latency = (requestMsg.received.sec - requestMsg.sent.sec) + (requestMsg.received.usec - requestMsg.sent.usec) / 1000000.; timeMsg.latency = (requestMsg.received.sec - requestMsg.sent.sec) + (requestMsg.received.usec - requestMsg.sent.usec) / 1000000.;
// tv diff = timeMsg.received - timeMsg.sent; // tv diff = timeMsg.received - timeMsg.sent;
// cout << "Latency: " << diff.sec << "." << diff.usec << "\n"; // cout << "Latency: " << diff.sec << "." << diff.usec << "\n";
connection->send(&timeMsg); connection->send(&timeMsg);
} }
else if (requestMsg.request == "serverSettings") else if (requestMsg.request == "serverSettings")
{ {
serverSettings->refersTo = requestMsg.id; serverSettings->refersTo = requestMsg.id;
connection->send(serverSettings); connection->send(serverSettings);
} }
else if (requestMsg.request == "sampleFormat") else if (requestMsg.request == "sampleFormat")
{ {
sampleFormat->refersTo = requestMsg.id; sampleFormat->refersTo = requestMsg.id;
connection->send(sampleFormat); connection->send(sampleFormat);
} }
else if (requestMsg.request == "headerChunk") else if (requestMsg.request == "headerChunk")
{ {
headerChunk->refersTo = requestMsg.id; headerChunk->refersTo = requestMsg.id;
connection->send(headerChunk); connection->send(headerChunk);
} }
} }
} }
void ControlServer::acceptor() void ControlServer::acceptor()
{ {
tcp::acceptor a(io_service_, tcp::endpoint(tcp::v4(), port_)); tcp::acceptor a(io_service_, tcp::endpoint(tcp::v4(), port_));
for (;;) for (;;)
{ {
socket_ptr sock(new tcp::socket(io_service_)); socket_ptr sock(new tcp::socket(io_service_));
struct timeval tv; struct timeval tv;
tv.tv_sec = 5; tv.tv_sec = 5;
tv.tv_usec = 0; tv.tv_usec = 0;
setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); a.accept(*sock);
setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
a.accept(*sock); setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
cout << "ControlServer::NewConnection: " << sock->remote_endpoint().address().to_string() << "\n"; cout << "ControlServer::NewConnection: " << sock->remote_endpoint().address().to_string() << "\n";
ServerConnection* session = new ServerConnection(this, sock); ServerConnection* session = new ServerConnection(this, sock);
sessions.insert(shared_ptr<ServerConnection>(session)); sessions.insert(shared_ptr<ServerConnection>(session));
session->start(); session->start();
} }
} }
void ControlServer::start() void ControlServer::start()
{ {
acceptThread = new thread(&ControlServer::acceptor, this); acceptThread = new thread(&ControlServer::acceptor, this);
} }
@ -80,23 +80,23 @@ void ControlServer::stop()
void ControlServer::setHeader(HeaderMessage* header) void ControlServer::setHeader(HeaderMessage* header)
{ {
if (header) if (header)
headerChunk = header; headerChunk = header;
} }
void ControlServer::setFormat(SampleFormat* format) void ControlServer::setFormat(SampleFormat* format)
{ {
if (format) if (format)
sampleFormat = format; sampleFormat = format;
} }
void ControlServer::setServerSettings(ServerSettings* settings) void ControlServer::setServerSettings(ServerSettings* settings)
{ {
if (settings) if (settings)
serverSettings = settings; serverSettings = settings;
} }

View file

@ -25,24 +25,24 @@ using namespace std;
class ControlServer : public MessageReceiver class ControlServer : public MessageReceiver
{ {
public: public:
ControlServer(unsigned short port); ControlServer(unsigned short port);
void start(); void start();
void stop(); void stop();
virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer); virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer);
void setHeader(HeaderMessage* header); void setHeader(HeaderMessage* header);
void setFormat(SampleFormat* format); void setFormat(SampleFormat* format);
void setServerSettings(ServerSettings* settings); void setServerSettings(ServerSettings* settings);
private: private:
void acceptor(); void acceptor();
set<shared_ptr<ServerConnection>> sessions; set<shared_ptr<ServerConnection>> sessions;
boost::asio::io_service io_service_; boost::asio::io_service io_service_;
unsigned short port_; unsigned short port_;
HeaderMessage* headerChunk; HeaderMessage* headerChunk;
SampleFormat* sampleFormat; SampleFormat* sampleFormat;
ServerSettings* serverSettings; ServerSettings* serverSettings;
thread* acceptThread; thread* acceptThread;
}; };

View file

@ -8,18 +8,18 @@
class Encoder class Encoder
{ {
public: public:
Encoder(const SampleFormat& format) : sampleFormat(format) Encoder(const SampleFormat& format) : sampleFormat(format)
{ {
} }
virtual double encode(PcmChunk* chunk) = 0; virtual double encode(PcmChunk* chunk) = 0;
virtual HeaderMessage* getHeader() virtual HeaderMessage* getHeader()
{ {
return NULL; return NULL;
} }
protected: protected:
SampleFormat sampleFormat; SampleFormat sampleFormat;
}; };

View file

@ -7,183 +7,183 @@ using namespace std;
OggEncoder::OggEncoder(const SampleFormat& format) : Encoder(format), headerChunk(NULL) OggEncoder::OggEncoder(const SampleFormat& format) : Encoder(format), headerChunk(NULL)
{ {
init(); init();
lastGranulepos = -1; lastGranulepos = -1;
} }
HeaderMessage* OggEncoder::getHeader() HeaderMessage* OggEncoder::getHeader()
{ {
return headerChunk; return headerChunk;
} }
double OggEncoder::encode(PcmChunk* chunk) double OggEncoder::encode(PcmChunk* chunk)
{ {
double res = 0; double res = 0;
if (tv_sec == 0) if (tv_sec == 0)
{ {
tv_sec = chunk->timestamp.sec; tv_sec = chunk->timestamp.sec;
tv_usec = chunk->timestamp.usec; tv_usec = chunk->timestamp.usec;
} }
//cout << "-> pcm: " << wireChunk->length << endl; //cout << "-> pcm: " << wireChunk->length << endl;
int bytes = chunk->payloadSize / 4; int bytes = chunk->payloadSize / 4;
float **buffer=vorbis_analysis_buffer(&vd, bytes); float **buffer=vorbis_analysis_buffer(&vd, bytes);
/* uninterleave samples */ /* uninterleave samples */
for(int i=0; i<bytes; i++) for(int i=0; i<bytes; i++)
{ {
buffer[0][i]=((chunk->payload[i*4+1]<<8)| buffer[0][i]=((chunk->payload[i*4+1]<<8)|
(0x00ff&(int)chunk->payload[i*4]))/32768.f; (0x00ff&(int)chunk->payload[i*4]))/32768.f;
buffer[1][i]=((chunk->payload[i*4+3]<<8)| buffer[1][i]=((chunk->payload[i*4+3]<<8)|
(0x00ff&(int)chunk->payload[i*4+2]))/32768.f; (0x00ff&(int)chunk->payload[i*4+2]))/32768.f;
} }
/* tell the library how much we actually submitted */ /* tell the library how much we actually submitted */
vorbis_analysis_wrote(&vd, bytes); vorbis_analysis_wrote(&vd, bytes);
/* vorbis does some data preanalysis, then divvies up blocks for /* vorbis does some data preanalysis, then divvies up blocks for
more involved (potentially parallel) processing. Get a single more involved (potentially parallel) processing. Get a single
block for encoding now */ block for encoding now */
size_t pos = 0; size_t pos = 0;
while(vorbis_analysis_blockout(&vd,&vb)==1) while(vorbis_analysis_blockout(&vd,&vb)==1)
{ {
/* analysis, assume we want to use bitrate management */ /* analysis, assume we want to use bitrate management */
vorbis_analysis(&vb,NULL); vorbis_analysis(&vb,NULL);
vorbis_bitrate_addblock(&vb); vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)) while(vorbis_bitrate_flushpacket(&vd,&op))
{ {
/* weld the packet into the bitstream */ /* weld the packet into the bitstream */
ogg_stream_packetin(&os,&op); ogg_stream_packetin(&os,&op);
/* write out pages (if any) */ /* write out pages (if any) */
while(true) while(true)
{ {
// int result = ogg_stream_pageout(&os,&og); // int result = ogg_stream_pageout(&os,&og);
int result = ogg_stream_flush(&os,&og); int result = ogg_stream_flush(&os,&og);
if (result == 0) if (result == 0)
break; break;
res = true; res = true;
size_t nextLen = pos + og.header_len + og.body_len; size_t nextLen = pos + og.header_len + og.body_len;
if (chunk->payloadSize < nextLen) if (chunk->payloadSize < nextLen)
chunk->payload = (char*)realloc(chunk->payload, nextLen); chunk->payload = (char*)realloc(chunk->payload, nextLen);
memcpy(chunk->payload + pos, og.header, og.header_len); memcpy(chunk->payload + pos, og.header, og.header_len);
pos += og.header_len; pos += og.header_len;
memcpy(chunk->payload + pos, og.body, og.body_len); memcpy(chunk->payload + pos, og.body, og.body_len);
pos += og.body_len; pos += og.body_len;
} }
} }
} }
if (res) if (res)
{ {
if (lastGranulepos == -1) if (lastGranulepos == -1)
res = os.granulepos; res = os.granulepos;
else else
res = os.granulepos - lastGranulepos; res = os.granulepos - lastGranulepos;
res /= 48.; res /= 48.;
lastGranulepos = os.granulepos; lastGranulepos = os.granulepos;
chunk->payload = (char*)realloc(chunk->payload, pos); chunk->payload = (char*)realloc(chunk->payload, pos);
chunk->payloadSize = pos; chunk->payloadSize = pos;
tv_sec = 0; tv_sec = 0;
tv_usec = 0; tv_usec = 0;
} }
return res; return res;
} }
void OggEncoder::init() void OggEncoder::init()
{ {
/********** Encode setup ************/ /********** Encode setup ************/
tv_sec = 0; tv_sec = 0;
tv_usec = 0; tv_usec = 0;
vorbis_info_init(&vi); vorbis_info_init(&vi);
/* choose an encoding mode. A few possibilities commented out, one /* choose an encoding mode. A few possibilities commented out, one
actually used: */ actually used: */
/********************************************************************* /*********************************************************************
Encoding using a VBR quality mode. The usable range is -.1 Encoding using a VBR quality mode. The usable range is -.1
(lowest quality, smallest file) to 1. (highest quality, largest file). (lowest quality, smallest file) to 1. (highest quality, largest file).
Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR
ret = vorbis_encode_init_vbr(&vi,2,44100,.4); ret = vorbis_encode_init_vbr(&vi,2,44100,.4);
--------------------------------------------------------------------- ---------------------------------------------------------------------
Encoding using an average bitrate mode (ABR). Encoding using an average bitrate mode (ABR).
example: 44kHz stereo coupled, average 128kbps VBR example: 44kHz stereo coupled, average 128kbps VBR
ret = vorbis_encode_init(&vi,2,44100,-1,128000,-1); ret = vorbis_encode_init(&vi,2,44100,-1,128000,-1);
--------------------------------------------------------------------- ---------------------------------------------------------------------
Encode using a quality mode, but select that quality mode by asking for Encode using a quality mode, but select that quality mode by asking for
an approximate bitrate. This is not ABR, it is true VBR, but selected an approximate bitrate. This is not ABR, it is true VBR, but selected
using the bitrate interface, and then turning bitrate management off: using the bitrate interface, and then turning bitrate management off:
ret = ( vorbis_encode_setup_managed(&vi,2,44100,-1,128000,-1) || ret = ( vorbis_encode_setup_managed(&vi,2,44100,-1,128000,-1) ||
vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE2_SET,NULL) || vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE2_SET,NULL) ||
vorbis_encode_setup_init(&vi)); vorbis_encode_setup_init(&vi));
*********************************************************************/ *********************************************************************/
ret=vorbis_encode_init_vbr(&vi, sampleFormat.channels, sampleFormat.rate, 0.7); ret=vorbis_encode_init_vbr(&vi, sampleFormat.channels, sampleFormat.rate, 0.7);
/* do not continue if setup failed; this can happen if we ask for a /* do not continue if setup failed; this can happen if we ask for a
mode that libVorbis does not support (eg, too low a bitrate, etc, mode that libVorbis does not support (eg, too low a bitrate, etc,
will return 'OV_EIMPL') */ will return 'OV_EIMPL') */
if(ret)exit(1); if(ret)exit(1);
/* add a comment */ /* add a comment */
vorbis_comment_init(&vc); vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc,"ENCODER","snapstream"); vorbis_comment_add_tag(&vc,"ENCODER","snapstream");
/* set up the analysis state and auxiliary encoding storage */ /* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init(&vd,&vi); vorbis_analysis_init(&vd,&vi);
vorbis_block_init(&vd,&vb); vorbis_block_init(&vd,&vb);
/* set up our packet->stream encoder */ /* set up our packet->stream encoder */
/* pick a random serial number; that way we can more likely build /* pick a random serial number; that way we can more likely build
chained streams just by concatenation */ chained streams just by concatenation */
srand(time(NULL)); srand(time(NULL));
ogg_stream_init(&os,rand()); ogg_stream_init(&os,rand());
/* Vorbis streams begin with three headers; the initial header (with /* Vorbis streams begin with three headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg most of the codec setup parameters) which is mandated by the Ogg
bitstream spec. The second header holds any comment fields. The bitstream spec. The second header holds any comment fields. The
third header holds the bitstream codebook. We merely need to third header holds the bitstream codebook. We merely need to
make the headers, then pass them to libvorbis one at a time; make the headers, then pass them to libvorbis one at a time;
libvorbis handles the additional Ogg bitstream constraints */ libvorbis handles the additional Ogg bitstream constraints */
vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
ogg_stream_packetin(&os,&header); ogg_stream_packetin(&os,&header);
ogg_stream_packetin(&os,&header_comm); ogg_stream_packetin(&os,&header_comm);
ogg_stream_packetin(&os,&header_code); ogg_stream_packetin(&os,&header_code);
/* This ensures the actual /* This ensures the actual
* audio data will start on a new page, as per spec * audio data will start on a new page, as per spec
*/ */
// while(!eos){ // while(!eos){
size_t pos(0); size_t pos(0);
headerChunk = new HeaderMessage(); headerChunk = new HeaderMessage();
while (true) while (true)
{ {
int result=ogg_stream_flush(&os,&og); int result=ogg_stream_flush(&os,&og);
if (result == 0) if (result == 0)
break; break;
headerChunk->payloadSize += og.header_len + og.body_len; headerChunk->payloadSize += og.header_len + og.body_len;
headerChunk->payload = (char*)realloc(headerChunk->payload, headerChunk->payloadSize); headerChunk->payload = (char*)realloc(headerChunk->payload, headerChunk->payloadSize);
cout << "HeadLen: " << og.header_len << ", bodyLen: " << og.body_len << ", result: " << result << "\n"; cout << "HeadLen: " << og.header_len << ", bodyLen: " << og.body_len << ", result: " << result << "\n";
memcpy(headerChunk->payload + pos, og.header, og.header_len); memcpy(headerChunk->payload + pos, og.header, og.header_len);
pos += og.header_len; pos += og.header_len;
memcpy(headerChunk->payload + pos, og.body, og.body_len); memcpy(headerChunk->payload + pos, og.body, og.body_len);
pos += og.body_len; pos += og.body_len;
} }
// fwrite(og.header,1,og.header_len,stdout); // fwrite(og.header,1,og.header_len,stdout);

View file

@ -7,37 +7,37 @@
class OggEncoder : public Encoder class OggEncoder : public Encoder
{ {
public: public:
OggEncoder(const SampleFormat& format); OggEncoder(const SampleFormat& format);
virtual double encode(PcmChunk* chunk); virtual double encode(PcmChunk* chunk);
virtual HeaderMessage* getHeader(); virtual HeaderMessage* getHeader();
private: private:
void init(); void init();
ogg_stream_state os; /* take physical pages, weld into a logical ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */ stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */ ogg_packet op; /* one raw packet of data for decode */
vorbis_info vi; /* struct that stores all the static vorbis bitstream vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */ settings */
vorbis_comment vc; /* struct that stores all the user comments */ vorbis_comment vc; /* struct that stores all the user comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */ vorbis_block vb; /* local working space for packet->PCM decode */
ogg_packet header; ogg_packet header;
ogg_packet header_comm; ogg_packet header_comm;
ogg_packet header_code; ogg_packet header_code;
ogg_int64_t lastGranulepos; ogg_int64_t lastGranulepos;
HeaderMessage* headerChunk; HeaderMessage* headerChunk;
int eos=0,ret; int eos=0,ret;
int i, founddata; int i, founddata;
int32_t tv_sec; int32_t tv_sec;
int32_t tv_usec; int32_t tv_usec;
}; };

View file

@ -7,11 +7,11 @@ PcmEncoder::PcmEncoder(const SampleFormat& format) : Encoder(format)
double PcmEncoder::encode(PcmChunk* chunk) double PcmEncoder::encode(PcmChunk* chunk)
{ {
/* WireChunk* wireChunk = chunk->wireChunk; /* WireChunk* wireChunk = chunk->wireChunk;
for (size_t n=0; n<wireChunk->length; ++n) for (size_t n=0; n<wireChunk->length; ++n)
wireChunk->payload[n] *= 1; wireChunk->payload[n] *= 1;
*/ */
return chunk->getDuration(); return chunk->getDuration();
} }

View file

@ -6,8 +6,8 @@
class PcmEncoder : public Encoder class PcmEncoder : public Encoder
{ {
public: public:
PcmEncoder(const SampleFormat& format); PcmEncoder(const SampleFormat& format);
virtual double encode(PcmChunk* chunk); virtual double encode(PcmChunk* chunk);
}; };

View file

@ -11,25 +11,25 @@ using namespace std;
ServerConnection::ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket) : SocketConnection(_receiver) ServerConnection::ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket) : SocketConnection(_receiver)
{ {
socket = _socket; socket = _socket;
} }
void ServerConnection::worker() void ServerConnection::worker()
{ {
active_ = true; active_ = true;
try try
{ {
while (active_) while (active_)
{ {
getNextMessage(); getNextMessage();
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl; cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl;
} }
active_ = false; active_ = false;
} }

View file

@ -12,10 +12,10 @@ using boost::asio::ip::tcp;
class ServerConnection : public SocketConnection class ServerConnection : public SocketConnection
{ {
public: public:
ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket); ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket);
protected: protected:
virtual void worker(); virtual void worker();
}; };

View file

@ -22,133 +22,133 @@ using namespace std;
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
try try
{ {
string sampleFormat; string sampleFormat;
size_t port; size_t port;
string fifoName; string fifoName;
string codec; string codec;
bool runAsDaemon; bool runAsDaemon;
po::options_description desc("Allowed options"); po::options_description desc("Allowed options");
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")
("sampleformat,s", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format") ("sampleformat,s", po::value<string>(&sampleFormat)->default_value("48000:16:2"), "sample format")
("codec,c", po::value<string>(&codec)->default_value("ogg"), "transport codec [ogg|pcm]") ("codec,c", po::value<string>(&codec)->default_value("ogg"), "transport codec [ogg|pcm]")
("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")
; ;
po::variables_map vm; po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm); po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm); po::notify(vm);
if (vm.count("help")) if (vm.count("help"))
{ {
cout << desc << "\n"; cout << desc << "\n";
return 1; return 1;
} }
if (runAsDaemon) if (runAsDaemon)
{ {
daemonize(); daemonize();
syslog (LOG_NOTICE, "First daemon started."); syslog (LOG_NOTICE, "First daemon started.");
} }
openlog ("firstdaemon", LOG_PID, LOG_DAEMON); openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
using namespace std; // For atoi. using namespace std; // For atoi.
timeval tvChunk; timeval tvChunk;
gettimeofday(&tvChunk, NULL); gettimeofday(&tvChunk, NULL);
long nextTick = getTickCount(); long nextTick = getTickCount();
mkfifo(fifoName.c_str(), 0777); mkfifo(fifoName.c_str(), 0777);
SampleFormat format(sampleFormat); SampleFormat format(sampleFormat);
size_t duration = 50; size_t duration = 50;
//size_t chunkSize = duration*format.rate*format.frameSize / 1000; //size_t chunkSize = duration*format.rate*format.frameSize / 1000;
std::auto_ptr<Encoder> encoder; std::auto_ptr<Encoder> encoder;
if (codec == "ogg") if (codec == "ogg")
encoder.reset(new OggEncoder(sampleFormat)); encoder.reset(new OggEncoder(sampleFormat));
else if (codec == "pcm") else if (codec == "pcm")
encoder.reset(new PcmEncoder(sampleFormat)); encoder.reset(new PcmEncoder(sampleFormat));
else else
{ {
cout << "unknown codec: " << codec << "\n"; cout << "unknown codec: " << codec << "\n";
return 1; return 1;
} }
std::auto_ptr<ServerSettings> serverSettings(new ServerSettings(port + 1)); std::auto_ptr<ServerSettings> serverSettings(new ServerSettings(port + 1));
ControlServer* controlServer = new ControlServer(port); ControlServer* controlServer = new ControlServer(port);
controlServer->setServerSettings(serverSettings.get()); controlServer->setServerSettings(serverSettings.get());
controlServer->setFormat(&format); controlServer->setFormat(&format);
controlServer->setHeader(encoder->getHeader()); controlServer->setHeader(encoder->getHeader());
controlServer->start(); controlServer->start();
StreamServer* server = new StreamServer(port + 1); StreamServer* server = new StreamServer(port + 1);
server->start(); server->start();
while (!g_terminated) while (!g_terminated)
{ {
int fd = open(fifoName.c_str(), O_RDONLY); int fd = open(fifoName.c_str(), O_RDONLY);
try try
{ {
shared_ptr<PcmChunk> chunk;//(new WireChunk()); shared_ptr<PcmChunk> chunk;//(new WireChunk());
while (true)//cin.good()) while (true)//cin.good())
{ {
chunk.reset(new PcmChunk(sampleFormat, duration));//2*WIRE_CHUNK_SIZE)); chunk.reset(new PcmChunk(sampleFormat, duration));//2*WIRE_CHUNK_SIZE));
int toRead = chunk->payloadSize; int toRead = chunk->payloadSize;
int len = 0; int len = 0;
do do
{ {
int count = read(fd, chunk->payload + len, toRead - len); int count = read(fd, chunk->payload + len, toRead - len);
if (count <= 0) if (count <= 0)
throw ServerException("count = " + boost::lexical_cast<string>(count)); throw ServerException("count = " + boost::lexical_cast<string>(count));
len += count; len += count;
} }
while (len < toRead); while (len < toRead);
chunk->timestamp.sec = tvChunk.tv_sec; chunk->timestamp.sec = tvChunk.tv_sec;
chunk->timestamp.usec = tvChunk.tv_usec; chunk->timestamp.usec = tvChunk.tv_usec;
double chunkDuration = encoder->encode(chunk.get()); double chunkDuration = encoder->encode(chunk.get());
if (chunkDuration > 0) if (chunkDuration > 0)
server->send(chunk); server->send(chunk);
//cout << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n"; //cout << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
// addUs(tvChunk, 1000*chunk->getDuration()); // addUs(tvChunk, 1000*chunk->getDuration());
addUs(tvChunk, chunkDuration * 1000); addUs(tvChunk, chunkDuration * 1000);
nextTick += duration; nextTick += duration;
long currentTick = getTickCount(); long currentTick = getTickCount();
if (nextTick > currentTick) if (nextTick > currentTick)
{ {
usleep((nextTick - currentTick) * 1000); usleep((nextTick - currentTick) * 1000);
} }
else else
{ {
gettimeofday(&tvChunk, NULL); gettimeofday(&tvChunk, NULL);
nextTick = getTickCount(); nextTick = getTickCount();
} }
} }
} }
catch(const std::exception& e) catch(const std::exception& e)
{ {
std::cerr << "Exception: " << e.what() << std::endl; std::cerr << "Exception: " << e.what() << std::endl;
} }
close(fd); close(fd);
} }
server->stop(); server->stop();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
std::cerr << "Exception: " << e.what() << std::endl; std::cerr << "Exception: " << e.what() << std::endl;
} }
syslog (LOG_NOTICE, "First daemon terminated."); syslog (LOG_NOTICE, "First daemon terminated.");
closelog(); closelog();
} }

View file

@ -9,34 +9,34 @@ StreamSession::StreamSession(std::shared_ptr<tcp::socket> _socket) : ServerConne
void StreamSession::worker() void StreamSession::worker()
{ {
active_ = true; active_ = true;
try try
{ {
boost::asio::streambuf streambuf; boost::asio::streambuf streambuf;
std::ostream stream(&streambuf); std::ostream stream(&streambuf);
for (;;) for (;;)
{ {
shared_ptr<BaseMessage> message(messages.pop()); shared_ptr<BaseMessage> message(messages.pop());
ServerConnection::send(message.get()); ServerConnection::send(message.get());
} }
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::cerr << "Exception in thread: " << e.what() << "\n"; std::cerr << "Exception in thread: " << e.what() << "\n";
active_ = false; active_ = false;
} }
active_ = false; active_ = false;
} }
void StreamSession::send(shared_ptr<BaseMessage> message) void StreamSession::send(shared_ptr<BaseMessage> message)
{ {
if (!message) if (!message)
return; return;
while (messages.size() > 100)// chunk->getDuration() > 10000) while (messages.size() > 100)// chunk->getDuration() > 10000)
messages.pop(); messages.pop();
messages.push(message); messages.push(message);
} }
@ -50,45 +50,45 @@ StreamServer::StreamServer(unsigned short port) : port_(port), headerChunk(NULL)
void StreamServer::acceptor() void StreamServer::acceptor()
{ {
tcp::acceptor a(io_service_, tcp::endpoint(tcp::v4(), port_)); tcp::acceptor a(io_service_, tcp::endpoint(tcp::v4(), port_));
for (;;) for (;;)
{ {
socket_ptr sock(new tcp::socket(io_service_)); socket_ptr sock(new tcp::socket(io_service_));
struct timeval tv; a.accept(*sock);
tv.tv_sec = 5; struct timeval tv;
tv.tv_usec = 0; tv.tv_sec = 5;
setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); tv.tv_usec = 0;
setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
a.accept(*sock); setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
cout << "StreamServer::New connection: " << sock->remote_endpoint().address().to_string() << "\n"; cout << "StreamServer::New connection: " << sock->remote_endpoint().address().to_string() << "\n";
StreamSession* session = new StreamSession(sock); StreamSession* session = new StreamSession(sock);
sessions.insert(shared_ptr<StreamSession>(session)); sessions.insert(shared_ptr<StreamSession>(session));
session->start(); session->start();
} }
} }
void StreamServer::send(shared_ptr<BaseMessage> message) void StreamServer::send(shared_ptr<BaseMessage> message)
{ {
for (std::set<shared_ptr<StreamSession>>::iterator it = sessions.begin(); it != sessions.end(); ) for (std::set<shared_ptr<StreamSession>>::iterator it = sessions.begin(); it != sessions.end(); )
{ {
if (!(*it)->active()) if (!(*it)->active())
{ {
cout << "Session inactive. Removing\n"; cout << "Session inactive. Removing\n";
sessions.erase(it++); sessions.erase(it++);
} }
else else
++it; ++it;
} }
for (auto s : sessions) for (auto s : sessions)
s->send(message); s->send(message);
} }
void StreamServer::start() void StreamServer::start()
{ {
acceptThread = new thread(&StreamServer::acceptor, this); acceptThread = new thread(&StreamServer::acceptor, this);
} }

View file

@ -25,13 +25,13 @@ using namespace std;
class StreamSession : public ServerConnection class StreamSession : public ServerConnection
{ {
public: public:
StreamSession(socket_ptr sock); StreamSession(socket_ptr sock);
void send(shared_ptr<BaseMessage> message); void send(shared_ptr<BaseMessage> message);
protected: protected:
virtual void worker(); virtual void worker();
thread* senderThread; thread* senderThread;
Queue<shared_ptr<BaseMessage>> messages; Queue<shared_ptr<BaseMessage>> messages;
}; };
@ -39,41 +39,41 @@ protected:
class StreamServer class StreamServer
{ {
public: public:
StreamServer(unsigned short port); StreamServer(unsigned short port);
void send(shared_ptr<BaseMessage> message); void send(shared_ptr<BaseMessage> message);
void start(); void start();
void stop(); void stop();
private: private:
void acceptor(); void acceptor();
set<shared_ptr<StreamSession>> sessions; set<shared_ptr<StreamSession>> sessions;
boost::asio::io_service io_service_; boost::asio::io_service io_service_;
unsigned short port_; unsigned short port_;
shared_ptr<HeaderMessage> headerChunk; shared_ptr<HeaderMessage> headerChunk;
shared_ptr<SampleFormat> sampleFormat; shared_ptr<SampleFormat> sampleFormat;
thread* acceptThread; thread* acceptThread;
}; };
class ServerException : public std::exception class ServerException : public std::exception
{ {
public: public:
ServerException(const std::string& what) : what_(what) ServerException(const std::string& what) : what_(what)
{ {
} }
virtual ~ServerException() throw() virtual ~ServerException() throw()
{ {
} }
virtual const char* what() const throw() virtual const char* what() const throw()
{ {
return what_.c_str(); return what_.c_str();
} }
private: private:
std::string what_; std::string what_;
}; };