]> git.tdb.fi Git - xinema.git/commitdiff
Implement basic playback controls
authorMikko Rasa <tdb@tdb.fi>
Fri, 16 Oct 2015 15:49:57 +0000 (18:49 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 16 Oct 2015 15:49:57 +0000 (18:49 +0300)
source/client.cpp
source/client.h
source/xinestream.cpp
source/xinestream.h

index 1f2164876024adc75fe4f440aa6f7938ca944dd8..0e87e205055f6a5c796ce40f53a056fc4293ca01 100644 (file)
@@ -3,7 +3,6 @@
 #include <msp/strings/format.h>
 #include "client.h"
 #include "xinema.h"
-#include "xinestream.h"
 
 using namespace std;
 using namespace Msp;
@@ -55,6 +54,15 @@ void Client::end_of_stream()
        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(' ');
@@ -62,12 +70,21 @@ void Client::process_command(const string &cmd)
        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)
@@ -92,16 +109,26 @@ void Client::list_directory(const FS::Path &dn)
 
 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);
index 31bdbec4d70ce6a571425a2dc51e2988ee2d29fd..2300fc2d3d5d3c5ffa54ab6c3c41a8fc9c218a04 100644 (file)
@@ -5,8 +5,8 @@
 #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
@@ -27,11 +27,13 @@ private:
        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 &);
index 5614dd00838324e29a3483e70e16459792a02770..619ec5800872e7d1c843f4eddde41c50178c1193 100644 (file)
@@ -6,7 +6,8 @@ using namespace std;
 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());
@@ -29,12 +30,46 @@ XineStream::~XineStream()
 
 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()
@@ -85,6 +120,9 @@ void XineStream::handle_event(const xine_event_t &event)
 {
        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);
@@ -93,3 +131,28 @@ void XineStream::handle_event(const xine_event_t &event)
                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));
+}
index c1f27f74aa45542318d40a05e8adb28153b874ea..def7f01a5f9d2dbd6a5e0ee694670c8c597e0bf6 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <string>
 #include <xine.h>
+#include <msp/strings/lexicalcast.h>
 #include <msp/time/timedelta.h>
 
 class XineEngine;
@@ -10,6 +11,14 @@ 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;
@@ -18,6 +27,7 @@ private:
        XineEngine &engine;
        xine_stream_t *stream;
        xine_event_queue_t *queue;
+       State state;
        std::string title;
        Msp::Time::TimeDelta duration;
        Msp::Time::TimeDelta position;
@@ -26,17 +36,26 @@ public:
        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