]> git.tdb.fi Git - xinema.git/commitdiff
Support changing audio and SPU channels
authorMikko Rasa <tdb@tdb.fi>
Fri, 16 Oct 2015 23:48:59 +0000 (02:48 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 16 Oct 2015 23:48:59 +0000 (02:48 +0300)
source/client.cpp
source/client.h
source/xinestream.cpp
source/xinestream.h

index 8c84e26a7f371a1da9da0f9fdc7bb00488339382..604779662b5f0fc6944bf07542bd686ce390bdfb 100644 (file)
@@ -94,6 +94,10 @@ void Client::process_command(const string &cmd)
                get_stream().pause();
        else if(keyword=="stop")
                get_stream().stop();
+       else if(keyword=="select_audio")
+               set_audio_channel(args);
+       else if(keyword=="select_spu")
+               set_spu_channel(args);
        else
                throw runtime_error("Invalid command");
 }
@@ -126,12 +130,31 @@ void Client::list_directory(const FS::Path &dn)
        }
 }
 
+void Client::set_audio_channel(const string &arg)
+{
+       XineStream &stream = get_stream();
+       if(arg=="off")
+               stream.set_audio_off();
+       else
+               stream.set_audio_channel(lexical_cast<unsigned>(arg));
+}
+
+void Client::set_spu_channel(const string &arg)
+{
+       XineStream &stream = get_stream();
+       if(arg=="off")
+               stream.set_spu_off();
+       else
+               stream.set_spu_channel(lexical_cast<unsigned>(arg));
+}
+
 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.signal_channels_changed.connect(sigc::mem_fun(this, &Client::stream_channels_changed));
 
        MutexLock lock(stream.get_mutex());
        stream_state_changed(stream.get_state());
@@ -142,6 +165,8 @@ void Client::stream_created(XineStream &stream)
 
        if(const Time::TimeDelta &dur = stream.get_duration())
                stream_duration_changed(dur);
+
+       stream_channels_changed();
 }
 
 void Client::stream_destroyed()
@@ -172,3 +197,20 @@ void Client::stream_position_changed(const Time::TimeDelta &pos)
                last_position = pos;
        }
 }
+
+void Client::stream_channels_changed()
+{
+       XineStream &stream = get_stream();
+
+       const vector<string> &audio_channels = stream.get_audio_channels();
+       send_reply(format("audio_count %d", audio_channels.size()));
+       for(unsigned i=0; i<audio_channels.size(); ++i)
+               send_reply(format("audio %d %s", i, audio_channels[i]));
+
+       const vector<string> &spu_channels = stream.get_spu_channels();
+       send_reply(format("spu_count %d", spu_channels.size()));
+       for(unsigned i=0; i<spu_channels.size(); ++i)
+               send_reply(format("spu %d %s", i, spu_channels[i]));
+
+       send_reply("channels_end");
+}
index f1f4dc15ed319c6312cfef6fc3bbbd0de1ef2892..671290e1b86cf4f65dea17675957e99a6fb8ac77 100644 (file)
@@ -32,6 +32,8 @@ private:
        void process_command(const std::string &);
        void send_reply(const std::string &);
        void list_directory(const Msp::FS::Path &);
+       void set_audio_channel(const std::string &);
+       void set_spu_channel(const std::string &);
 
        void stream_created(XineStream &);
        void stream_destroyed();
@@ -39,6 +41,7 @@ private:
        void stream_title_changed(const std::string &);
        void stream_duration_changed(const Msp::Time::TimeDelta &);
        void stream_position_changed(const Msp::Time::TimeDelta &);
+       void stream_channels_changed();
 };
 
 #endif
index 6cc3d7546847af6593007ca746121e56ef856f64..a702b28b335e66ce0ed840c1d11f68da83aa22aa 100644 (file)
@@ -7,7 +7,8 @@ using namespace Msp;
 
 XineStream::XineStream(XineEngine &e, const string &mrl):
        engine(e),
