#include <msp/strings/format.h>
#include "client.h"
#include "xinema.h"
-#include "xinestream.h"
using namespace std;
using namespace Msp;
stale = true;
}
+XineStream &Client::get_stream() const
+{
+ XineStream *stream = xinema.get_stream();
+ if(stream)
+ return *stream;
+
+ throw runtime_error("No stream");
+}
+
void Client::process_command(const string &cmd)
{
string::size_type space = cmd.find(' ');
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 if(keyword=="play")
+ get_stream().play();
+ else if(keyword=="seek")
+ get_stream().seek(lexical_cast<float>(args)*Time::sec);
+ else if(keyword=="pause")
+ get_stream().pause();
+ else if(keyword=="stop")
+ get_stream().stop();
else
- send_reply("error Invalid command");
+ throw runtime_error("Invalid command");
}
void Client::send_reply(const string &reply)
void Client::stream_created(XineStream &stream)
{
+ stream.signal_state_changed.connect(sigc::mem_fun(this, &Client::stream_state_changed));
stream.signal_title_changed.connect(sigc::mem_fun(this, &Client::stream_title_changed));
stream.signal_duration_changed.connect(sigc::mem_fun(this, &Client::stream_duration_changed));
stream.signal_position_changed.connect(sigc::mem_fun(this, &Client::stream_position_changed));
+
+ stream_state_changed(stream.get_state());
+
string title = stream.get_title();
if(!title.empty())
send_reply("title "+title);
+
if(const Time::TimeDelta &dur = stream.get_duration())
stream_duration_changed(dur);
}
+void Client::stream_state_changed(XineStream::State state)
+{
+ send_reply(format("state %s", state));
+}
+
void Client::stream_title_changed(const string &title)
{
send_reply("title "+title);
#include <msp/fs/path.h>
#include <msp/net/streamsocket.h>
#include <msp/time/timedelta.h>
+#include "xinestream.h"
-class XineStream;
class Xinema;
class Client: public sigc::trackable
void data_available();
void end_of_stream();
+ XineStream &get_stream() const;
void process_command(const std::string &);
void send_reply(const std::string &);
void list_directory(const Msp::FS::Path &);
void stream_created(XineStream &);
+ void stream_state_changed(XineStream::State);
void stream_title_changed(const std::string &);
void stream_duration_changed(const Msp::Time::TimeDelta &);
void stream_position_changed(const Msp::Time::TimeDelta &);
using namespace Msp;
XineStream::XineStream(XineEngine &e, const string &mrl):
- engine(e)
+ engine(e),
+ state(STOPPED)
{
stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
xine_open(stream, mrl.c_str());
void XineStream::play()
{
- xine_play(stream, 0, 0);
+ if(state==STOPPED)
+ xine_play(stream, 0, 0);
+ else if(state==PAUSED)
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+
+ set_state(PLAYING);
+}
+
+void XineStream::seek(const Time::TimeDelta &time)
+{
+ xine_play(stream, 0, time/Time::msec);
+ if(state!=PLAYING)
+ {
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ set_state(PAUSED);
+ }
+}
+
+void XineStream::pause()
+{
+ if(state==PLAYING)
+ {
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ set_state(PAUSED);
+ }
}
void XineStream::stop()
{
xine_stop(stream);
+ set_state(STOPPED);
+}
+
+void XineStream::set_state(State s)
+{
+ if(s==state)
+ return;
+
+ state = s;
+ signal_state_changed.emit(state);
}
void XineStream::tick()
{
switch(event.type)
{
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ set_state(STOPPED);
+ break;
case XINE_EVENT_PROGRESS:
{
xine_progress_data_t *data = reinterpret_cast<xine_progress_data_t *>(event.data);
break;
}
}
+
+
+void operator<<(LexicalConverter &conv, XineStream::State state)
+{
+ switch(state)
+ {
+ case XineStream::STOPPED: conv.result("STOPPED"); return;
+ case XineStream::PAUSED: conv.result("PAUSED"); return;
+ case XineStream::PLAYING: conv.result("PLAYING"); return;
+ default: conv.result(format("State(%d)", static_cast<int>(state))); return;
+ }
+}
+
+void operator>>(const LexicalConverter &conv, XineStream::State &state)
+{
+ const string &str = conv.get();
+ if(str=="STOPPED")
+ state = XineStream::STOPPED;
+ else if(str=="PAUSED")
+ state = XineStream::PAUSED;
+ else if(str=="PLAYING")
+ state = XineStream::PLAYING;
+ else
+ throw lexical_error(format("Conversion of '%s' to XineStream::State", str));
+}
#include <string>
#include <xine.h>
+#include <msp/strings/lexicalcast.h>
#include <msp/time/timedelta.h>
class XineEngine;
class XineStream
{
public:
+ enum State
+ {
+ STOPPED,
+ PAUSED,
+ PLAYING
+ };
+
+ sigc::signal<void, State> signal_state_changed;
sigc::signal<void, const std::string &> signal_title_changed;
sigc::signal<void, const Msp::Time::TimeDelta &> signal_duration_changed;
sigc::signal<void, const Msp::Time::TimeDelta &> signal_position_changed;
XineEngine &engine;
xine_stream_t *stream;
xine_event_queue_t *queue;
+ State state;
std::string title;
Msp::Time::TimeDelta duration;
Msp::Time::TimeDelta position;
XineStream(XineEngine &, const std::string &);
~XineStream();
+ State get_state() const { return state; }
const Msp::Time::TimeDelta &get_duration() const { return duration; }
const Msp::Time::TimeDelta &get_position() const { return position; }
const std::string &get_title() const { return title; }
void play();
+ void seek(const Msp::Time::TimeDelta &);
+ void pause();
void stop();
+private:
+ void set_state(State);
+public:
void tick();
private:
void check_info();
void handle_event(const xine_event_t &);
};
+void operator<<(Msp::LexicalConverter &, XineStream::State);
+void operator>>(const Msp::LexicalConverter &, XineStream::State &);
+
#endif