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