require "xlib";
require "libxine";
require "sigc++-2.0";
+ require "mspnet";
source "source";
build_info
{
--- /dev/null
+#include <msp/fs/dir.h>
+#include <msp/fs/stat.h>
+#include "client.h"
+#include "xinema.h"
+
+using namespace std;
+using namespace Msp;
+
+Client::Client(Xinema &x, Net::StreamSocket *s):
+ xinema(x),
+ socket(s),
+ stale(false)
+{
+ socket->signal_data_available.connect(sigc::mem_fun(this, &Client::data_available));
+ socket->signal_end_of_file.connect(sigc::mem_fun(this, &Client::end_of_stream));
+}
+
+void Client::data_available()
+{
+ char rbuf[1024];
+ unsigned len = socket->read(rbuf, sizeof(rbuf));
+ buffer.append(rbuf, len);
+
+ string::size_type start = 0;
+ while(1)
+ {
+ string::size_type newline = buffer.find('\n', start);
+ if(newline==string::npos)
+ break;
+
+ try
+ {
+ process_command(buffer.substr(start, newline-start));
+ }
+ catch(const exception &e)
+ {
+ send_reply(string("error ")+e.what());
+ return;
+ }
+
+ start = newline+1;
+ }
+
+ buffer.erase(0, start);
+}
+
+void Client::end_of_stream()
+{
+ stale = true;
+}
+
+void Client::process_command(const string &cmd)
+{
+ string::size_type space = cmd.find(' ');
+ string keyword = cmd.substr(0, space);
+ string args;
+ if(space!=string::npos)
+ args = cmd.substr(space+1);
+ if(keyword=="list_directory")
+ list_directory(args);
+ else if(keyword=="play_file")
+ xinema.play_file(args);
+ else
+ send_reply("error Invalid command");
+}
+
+void Client::send_reply(const string &reply)
+{
+ socket->write(reply);
+ socket->put('\n');
+}
+
+void Client::list_directory(const FS::Path &dn)
+{
+ list<string> files = FS::list_files(dn);
+
+ send_reply("directory "+dn.str());
+ for(list<string>::const_iterator i=files.begin(); i!=files.end(); ++i)
+ {
+ if(FS::is_dir(dn / *i))
+ send_reply("subdir "+*i);
+ else
+ send_reply("file "+*i);
+ }
+}
--- /dev/null
+#ifndef CLIENT_H_
+#define CLIENT_H_
+
+#include <msp/fs/path.h>
+#include <msp/net/streamsocket.h>
+
+class Xinema;
+
+class Client
+{
+private:
+ Xinema &xinema;
+ Msp::Net::StreamSocket *socket;
+ std::string buffer;
+ bool stale;
+
+public:
+ Client(Xinema &, Msp::Net::StreamSocket *);
+
+ bool is_stale() const { return stale; }
+
+private:
+ void data_available();
+ void end_of_stream();
+
+ void process_command(const std::string &);
+ void send_reply(const std::string &);
+ void list_directory(const Msp::FS::Path &);
+};
+
+#endif
--- /dev/null
+#include <msp/net/inet6.h>
+#include <msp/net/resolve.h>
+#include "client.h"
+#include "networkinterface.h"
+
+using namespace std;
+using namespace Msp;
+
+NetworkInterface::NetworkInterface(Xinema &x):
+ xinema(x)
+{
+ Net::SockAddr *addr = Net::resolve("::", "34588", Net::INET6);
+ server_sock = new Net::StreamServerSocket(addr->get_family());
+ server_sock->listen(*addr);
+ delete addr;
+
+ server_sock->signal_data_available.connect(sigc::mem_fun(this, &NetworkInterface::connection_available));
+
+ event_disp.add(*server_sock);
+
+ thread = new NetworkThread(*this);
+}
+
+NetworkInterface::~NetworkInterface()
+{
+ thread->terminate();
+ delete thread;
+ delete server_sock;
+}
+
+void NetworkInterface::connection_available()
+{
+ Net::StreamSocket *sock = server_sock->accept();
+ event_disp.add(*sock);
+ clients.push_back(new Client(xinema, sock));
+}
+
+
+NetworkInterface::NetworkThread::NetworkThread(NetworkInterface &n):
+ network(n),
+ done(false)
+{
+ network.event_disp.add(wakeup_pipe);
+ launch();
+}
+
+void NetworkInterface::NetworkThread::terminate()
+{
+ done = true;
+ wakeup_pipe.put('w');
+ join();
+}
+
+void NetworkInterface::NetworkThread::main()
+{
+ while(!done)
+ {
+ network.event_disp.tick();
+
+ for(list<Client *>::iterator i=network.clients.begin(); i!=network.clients.end(); )
+ {
+ if((*i)->is_stale())
+ {
+ delete *i;
+ network.clients.erase(i++);
+ }
+ else
+ ++i;
+ }
+ }
+}
--- /dev/null
+#ifndef NETWORKINTERFACE_H_
+#define NETWORKINTERFACE_H_
+
+#include <msp/core/thread.h>
+#include <msp/io/eventdispatcher.h>
+#include <msp/io/pipe.h>
+#include <msp/net/streamserversocket.h>
+
+class Client;
+class Xinema;
+
+class NetworkInterface
+{
+private:
+ class NetworkThread: public Msp::Thread
+ {
+ private:
+ NetworkInterface &network;
+ Msp::IO::Pipe wakeup_pipe;
+ bool done;
+
+ public:
+ NetworkThread(NetworkInterface &);
+
+ void terminate();
+
+ private:
+ virtual void main();
+ };
+
+ Xinema &xinema;
+ Msp::Net::StreamServerSocket *server_sock;
+ Msp::IO::EventDispatcher event_disp;
+ NetworkThread *thread;
+ std::list<Client *> clients;
+
+public:
+ NetworkInterface(Xinema &);
+ ~NetworkInterface();
+
+private:
+ void connection_available();
+};
+
+#endif
#include <sigc++/bind.h>
-#include <msp/core/getopt.h>
+#include <msp/time/utils.h>
#include "xineengine.h"
#include "xinema.h"
#include "xinestream.h"
using namespace std;
using namespace Msp;
-Xinema::Xinema(int argc, char **argv):
- window(display, 1920, 1080)
+Xinema::Xinema(int, char **):
+ window(display, 1920, 1080),
+ network(*this),
+ engine(0),
+ stream(0)
{
- GetOpt getopt;
- getopt.add_argument("filename", filename, GetOpt::REQUIRED_ARG);
- getopt(argc, argv);
-
window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Xinema::exit), 0));
}
display.tick();
engine = new XineEngine(window, &display_mutex);
- stream = new XineStream(*engine, filename);
- stream->play();
Application::main();
- delete stream;
+ if(stream)
+ delete stream;
delete engine;
return exit_code;
void Xinema::tick()
{
+ {
+ MutexLock lock(command_mutex);
+ if(!pending_mrl.empty())
+ {
+ delete stream;
+ stream = new XineStream(*engine, pending_mrl);
+ stream->play();
+ pending_mrl.clear();
+ }
+ }
+
{
MutexLock lock(display_mutex);
display.tick();
}
- stream->tick();
+ if(stream)
+ stream->tick();
+
+ Time::sleep(10*Time::msec);
+}
+
+void Xinema::play_file(const FS::Path &fn)
+{
+ MutexLock lock(command_mutex);
+ pending_mrl = "file://"+fn.str();
}
#include <msp/core/application.h>
#include <msp/core/mutex.h>
+#include <msp/fs/path.h>
#include <msp/graphics/display.h>
#include <msp/graphics/window.h>
+#include "networkinterface.h"
class XineEngine;
class XineStream;
class Xinema: public Msp::RegisteredApplication<Xinema>
{
private:
- std::string filename;
Msp::Graphics::Display display;
Msp::Mutex display_mutex;
Msp::Graphics::Window window;
+ NetworkInterface network;
XineEngine *engine;
XineStream *stream;
+ Msp::Mutex command_mutex;
+ std::string pending_mrl;
+
public:
Xinema(int, char **);
virtual int main();
-
private:
virtual void tick();
+
+public:
+ void play_file(const Msp::FS::Path &);
};
#endif