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");
}
}
}
+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());
if(const Time::TimeDelta &dur = stream.get_duration())
stream_duration_changed(dur);
+
+ stream_channels_changed();
}
void Client::stream_destroyed()
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");
+}
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();
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
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());
queue = xine_event_new_queue(stream);
update_info();
+ update_channels();
engine.add_stream(*this);
}
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)
}
update_info();
+
+ if(channels_changed)
+ {
+ channels_changed = false;
+ update_channels();
+ }
}
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)
set_state(STOPPED);
signal_finished.emit();
break;
+ case XINE_EVENT_UI_CHANNELS_CHANGED:
+ channels_changed = true;
+ break;
}
}
#define XINESTREAM_H_
#include <string>
+#include <vector>
#include <xine.h>
#include <msp/core/mutex.h>
#include <msp/strings/lexicalcast.h>
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;
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 &);
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 &);
void tick();
private:
void update_info();
+ void update_channels();
void handle_event(const xine_event_t &);
};