-       state(STOPPED)
+       state(STOPPED),
+       channels_changed(false)
 {
        stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
        xine_open(stream, mrl.c_str());
@@ -15,6 +16,7 @@ XineStream::XineStream(XineEngine &e, const string &mrl):
        queue = xine_event_new_queue(stream);
 
        update_info();
+       update_channels();
 
        engine.add_stream(*this);
 }
@@ -28,6 +30,32 @@ XineStream::~XineStream()
        xine_dispose(stream);
 }
 
+void XineStream::set_audio_channel(unsigned i)
+{
+       if(i>=audio_channels.size())
+               throw out_of_range("XineStream::set_audio_channel");
+
+       xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, i);
+}
+
+void XineStream::set_audio_off()
+{
+       xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -2);
+}
+
+void XineStream::set_spu_channel(unsigned i)
+{
+       if(i>=spu_channels.size())
+               throw out_of_range("XineStream::set_spu_channel");
+
+       xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, i);
+}
+
+void XineStream::set_spu_off()
+{
+       xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, -2);
+}
+
 void XineStream::play()
 {
        if(state==STOPPED)
@@ -82,6 +110,12 @@ void XineStream::tick()
        }
 
        update_info();
+
+       if(channels_changed)
+       {
+               channels_changed = false;
+               update_channels();
+       }
 }
 
 void XineStream::update_info()
@@ -112,6 +146,30 @@ void XineStream::update_info()
        }
 }
 
+void XineStream::update_channels()
+{
+       MutexLock lock(mutex);
+       char langbuf[XINE_LANG_MAX];
+
+       unsigned n_audio = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
+       audio_channels.resize(n_audio);
+       for(unsigned i=0; i<n_audio; ++i)
+       {
+               xine_get_audio_lang(stream, i, langbuf);
+               audio_channels[i].assign(langbuf);
+       }
+
+       unsigned n_spu = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
+       spu_channels.resize(n_spu);
+       for(unsigned i=0; i<n_spu; ++i)
+       {
+               xine_get_spu_lang(stream, i, langbuf);
+               spu_channels[i].assign(langbuf);
+       }
+
+       signal_channels_changed.emit();
+}
+
 void XineStream::handle_event(const xine_event_t &event)
 {
        switch(event.type)
@@ -120,6 +178,9 @@ void XineStream::handle_event(const xine_event_t &event)
                set_state(STOPPED);
                signal_finished.emit();
                break;
+       case XINE_EVENT_UI_CHANNELS_CHANGED:
+               channels_changed = true;
+               break;
        }
 }
 
index 65f25ab26ee13112a8e07a592075b75919308102..c5778c7d0f36975acb193d2c16c7c510e987687b 100644 (file)
@@ -2,6 +2,7 @@
 #define XINESTREAM_H_
 
 #include <string>
+#include <vector>
 #include <xine.h>
 #include <msp/core/mutex.h>
 #include <msp/strings/lexicalcast.h>
@@ -23,6 +24,8 @@ public:
        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;
+       sigc::signal<void> signal_channels_changed;
+       sigc::signal<void> signal_finished;
 
 private:
        XineEngine &engine;
@@ -33,6 +36,9 @@ private:
        std::string title;
        Msp::Time::TimeDelta duration;
        Msp::Time::TimeDelta position;
+       std::vector<std::string> audio_channels;
+       std::vector<std::string> spu_channels;
+       bool channels_changed;
 
 public:
        XineStream(XineEngine &, const std::string &);
@@ -43,6 +49,12 @@ public:
        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; }
+       const std::vector<std::string> &get_audio_channels() const { return audio_channels; }
+       const std::vector<std::string> &get_spu_channels() const { return spu_channels; }
+       void set_audio_channel(unsigned);
+       void set_audio_off();
+       void set_spu_channel(unsigned);
+       void set_spu_off();
 
        void play();
        void seek(const Msp::Time::TimeDelta &);
@@ -55,6 +67,7 @@ public:
        void tick();
 private:
        void update_info();
+       void update_channels();
        void handle_event(const xine_event_t &);
 };