]> git.tdb.fi Git - xinema.git/blob - source/xinestream.cpp
Support changing audio and SPU channels
[xinema.git] / source / xinestream.cpp
1 #include <msp/strings/format.h>
2 #include "xineengine.h"
3 #include "xinestream.h"
4
5 using namespace std;
6 using namespace Msp;
7
8 XineStream::XineStream(XineEngine &e, const string &mrl):
9         engine(e),
10         state(STOPPED),
11         channels_changed(false)
12 {
13         stream = xine_stream_new(engine.get_engine(), engine.get_audio_driver(), engine.get_video_driver());
14         xine_open(stream, mrl.c_str());
15
16         queue = xine_event_new_queue(stream);
17
18         update_info();
19         update_channels();
20
21         engine.add_stream(*this);
22 }
23
24 XineStream::~XineStream()
25 {
26         engine.remove_stream(*this);
27
28         xine_close(stream);
29         xine_event_dispose_queue(queue);
30         xine_dispose(stream);
31 }
32
33 void XineStream::set_audio_channel(unsigned i)
34 {
35         if(i>=audio_channels.size())
36                 throw out_of_range("XineStream::set_audio_channel");
37
38         xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, i);
39 }
40
41 void XineStream::set_audio_off()
42 {
43         xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -2);
44 }
45
46 void XineStream::set_spu_channel(unsigned i)
47 {
48         if(i>=spu_channels.size())
49                 throw out_of_range("XineStream::set_spu_channel");
50
51         xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, i);
52 }
53
54 void XineStream::set_spu_off()
55 {
56         xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, -2);
57 }
58
59 void XineStream::play()
60 {
61         if(state==STOPPED)
62                 xine_play(stream, 0, 0);
63         else if(state==PAUSED)
64                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
65
66         set_state(PLAYING);
67 }
68
69 void XineStream::seek(const Time::TimeDelta &time)
70 {
71         xine_play(stream, 0, time/Time::msec);
72         if(state!=PLAYING)
73         {
74                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
75                 set_state(PAUSED);
76         }
77 }
78
79 void XineStream::pause()
80 {
81         if(state==PLAYING)
82         {
83                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
84                 set_state(PAUSED);
85         }
86 }
87
88 void XineStream::stop()
89 {
90         xine_stop(stream);
91         set_state(STOPPED);
92 }
93
94 void XineStream::set_state(State s)
95 {
96         if(s==state)
97                 return;
98
99         MutexLock lock(mutex);
100         state = s;
101         signal_state_changed.emit(state);
102 }
103
104 void XineStream::tick()
105 {
106         while(xine_event_t *event = xine_event_get(queue))
107         {
108                 handle_event(*event);
109                 xine_event_free(event);
110         }
111
112         update_info();
113
114         if(channels_changed)
115         {
116                 channels_changed = false;
117                 update_channels();
118         }
119 }
120
121 void XineStream::update_info()
122 {
123         const char *xt = xine_get_meta_info(stream, XINE_META_INFO_TITLE);
124         if((xt && title.compare(xt)) || (!xt && !title.empty()))
125         {
126                 MutexLock lock(mutex);
127                 title = (xt ? xt : string());
128                 signal_title_changed.emit(title);
129         }
130
131         int dur_msec, pos_msec;
132         xine_get_pos_length(stream, 0, &pos_msec, &dur_msec);
133         Time::TimeDelta dur = dur_msec*Time::msec;
134         Time::TimeDelta pos = pos_msec*Time::msec;
135         if(dur!=duration)
136         {
137                 MutexLock lock(mutex);
138                 duration = dur;
139                 signal_duration_changed.emit(duration);
140         }
141         if(pos!=position)
142         {
143                 MutexLock lock(mutex);
144                 position = pos;
145                 signal_position_changed.emit(position);
146         }
147 }
148
149 void XineStream::update_channels()
150 {
151         MutexLock lock(mutex);
152         char langbuf[XINE_LANG_MAX];
153
154         unsigned n_audio = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
155         audio_channels.resize(n_audio);
156         for(unsigned i=0; i<n_audio; ++i)
157         {
158                 xine_get_audio_lang(stream, i, langbuf);
159                 audio_channels[i].assign(langbuf);
160         }
161
162         unsigned n_spu = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
163         spu_channels.resize(n_spu);
164         for(unsigned i=0; i<n_spu; ++i)
165         {
166                 xine_get_spu_lang(stream, i, langbuf);
167                 spu_channels[i].assign(langbuf);
168         }
169
170         signal_channels_changed.emit();
171 }
172
173 void XineStream::handle_event(const xine_event_t &event)
174 {
175         switch(event.type)
176         {
177         case XINE_EVENT_UI_PLAYBACK_FINISHED:
178                 set_state(STOPPED);
179                 signal_finished.emit();
180                 break;
181         case XINE_EVENT_UI_CHANNELS_CHANGED:
182                 channels_changed = true;
183                 break;
184         }
185 }
186
187
188 void operator<<(LexicalConverter &conv, XineStream::State state)
189 {
190         switch(state)
191         {
192         case XineStream::STOPPED: conv.result("STOPPED"); return;
193         case XineStream::PAUSED: conv.result("PAUSED"); return;
194         case XineStream::PLAYING: conv.result("PLAYING"); return;
195         default: conv.result(format("State(%d)", static_cast<int>(state))); return;
196         }
197 }
198
199 void operator>>(const LexicalConverter &conv, XineStream::State &state)
200 {
201         const string &str = conv.get();
202         if(str=="STOPPED")
203                 state = XineStream::STOPPED;
204         else if(str=="PAUSED")
205                 state = XineStream::PAUSED;
206         else if(str=="PLAYING")
207                 state = XineStream::PLAYING;
208         else
209                 throw lexical_error(format("Conversion of '%s' to XineStream::State", str));
210 }