]> git.tdb.fi Git - xinema.git/blob - source/xinestream.cpp
Substitute "unknown" if channel language can't be determined
[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::play()
35 {
36         if(state==STOPPED)
37                 xine_play(stream, 0, 0);
38         else if(state==PAUSED)
39                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
40
41         set_state(PLAYING);
42 }
43
44 void XineStream::seek(const Time::TimeDelta &time)
45 {
46         xine_play(stream, 0, time/Time::msec);
47         if(state!=PLAYING)
48         {
49                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
50                 set_state(PAUSED);
51         }
52 }
53
54 void XineStream::pause()
55 {
56         if(state==PLAYING)
57         {
58                 xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
59                 set_state(PAUSED);
60         }
61 }
62
63 void XineStream::stop()
64 {
65         xine_stop(stream);
66         set_state(STOPPED);
67 }
68
69 void XineStream::set_state(State s)
70 {
71         if(s==state)
72                 return;
73
74         MutexLock lock(mutex);
75         state = s;
76         signal_state_changed.emit(state);
77 }
78
79 void XineStream::select_audio_channel(int i)
80 {
81         if(i>=0 && static_cast<unsigned>(i)>=audio_channels.size())
82                 throw out_of_range("XineStream::set_audio_channel");
83
84         if(i<0)
85                 i = OFF;
86         xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, (i==OFF ? -2 : i));
87 }
88
89 void XineStream::select_spu_channel(int i)
90 {
91         if(i>=0 && static_cast<unsigned>(i)>=spu_channels.size())
92                 throw out_of_range("XineStream::set_spu_channel");
93
94         if(i<0)
95                 i = OFF;
96         xine_set_param(stream, XINE_PARAM_SPU_CHANNEL, (i==OFF ? -2 : i));
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                 if(xine_get_audio_lang(stream, i, langbuf))
176                         audio_channels[i].assign(langbuf);
177                 else
178                         audio_channels[i].assign("unknown");
179         }
180
181         unsigned n_spu = xine_get_stream_info(stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
182         spu_channels.resize(n_spu);
183         for(unsigned i=0; i<n_spu; ++i)
184         {
185                 if(xine_get_spu_lang(stream, i, langbuf))
186                         spu_channels[i].assign(langbuf);
187                 else
188                         spu_channels[i].assign("unknown");
189         }
190
191         signal_channels_changed.emit();
192 }
193
194 void XineStream::handle_event(const xine_event_t &event)
195 {
196         switch(event.type)
197         {
198         case XINE_EVENT_UI_PLAYBACK_FINISHED:
199                 set_state(STOPPED);
200                 signal_finished.emit();
201                 break;
202         case XINE_EVENT_UI_CHANNELS_CHANGED:
203                 channels_changed = true;
204                 break;
205         }
206 }
207
208
209 void operator<<(LexicalConverter &conv, XineStream::State state)
210 {
211         switch(state)
212         {
213         case XineStream::STOPPED: conv.result("STOPPED"); return;
214         case XineStream::PAUSED: conv.result("PAUSED"); return;
215         case XineStream::PLAYING: conv.result("PLAYING"); return;
216         default: conv.result(format("State(%d)", static_cast<int>(state))); return;
217         }
218 }
219
220 void operator>>(const LexicalConverter &conv, XineStream::State &state)
221 {
222         const string &str = conv.get();
223         if(str=="STOPPED")
224                 state = XineStream::STOPPED;
225         else if(str=="PAUSED")
226                 state = XineStream::PAUSED;
227         else if(str=="PLAYING")
228                 state = XineStream::PLAYING;
229         else
230                 throw lexical_error(format("Conversion of '%s' to XineStream::State", str));
231 }