add infrastructure for record service events (not finished yet)
[enigma2.git] / lib / service / servicexine.cpp
1 #define HAVE_XINE
2 #ifdef HAVE_XINE
3
4 /* yes, it's xine, not Xine. But eServicexine looks odd. */
5
6 #include <lib/base/eerror.h>
7 #include <lib/base/object.h>
8 #include <lib/base/ebase.h>
9 #include <string>
10 #include <lib/service/servicexine.h>
11 #include <lib/service/service.h>
12 #include <lib/base/init_num.h>
13 #include <lib/base/init.h>
14
15 static xine_t *xine; /* TODO: move this into a static class */
16
17 // eServiceFactoryXine
18
19 eServiceFactoryXine::eServiceFactoryXine()
20 {
21         ePtr<eServiceCenter> sc;
22         
23         eServiceCenter::getPrivInstance(sc);
24         if (sc)
25                 sc->addServiceFactory(eServiceFactoryXine::id, this);
26
27         m_service_info = new eStaticServiceXineInfo();
28 }
29
30 eServiceFactoryXine::~eServiceFactoryXine()
31 {
32         ePtr<eServiceCenter> sc;
33         
34         eServiceCenter::getPrivInstance(sc);
35         if (sc)
36                 sc->removeServiceFactory(eServiceFactoryXine::id);
37 }
38
39 DEFINE_REF(eServiceFactoryXine)
40
41         // iServiceHandler
42 RESULT eServiceFactoryXine::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
43 {
44                 // check resources...
45         ptr = new eServiceXine(ref.path.c_str());
46         return 0;
47 }
48
49 RESULT eServiceFactoryXine::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
50 {
51         ptr=0;
52         return -1;
53 }
54
55 RESULT eServiceFactoryXine::list(const eServiceReference &, ePtr<iListableService> &ptr)
56 {
57         ptr=0;
58         return -1;
59 }
60
61 RESULT eServiceFactoryXine::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
62 {
63         ptr = m_service_info;
64         return 0;
65 }
66
67 RESULT eServiceFactoryXine::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
68 {
69         ptr = 0;
70         return -1;
71 }
72
73
74 // eStaticServiceXineInfo
75
76
77 DEFINE_REF(eStaticServiceXineInfo)
78
79 eStaticServiceXineInfo::eStaticServiceXineInfo()
80 {
81 }
82
83 RESULT eStaticServiceXineInfo::getName(const eServiceReference &ref, std::string &name)
84 {
85         size_t last = ref.path.rfind('/');
86         if (last != std::string::npos)
87                 name = ref.path.substr(last+1);
88         else
89                 name = ref.path;
90         return 0;
91 }
92
93 int eStaticServiceXineInfo::getLength(const eServiceReference &ref)
94 {
95         return -1;
96 }
97
98 // eServiceXine
99
100 eServiceXine::eServiceXine(const char *filename): m_filename(filename), m_pump(eApp, 1)
101 {
102         m_state = stError;
103         stream = 0;
104         event_queue = 0;
105         ao_port = 0;
106         vo_port = 0;
107         
108         
109         if ((vo_port = xine_open_video_driver(xine, "fb", XINE_VISUAL_TYPE_FB, NULL)) == NULL)
110         {
111                 eWarning("cannot open xine video driver");
112         }
113
114         if ((ao_port = xine_open_audio_driver(xine , "alsa", NULL)) == NULL)
115         {
116                 eWarning("cannot open xine audio driver");
117         }
118         stream = xine_stream_new(xine, ao_port, vo_port);
119         event_queue = xine_event_new_queue(stream);
120         xine_event_create_listener_thread(event_queue, eventListenerWrap, this);
121
122 //      CONNECT(m_pump.recv_msg, eServiceXine::gstPoll);
123         m_state = stIdle;
124 }
125
126 eServiceXine::~eServiceXine()
127 {
128         if (m_state == stRunning)
129                 stop();
130
131         if (stream)
132                 xine_close(stream);
133         if (event_queue)
134                 xine_event_dispose_queue(event_queue);
135         if (stream)
136                 xine_dispose(stream);
137         if (ao_port)
138                 xine_close_audio_driver(xine, ao_port); 
139         if (vo_port)
140                 xine_close_video_driver(xine, vo_port); 
141 }
142
143 DEFINE_REF(eServiceXine);       
144
145 void eServiceXine::eventListenerWrap(void *user_data, const xine_event_t *event)
146 {
147         eServiceXine *e = (eServiceXine*)user_data;
148         e->eventListener(event);
149 }
150
151 void eServiceXine::eventListener(const xine_event_t *event)
152 {
153         eDebug("handle %d", event->type);
154         switch(event->type) { 
155         case XINE_EVENT_UI_PLAYBACK_FINISHED:
156                 break;
157         }
158 }
159
160 RESULT eServiceXine::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
161 {
162         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
163         return 0;
164 }
165
166 RESULT eServiceXine::start()
167 {
168         if (m_state == stError)
169                 return -1;
170
171         assert(m_state == stIdle);
172         assert(stream);
173         
174         if (!xine_open(stream, m_filename.c_str()))
175         {
176                 eWarning("xine_open failed!");
177                 return -1;
178         }
179         
180         if (!xine_play(stream, 0, 0))
181         {
182                 eWarning("xine_play failed!");
183                 return -1;
184         }
185
186         m_state = stRunning;
187         
188         m_event(this, evStart);
189         return 0;
190 }
191
192 RESULT eServiceXine::stop()
193 {
194         if (m_state == stError)
195                 return -1;
196
197         assert(m_state != stIdle);
198         assert(stream);
199         if (m_state == stStopped)
200                 return -1;
201         printf("Xine: %s stop\n", m_filename.c_str());
202         xine_stop(stream);
203         // STOP
204         m_state = stStopped;
205         return 0;
206 }
207
208 RESULT eServiceXine::setTarget(int target)
209 {
210         return -1;
211 }
212
213 RESULT eServiceXine::pause(ePtr<iPauseableService> &ptr)
214 {
215         ptr=this;
216         return 0;
217 }
218
219 RESULT eServiceXine::setSlowMotion(int ratio)
220 {
221         return -1;
222 }
223
224 RESULT eServiceXine::setFastForward(int ratio)
225 {
226         return -1;
227 }
228   
229                 // iPausableService
230 RESULT eServiceXine::pause()
231 {
232         // PAUSE
233         return 0;
234 }
235
236 RESULT eServiceXine::unpause()
237 {
238         // PLAY
239         return 0;
240 }
241
242         /* iSeekableService */
243 RESULT eServiceXine::seek(ePtr<iSeekableService> &ptr)
244 {
245         ptr = this;
246         return 0;
247 }
248
249 RESULT eServiceXine::getLength(pts_t &pts)
250 {
251                 // LENGTH
252         return 0;
253 }
254
255 RESULT eServiceXine::seekTo(pts_t to)
256 {
257                 // SEEK
258         return 0;
259 }
260
261 RESULT eServiceXine::seekRelative(int direction, pts_t to)
262 {
263                 // SEEK RELATIVE
264         return 0;
265 }
266
267 RESULT eServiceXine::getPlayPosition(pts_t &pts)
268 {
269                 // GET POSITION
270         return 0;
271 }
272
273 RESULT eServiceXine::setTrickmode(int trick)
274 {
275                 /* trickmode currently doesn't make any sense for us. */
276         return -1;
277 }
278
279 RESULT eServiceXine::isCurrentlySeekable()
280 {
281         return 1;
282 }
283
284 RESULT eServiceXine::info(ePtr<iServiceInformation>&i)
285 {
286         i = this;
287         return 0;
288 }
289
290 RESULT eServiceXine::getName(std::string &name)
291 {
292         name = "xine File: " + m_filename;
293         return 0;
294 }
295
296 int eServiceXine::getInfo(int w)
297 {
298         switch (w)
299         {
300         case sTitle:
301         case sArtist:
302         case sAlbum:
303         case sComment:
304         case sTracknumber:
305         case sGenre:
306                 return resIsString;
307
308         default:
309                 return resNA;
310         }
311 }
312
313 std::string eServiceXine::getInfoString(int w)
314 {
315         return "";
316 }
317
318 class eXine
319 {
320 public:
321         eXine()
322         {
323                         /* this should be done once. */
324
325                 if(!xine_check_version(1, 1, 0))
326                 {
327                         int major, minor, sub;
328                         xine_get_version (&major, &minor, &sub);
329                         eWarning("Require xine library version 1.1.0, found %d.%d.%d.\n",
330                                                 major, minor,sub);
331                         return;
332                 } else {
333                         int major, minor, sub;
334                         eDebug("Built with xine library %d.%d.%d (%s)\n",
335                                                  XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION, XINE_VERSION);
336                 
337                         xine_get_version (&major, &minor, &sub);
338
339                         eDebug("Found xine library version: %d.%d.%d (%s).\n", 
340                                                  major, minor, sub, xine_get_version_string());
341                 }
342         
343                 xine = xine_new();
344                 xine_engine_set_param(xine, XINE_ENGINE_PARAM_VERBOSITY, 1);
345                 xine_init(xine);
346         }
347         ~eXine()
348         {
349                 if (xine)
350                         xine_exit(xine);
351         }
352 };
353
354 eAutoInitP0<eXine> init_eXine(eAutoInitNumbers::service, "libxine");
355 eAutoInitPtr<eServiceFactoryXine> init_eServiceFactoryXine(eAutoInitNumbers::service+1, "eServiceFactoryXine");
356 #else
357 #warning xine not available
358 #endif