|
1 /* |
|
2 * MP3/MPlayer plugin to VDR (C++) |
|
3 * |
|
4 * (C) 2001-2007 Stefan Huelswitt <s.huelswitt@gmx.de> |
|
5 * |
|
6 * This code is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU General Public License |
|
8 * as published by the Free Software Foundation; either version 2 |
|
9 * of the License, or (at your option) any later version. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 * GNU General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU General Public License |
|
17 * along with this program; if not, write to the Free Software |
|
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
19 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html |
|
20 */ |
|
21 |
|
22 #include <stdlib.h> |
|
23 #include <getopt.h> |
|
24 #include <strings.h> |
|
25 #include <typeinfo> |
|
26 |
|
27 #include "common.h" |
|
28 |
|
29 #include <vdr/menuitems.h> |
|
30 #include <vdr/status.h> |
|
31 #include <vdr/plugin.h> |
|
32 #if APIVERSNUM >= 10307 |
|
33 #include <vdr/interface.h> |
|
34 #include <vdr/skins.h> |
|
35 #endif |
|
36 |
|
37 #include "setup.h" |
|
38 #include "setup-mp3.h" |
|
39 #include "data-mp3.h" |
|
40 #include "data-src.h" |
|
41 #include "player-mp3.h" |
|
42 #include "menu.h" |
|
43 #include "menu-async.h" |
|
44 #include "decoder.h" |
|
45 #include "i18n.h" |
|
46 #include "version.h" |
|
47 #include "service.h" |
|
48 |
|
49 #ifdef DEBUG |
|
50 #include <mad.h> |
|
51 #endif |
|
52 |
|
53 const char *sourcesSub=0; |
|
54 cFileSources MP3Sources; |
|
55 |
|
56 // --- cMenuSetupMP3 -------------------------------------------------------- |
|
57 |
|
58 class cMenuSetupMP3 : public cMenuSetupPage { |
|
59 private: |
|
60 cMP3Setup data; |
|
61 // |
|
62 const char *cddb[3], *disp[2], *scan[3], *bgr[3]; |
|
63 const char *aout[AUDIOOUTMODES]; |
|
64 int amode, amodes[AUDIOOUTMODES]; |
|
65 protected: |
|
66 virtual void Store(void); |
|
67 public: |
|
68 cMenuSetupMP3(void); |
|
69 }; |
|
70 |
|
71 cMenuSetupMP3::cMenuSetupMP3(void) |
|
72 { |
|
73 static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789-_" }; |
|
74 int numModes=0; |
|
75 aout[numModes]=tr("DVB"); amodes[numModes]=AUDIOOUTMODE_DVB; numModes++; |
|
76 #ifdef WITH_OSS |
|
77 aout[numModes]=tr("OSS"); amodes[numModes]=AUDIOOUTMODE_OSS; numModes++; |
|
78 #endif |
|
79 data=MP3Setup; |
|
80 amode=0; |
|
81 for(int i=0; i<numModes; i++) |
|
82 if(amodes[i]==data.AudioOutMode) { amode=i; break; } |
|
83 |
|
84 SetSection(tr("MP3")); |
|
85 Add(new cMenuEditStraItem(tr("Setup.MP3$Audio output mode"), &amode,numModes,aout)); |
|
86 Add(new cMenuEditBoolItem(tr("Setup.MP3$Audio mode"), &data.AudioMode, tr("Round"), tr("Dither"))); |
|
87 Add(new cMenuEditBoolItem(tr("Setup.MP3$Use 48kHz mode only"), &data.Only48kHz)); |
|
88 #if APIVERSNUM >= 10307 |
|
89 disp[0]=tr("classic"); |
|
90 disp[1]=tr("via skin"); |
|
91 Add(new cMenuEditStraItem(tr("Setup.MP3$Replay display"), &data.ReplayDisplay, 2, disp)); |
|
92 #endif |
|
93 Add(new cMenuEditIntItem( tr("Setup.MP3$Display mode"), &data.DisplayMode, 1, 3)); |
|
94 bgr[0]=tr("Black"); |
|
95 bgr[1]=tr("Live"); |
|
96 bgr[2]=tr("Images"); |
|
97 Add(new cMenuEditStraItem(tr("Setup.MP3$Background mode"), &data.BackgrMode, 3, bgr)); |
|
98 Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial loop mode"), &data.InitLoopMode)); |
|
99 Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial shuffle mode"), &data.InitShuffleMode)); |
|
100 Add(new cMenuEditBoolItem(tr("Setup.MP3$Abort player at end of list"),&data.AbortAtEOL)); |
|
101 scan[0]=tr("disabled"); |
|
102 scan[1]=tr("ID3 only"); |
|
103 scan[2]=tr("ID3 & Level"); |
|
104 Add(new cMenuEditStraItem(tr("Setup.MP3$Background scan"), &data.BgrScan, 3, scan)); |
|
105 Add(new cMenuEditBoolItem(tr("Setup.MP3$Editor display mode"), &data.EditorMode, tr("Filenames"), tr("ID3 names"))); |
|
106 Add(new cMenuEditBoolItem(tr("Setup.MP3$Mainmenu mode"), &data.MenuMode, tr("Playlists"), tr("Browser"))); |
|
107 Add(new cMenuEditBoolItem(tr("Setup.MP3$Keep selection menu"), &data.KeepSelect)); |
|
108 Add(new cMenuEditBoolItem(tr("Setup.MP3$Title/Artist order"), &data.TitleArtistOrder, tr("Normal"), tr("Reversed"))); |
|
109 Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu)); |
|
110 Add(new cMenuEditIntItem( tr("Setup.MP3$Normalizer level"), &data.TargetLevel, 0, MAX_TARGET_LEVEL)); |
|
111 Add(new cMenuEditIntItem( tr("Setup.MP3$Limiter level"), &data.LimiterLevel, MIN_LIMITER_LEVEL, 100)); |
|
112 Add(new cMenuEditBoolItem(tr("Setup.MP3$Use HTTP proxy"), &data.UseProxy)); |
|
113 Add(new cMenuEditStrItem( tr("Setup.MP3$HTTP proxy host"), data.ProxyHost,MAX_HOSTNAME,allowed)); |
|
114 Add(new cMenuEditIntItem( tr("Setup.MP3$HTTP proxy port"), &data.ProxyPort,1,65535)); |
|
115 cddb[0]=tr("disabled"); |
|
116 cddb[1]=tr("local only"); |
|
117 cddb[2]=tr("local&remote"); |
|
118 Add(new cMenuEditStraItem(tr("Setup.MP3$CDDB for CD-Audio"), &data.UseCddb,3,cddb)); |
|
119 Add(new cMenuEditStrItem( tr("Setup.MP3$CDDB server"), data.CddbHost,MAX_HOSTNAME,allowed)); |
|
120 Add(new cMenuEditIntItem( tr("Setup.MP3$CDDB port"), &data.CddbPort,1,65535)); |
|
121 } |
|
122 |
|
123 void cMenuSetupMP3::Store(void) |
|
124 { |
|
125 data.AudioOutMode=amodes[amode]; |
|
126 |
|
127 MP3Setup=data; |
|
128 SetupStore("InitLoopMode", MP3Setup.InitLoopMode ); |
|
129 SetupStore("InitShuffleMode", MP3Setup.InitShuffleMode); |
|
130 SetupStore("AudioMode", MP3Setup.AudioMode ); |
|
131 SetupStore("AudioOutMode", MP3Setup.AudioOutMode ); |
|
132 SetupStore("BgrScan", MP3Setup.BgrScan ); |
|
133 SetupStore("EditorMode", MP3Setup.EditorMode ); |
|
134 SetupStore("DisplayMode", MP3Setup.DisplayMode ); |
|
135 SetupStore("BackgrMode", MP3Setup.BackgrMode ); |
|
136 SetupStore("MenuMode", MP3Setup.MenuMode ); |
|
137 SetupStore("TargetLevel", MP3Setup.TargetLevel ); |
|
138 SetupStore("LimiterLevel", MP3Setup.LimiterLevel ); |
|
139 SetupStore("Only48kHz", MP3Setup.Only48kHz ); |
|
140 SetupStore("UseProxy", MP3Setup.UseProxy ); |
|
141 SetupStore("ProxyHost", MP3Setup.ProxyHost ); |
|
142 SetupStore("ProxyPort", MP3Setup.ProxyPort ); |
|
143 SetupStore("UseCddb", MP3Setup.UseCddb ); |
|
144 SetupStore("CddbHost", MP3Setup.CddbHost ); |
|
145 SetupStore("CddbPort", MP3Setup.CddbPort ); |
|
146 SetupStore("AbortAtEOL", MP3Setup.AbortAtEOL ); |
|
147 #if APIVERSNUM >= 10307 |
|
148 SetupStore("ReplayDisplay", MP3Setup.ReplayDisplay ); |
|
149 #endif |
|
150 SetupStore("HideMainMenu", MP3Setup.HideMainMenu ); |
|
151 SetupStore("KeepSelect", MP3Setup.KeepSelect ); |
|
152 SetupStore("TitleArtistOrder", MP3Setup.TitleArtistOrder); |
|
153 } |
|
154 |
|
155 // --- cAsyncStatus ------------------------------------------------------------ |
|
156 |
|
157 cAsyncStatus asyncStatus; |
|
158 |
|
159 cAsyncStatus::cAsyncStatus(void) |
|
160 { |
|
161 text=0; |
|
162 changed=false; |
|
163 } |
|
164 |
|
165 cAsyncStatus::~cAsyncStatus() |
|
166 { |
|
167 free((void *)text); |
|
168 } |
|
169 |
|
170 void cAsyncStatus::Set(const char *Text) |
|
171 { |
|
172 Lock(); |
|
173 free((void *)text); |
|
174 text=Text ? strdup(Text) : 0; |
|
175 changed=true; |
|
176 Unlock(); |
|
177 } |
|
178 |
|
179 const char *cAsyncStatus::Begin(void) |
|
180 { |
|
181 Lock(); |
|
182 return text; |
|
183 } |
|
184 |
|
185 void cAsyncStatus::Finish(void) |
|
186 { |
|
187 changed=false; |
|
188 Unlock(); |
|
189 } |
|
190 |
|
191 // --- -------------------------------------------------------------------- |
|
192 |
|
193 static const char *TitleArtist(const char *title, const char *artist) |
|
194 { |
|
195 static char buf[256]; // clearly not multi-thread save! |
|
196 char *fmt; |
|
197 if(artist && artist[0]) { |
|
198 if(MP3Setup.TitleArtistOrder) fmt="%2$s - %1$s"; |
|
199 else fmt="%s - %s"; |
|
200 } |
|
201 else fmt="%s"; |
|
202 snprintf(buf,sizeof(buf),fmt,title,artist); |
|
203 return buf; |
|
204 } |
|
205 |
|
206 // --- cMP3Control -------------------------------------------------------- |
|
207 |
|
208 #if APIVERSNUM >= 10307 |
|
209 #define clrBackground clrGray50 |
|
210 #define eDvbColor int |
|
211 #define MAXROWS 120 |
|
212 #define INLINE |
|
213 #else |
|
214 #define MAXROWS MAXOSDHEIGHT |
|
215 #define INLINE inline |
|
216 #endif |
|
217 |
|
218 class cMP3Control : public cControl { |
|
219 private: |
|
220 #if APIVERSNUM >= 10307 |
|
221 cOsd *osd; |
|
222 const cFont *font; |
|
223 cSkinDisplayReplay *disp; |
|
224 #else |
|
225 bool statusInterfaceOpen; |
|
226 #endif |
|
227 int bw, bh, bwc, fw, fh; |
|
228 // |
|
229 cMP3Player *player; |
|
230 bool visible, shown, bigwin, statusActive; |
|
231 time_t timeoutShow, greentime, oktime; |
|
232 int lastkeytime, number; |
|
233 bool selecting, selecthide; |
|
234 // |
|
235 cMP3PlayInfo *lastMode; |
|
236 time_t fliptime, listtime; |
|
237 int hashlist[MAXROWS]; |
|
238 int flip, flipint, top, rows; |
|
239 int lastIndex, lastTotal, lastTop; |
|
240 int framesPerSecond; |
|
241 // |
|
242 bool jumpactive, jumphide, jumpsecs; |
|
243 int jumpmm; |
|
244 // |
|
245 void ShowTimed(int Seconds=0); |
|
246 void ShowProgress(bool open=false, bool bigWin=false); |
|
247 void ShowStatus(bool force); |
|
248 void HideStatus(void); |
|
249 void DisplayInfo(const char *s=0); |
|
250 void JumpDisplay(void); |
|
251 void JumpProcess(eKeys Key); |
|
252 void Jump(void); |
|
253 void Stop(void); |
|
254 INLINE void Write(int x, int y, int w, const char *text, eDvbColor fg=clrWhite, eDvbColor bg=clrBackground); |
|
255 INLINE void Fill(int x, int y, int w, int h, eDvbColor fg); |
|
256 inline void Flush(void); |
|
257 public: |
|
258 cMP3Control(void); |
|
259 virtual ~cMP3Control(); |
|
260 virtual eOSState ProcessKey(eKeys Key); |
|
261 virtual void Show(void) { ShowTimed(); } |
|
262 virtual void Hide(void); |
|
263 bool Visible(void) { return visible; } |
|
264 static bool SetPlayList(cPlayList *plist); |
|
265 }; |
|
266 |
|
267 cMP3Control::cMP3Control(void) |
|
268 :cControl(player=new cMP3Player) |
|
269 { |
|
270 visible=shown=bigwin=selecting=selecthide=jumpactive=jumphide=statusActive=false; |
|
271 timeoutShow=greentime=oktime=0; |
|
272 lastkeytime=number=0; |
|
273 lastMode=0; |
|
274 framesPerSecond=SecondsToFrames(1); |
|
275 #if APIVERSNUM >= 10307 |
|
276 osd=0; disp=0; |
|
277 font=cFont::GetFont(fontOsd); |
|
278 #else |
|
279 statusInterfaceOpen=false; |
|
280 #endif |
|
281 #if APIVERSNUM >= 10338 |
|
282 cStatus::MsgReplaying(this,"MP3",0,true); |
|
283 #else |
|
284 cStatus::MsgReplaying(this,"MP3"); |
|
285 #endif |
|
286 } |
|
287 |
|
288 cMP3Control::~cMP3Control() |
|
289 { |
|
290 delete lastMode; |
|
291 Hide(); |
|
292 Stop(); |
|
293 } |
|
294 |
|
295 void cMP3Control::Stop(void) |
|
296 { |
|
297 #if APIVERSNUM >= 10338 |
|
298 cStatus::MsgReplaying(this,0,0,false); |
|
299 #else |
|
300 cStatus::MsgReplaying(this,0); |
|
301 #endif |
|
302 delete player; player=0; |
|
303 mgr->Halt(); |
|
304 mgr->Flush(); //XXX remove later |
|
305 } |
|
306 |
|
307 bool cMP3Control::SetPlayList(cPlayList *plist) |
|
308 { |
|
309 bool res; |
|
310 cControl *control=cControl::Control(); |
|
311 // is there a running MP3 player? |
|
312 if(control && typeid(*control)==typeid(cMP3Control)) { |
|
313 // add songs to running playlist |
|
314 mgr->Add(plist); |
|
315 res=true; |
|
316 } |
|
317 else { |
|
318 mgr->Flush(); |
|
319 mgr->Add(plist); |
|
320 cControl::Launch(new cMP3Control); |
|
321 res=false; |
|
322 } |
|
323 delete plist; |
|
324 return res; |
|
325 } |
|
326 |
|
327 void cMP3Control::ShowTimed(int Seconds) |
|
328 { |
|
329 if(!visible) { |
|
330 ShowProgress(true); |
|
331 if(Seconds>0) timeoutShow=time(0)+Seconds; |
|
332 } |
|
333 } |
|
334 |
|
335 void cMP3Control::Hide(void) |
|
336 { |
|
337 HideStatus(); |
|
338 if(visible) { |
|
339 #if APIVERSNUM >= 10307 |
|
340 delete osd; osd=0; |
|
341 delete disp; disp=0; |
|
342 #else |
|
343 Interface->Close(); |
|
344 #endif |
|
345 visible=bigwin=false; |
|
346 #if APIVERSNUM >= 10500 |
|
347 SetNeedsFastResponse(false); |
|
348 #else |
|
349 needsFastResponse=false; |
|
350 #endif |
|
351 } |
|
352 } |
|
353 |
|
354 void cMP3Control::ShowStatus(bool force) |
|
355 { |
|
356 if((asyncStatus.Changed() || (force && !statusActive)) && !jumpactive) { |
|
357 const char *text=asyncStatus.Begin(); |
|
358 if(text) { |
|
359 #if APIVERSNUM >= 10307 |
|
360 if(MP3Setup.ReplayDisplay || !osd) { |
|
361 if(statusActive) Skins.Message(mtStatus,0); |
|
362 Skins.Message(mtStatus,text); |
|
363 } |
|
364 else { |
|
365 if(!statusActive) osd->SaveRegion(0,bh-2*fh,bw-1,bh-fh-1); |
|
366 osd->DrawText(0,bh-2*fh,text,clrBlack,clrCyan,font,bw,fh,taCenter); |
|
367 osd->Flush(); |
|
368 } |
|
369 #else |
|
370 if(!Interface->IsOpen()) { |
|
371 Interface->Open(0,-1); |
|
372 statusInterfaceOpen=true; |
|
373 } |
|
374 Interface->Status(text); |
|
375 Interface->Flush(); |
|
376 #endif |
|
377 statusActive=true; |
|
378 } |
|
379 else |
|
380 HideStatus(); |
|
381 asyncStatus.Finish(); |
|
382 } |
|
383 } |
|
384 |
|
385 void cMP3Control::HideStatus(void) |
|
386 { |
|
387 if(statusActive) { |
|
388 #if APIVERSNUM >= 10307 |
|
389 if(MP3Setup.ReplayDisplay || !osd) |
|
390 Skins.Message(mtStatus,0); |
|
391 else { |
|
392 osd->RestoreRegion(); |
|
393 osd->Flush(); |
|
394 } |
|
395 #else |
|
396 if(statusInterfaceOpen) { |
|
397 Interface->Close(); |
|
398 statusInterfaceOpen=false; |
|
399 } |
|
400 else { |
|
401 Interface->Status(0); |
|
402 Interface->Flush(); |
|
403 } |
|
404 #endif |
|
405 } |
|
406 statusActive=false; |
|
407 } |
|
408 |
|
409 #define CTAB 11 // some tabbing values for the progress display |
|
410 #define CTAB2 5 |
|
411 |
|
412 void cMP3Control::Write(int x, int y, int w, const char *text, eDvbColor fg, eDvbColor bg) |
|
413 { |
|
414 #if APIVERSNUM >= 10307 |
|
415 if(osd) { |
|
416 //d(printf("write x=%d y=%d w=%d ->",x,y,w)) |
|
417 x*=fw; if(x<0) x+=bw; |
|
418 y*=fh; if(y<0) y+=bh; |
|
419 osd->DrawText(x,y,text,fg,bg,font,w*fw); |
|
420 //d(printf(" x=%d y=%d w=%d\n",x,y,w*fw)) |
|
421 } |
|
422 #else |
|
423 if(w>0) Fill(x,y,w,1,bg); |
|
424 Interface->Write(x,y,text,fg,bg); |
|
425 #endif |
|
426 } |
|
427 |
|
428 void cMP3Control::Fill(int x, int y, int w, int h, eDvbColor fg) |
|
429 { |
|
430 #if APIVERSNUM >= 10307 |
|
431 if(osd) { |
|
432 //d(printf("fill x=%d y=%d w=%d h=%d ->",x,y,w,h)) |
|
433 x*=fw; if(x<0) x+=bw; |
|
434 y*=fh; if(y<0) y+=bh; |
|
435 osd->DrawRectangle(x,y,x+w*fw-1,y+h*fh-1,fg); |
|
436 //d(printf(" x=%d y=%d x2=%d y2=%d\n",x,y,x+h*fh-1,y+w*fw-1)) |
|
437 } |
|
438 #else |
|
439 Interface->Fill(x,y,w,h,fg); |
|
440 #endif |
|
441 } |
|
442 |
|
443 void cMP3Control::Flush(void) |
|
444 { |
|
445 #if APIVERSNUM >= 10307 |
|
446 if(MP3Setup.ReplayDisplay) Skins.Flush(); |
|
447 else if(osd) osd->Flush(); |
|
448 #else |
|
449 Interface->Flush(); |
|
450 #endif |
|
451 } |
|
452 |
|
453 void cMP3Control::ShowProgress(bool open, bool bigWin) |
|
454 { |
|
455 int index, total; |
|
456 |
|
457 if(player->GetIndex(index,total) && total>=0) { |
|
458 if(!visible && open) { |
|
459 HideStatus(); |
|
460 #if APIVERSNUM >= 10307 |
|
461 if(MP3Setup.ReplayDisplay) { |
|
462 disp=Skins.Current()->DisplayReplay(false); |
|
463 if(!disp) return; |
|
464 bigWin=false; |
|
465 } |
|
466 else { |
|
467 int bt, bp; |
|
468 fw=font->Width(' ')*2; |
|
469 fh=font->Height(); |
|
470 if(bigWin) { |
|
471 bw=Setup.OSDWidth; |
|
472 bh=Setup.OSDHeight; |
|
473 bt=0; |
|
474 bp=2*fh; |
|
475 rows=(bh-bp-fh/3)/fh; |
|
476 } |
|
477 else { |
|
478 bw=Setup.OSDWidth; |
|
479 bh=bp=2*fh; |
|
480 bt=Setup.OSDHeight-bh; |
|
481 rows=0; |
|
482 } |
|
483 bwc=bw/fw+1; |
|
484 //d(printf("mp3: bw=%d bh=%d bt=%d bp=%d bwc=%d rows=%d fw=%d fh=%d\n", |
|
485 // bw,bh,bt,bp,bwc,rows,fw,fh)) |
|
486 osd=cOsdProvider::NewOsd(Setup.OSDLeft,Setup.OSDTop+bt); |
|
487 if(!osd) return; |
|
488 if(bigWin) { |
|
489 tArea Areas[] = { { 0,0,bw-1,bh-bp-1,2 }, { 0,bh-bp,bw-1,bh-1,4 } }; |
|
490 osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); |
|
491 } |
|
492 else { |
|
493 tArea Areas[] = { { 0,0,bw-1,bh-1,4 } }; |
|
494 osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea)); |
|
495 } |
|
496 osd->DrawRectangle(0,0,bw-1,bh-1,clrGray50); |
|
497 osd->Flush(); |
|
498 } |
|
499 #else |
|
500 fw=cOsd::CellWidth(); |
|
501 fh=cOsd::LineHeight(); |
|
502 bh=bigWin ? Setup.OSDheight : -2; |
|
503 bw=bwc=Setup.OSDwidth; |
|
504 rows=Setup.OSDheight-3; |
|
505 Interface->Open(bw,bh); |
|
506 Interface->Clear(); |
|
507 #endif |
|
508 ShowStatus(true); |
|
509 bigwin=bigWin; |
|
510 visible=true; |
|
511 #if APIVERSNUM >= 10500 |
|
512 SetNeedsFastResponse(true); |
|
513 #else |
|
514 needsFastResponse=true; |
|
515 #endif |
|
516 fliptime=listtime=0; flipint=0; flip=-1; top=lastTop=-1; lastIndex=lastTotal=-1; |
|
517 delete lastMode; lastMode=0; |
|
518 } |
|
519 |
|
520 cMP3PlayInfo *mode=new cMP3PlayInfo; |
|
521 bool valid=mgr->Info(-1,mode); |
|
522 bool changed=(!lastMode || mode->Hash!=lastMode->Hash); |
|
523 char buf[256]; |
|
524 if(changed) { d(printf("mp3-ctrl: mode change detected\n")) } |
|
525 |
|
526 if(valid) { // send progress to status monitor |
|
527 if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) { |
|
528 snprintf(buf,sizeof(buf),"[%c%c] (%d/%d) %s", |
|
529 mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,TitleArtist(mode->Title,mode->Artist)); |
|
530 #if APIVERSNUM >= 10338 |
|
531 cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true); |
|
532 #else |
|
533 cStatus::MsgReplaying(this,buf); |
|
534 #endif |
|
535 } |
|
536 } |
|
537 |
|
538 if(visible) { // refresh the OSD progress display |
|
539 bool flush=false; |
|
540 |
|
541 #if APIVERSNUM >= 10307 |
|
542 if(MP3Setup.ReplayDisplay) { |
|
543 if(!statusActive) { |
|
544 if(total>0) disp->SetProgress(index,total); |
|
545 disp->SetCurrent(IndexToHMSF(index)); |
|
546 disp->SetTotal(IndexToHMSF(total)); |
|
547 bool Play, Forward; |
|
548 int Speed; |
|
549 if(GetReplayMode(Play,Forward,Speed)) |
|
550 disp->SetMode(Play, Forward, Speed); |
|
551 flush=true; |
|
552 } |
|
553 } |
|
554 else { |
|
555 #endif |
|
556 if(!selecting && changed && !statusActive) { |
|
557 snprintf(buf,sizeof(buf),"(%d/%d)",mode->Num,mode->MaxNum); |
|
558 Write(0,-2,CTAB,buf); |
|
559 flush=true; |
|
560 } |
|
561 |
|
562 if(!lastMode || mode->Loop!=lastMode->Loop) { |
|
563 if(mode->Loop) Write(-4,-1,0,"L",clrBlack,clrYellow); |
|
564 else Fill(-4,-1,2,1,clrBackground); |
|
565 flush=true; |
|
566 } |
|
567 if(!lastMode || mode->Shuffle!=lastMode->Shuffle) { |
|
568 if(mode->Shuffle) Write(-2,-1,0,"S",clrWhite,clrRed); |
|
569 else Fill(-2,-1,2,1,clrBackground); |
|
570 flush=true; |
|
571 } |
|
572 |
|
573 index/=framesPerSecond; total/=framesPerSecond; |
|
574 if(index!=lastIndex || total!=lastTotal) { |
|
575 if(total>0) { |
|
576 #if APIVERSNUM >= 10307 |
|
577 cProgressBar ProgressBar(bw-(CTAB+CTAB2)*fw,fh,index,total); |
|
578 osd->DrawBitmap(CTAB*fw,bh-fh,ProgressBar); |
|
579 #else |
|
580 cProgressBar ProgressBar((bw-CTAB-CTAB2)*fw,fh,index,total); |
|
581 Interface->SetBitmap(CTAB*fw,(abs(bh)-1)*fh,ProgressBar); |
|
582 #endif |
|
583 } |
|
584 snprintf(buf,sizeof(buf),total?"%02d:%02d/%02d:%02d":"%02d:%02d",index/60,index%60,total/60,total%60); |
|
585 Write(0,-1,11,buf); |
|
586 flush=true; |
|
587 } |
|
588 #if APIVERSNUM >= 10307 |
|
589 } |
|
590 #endif |
|
591 |
|
592 if(!jumpactive) { |
|
593 bool doflip=false; |
|
594 if(MP3Setup.ReplayDisplay && (!lastMode || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle)) |
|
595 doflip=true; |
|
596 if(!valid || changed) { |
|
597 fliptime=time(0); flip=0; |
|
598 doflip=true; |
|
599 } |
|
600 else if(time(0)>fliptime+flipint) { |
|
601 fliptime=time(0); |
|
602 flip++; if(flip>=MP3Setup.DisplayMode) flip=0; |
|
603 doflip=true; |
|
604 } |
|
605 if(doflip) { |
|
606 buf[0]=0; |
|
607 switch(flip) { |
|
608 default: |
|
609 flip=0; |
|
610 // fall through |
|
611 case 0: |
|
612 snprintf(buf,sizeof(buf),"%s",TitleArtist(mode->Title,mode->Artist)); |
|
613 flipint=6; |
|
614 break; |
|
615 case 1: |
|
616 if(mode->Album[0]) { |
|
617 snprintf(buf,sizeof(buf),mode->Year>0?"from: %s (%d)":"from: %s",mode->Album,mode->Year); |
|
618 flipint=4; |
|
619 } |
|
620 else fliptime=0; |
|
621 break; |
|
622 case 2: |
|
623 if(mode->MaxBitrate>0) |
|
624 snprintf(buf,sizeof(buf),"%.1f kHz, %d-%d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->MaxBitrate/1000,mode->SMode); |
|
625 else |
|
626 snprintf(buf,sizeof(buf),"%.1f kHz, %d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->SMode); |
|
627 flipint=3; |
|
628 break; |
|
629 } |
|
630 if(buf[0]) { |
|
631 #if APIVERSNUM >= 10307 |
|
632 if(MP3Setup.ReplayDisplay) { |
|
633 char buf2[256]; |
|
634 snprintf(buf2,sizeof(buf2),"[%c%c] (%d/%d) %s", |
|
635 mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,buf); |
|
636 disp->SetTitle(buf2); |
|
637 flush=true; |
|
638 } |
|
639 else { |
|
640 #endif |
|
641 if(!statusActive) { |
|
642 DisplayInfo(buf); |
|
643 flush=true; |
|
644 } |
|
645 else { d(printf("mp3-ctrl: display info skip due to status active\n")) } |
|
646 #if APIVERSNUM >= 10307 |
|
647 } |
|
648 #endif |
|
649 } |
|
650 } |
|
651 } |
|
652 |
|
653 if(bigwin) { |
|
654 bool all=(top!=lastTop || changed); |
|
655 if(all || time(0)>listtime+2) { |
|
656 int num=(top>0 && mode->Num==lastMode->Num) ? top : mode->Num - rows/2; |
|
657 if(num+rows>mode->MaxNum) num=mode->MaxNum-rows+1; |
|
658 if(num<1) num=1; |
|
659 top=num; |
|
660 for(int i=0 ; i<rows && i<MAXROWS && num<=mode->MaxNum ; i++,num++) { |
|
661 cMP3PlayInfo pi; |
|
662 mgr->Info(num,&pi); if(!pi.Title[0]) break; |
|
663 snprintf(buf,sizeof(buf),"%d.\t%s",num,TitleArtist(pi.Title,pi.Artist)); |
|
664 eDvbColor fg=clrWhite, bg=clrBackground; |
|
665 int hash=MakeHash(buf); |
|
666 if(num==mode->Num) { fg=clrBlack; bg=clrCyan; hash=(hash^77) + 23; } |
|
667 if(all || hash!=hashlist[i]) { |
|
668 char *s=rindex(buf,'\t'); |
|
669 if(s) { |
|
670 *s++=0; |
|
671 Write(0,i,5,buf,fg,bg); |
|
672 Write(5,i,bwc-5,s,fg,bg); |
|
673 } |
|
674 else |
|
675 Write(0,i,bwc,buf,fg,bg); |
|
676 flush=true; |
|
677 hashlist[i]=hash; |
|
678 } |
|
679 } |
|
680 listtime=time(0); lastTop=top; |
|
681 } |
|
682 } |
|
683 |
|
684 if(flush) Flush(); |
|
685 } |
|
686 |
|
687 lastIndex=index; lastTotal=total; |
|
688 delete lastMode; lastMode=mode; |
|
689 } |
|
690 } |
|
691 |
|
692 void cMP3Control::DisplayInfo(const char *s) |
|
693 { |
|
694 if(s) Write(CTAB,-2,bwc-CTAB,s); |
|
695 else Fill(CTAB,-2,bwc-CTAB,1,clrBackground); |
|
696 } |
|
697 |
|
698 void cMP3Control::JumpDisplay(void) |
|
699 { |
|
700 char buf[64]; |
|
701 const char *j=tr("Jump: "), u=jumpsecs?'s':'m'; |
|
702 if(!jumpmm) sprintf(buf,"%s- %c", j,u); |
|
703 else sprintf(buf,"%s%d- %c",j,jumpmm,u); |
|
704 #if APIVERSNUM >= 10307 |
|
705 if(MP3Setup.ReplayDisplay) { |
|
706 disp->SetJump(buf); |
|
707 } |
|
708 else { |
|
709 #endif |
|
710 DisplayInfo(buf); |
|
711 #if APIVERSNUM >= 10307 |
|
712 } |
|
713 #endif |
|
714 } |
|
715 |
|
716 void cMP3Control::JumpProcess(eKeys Key) |
|
717 { |
|
718 int n=Key-k0, d=jumpsecs?1:60; |
|
719 switch (Key) { |
|
720 case k0 ... k9: |
|
721 if(jumpmm*10+n <= lastTotal/d) jumpmm=jumpmm*10+n; |
|
722 JumpDisplay(); |
|
723 break; |
|
724 case kBlue: |
|
725 jumpsecs=!jumpsecs; |
|
726 JumpDisplay(); |
|
727 break; |
|
728 case kPlay: |
|
729 case kUp: |
|
730 jumpmm-=lastIndex/d; |
|
731 // fall through |
|
732 case kFastRew: |
|
733 case kFastFwd: |
|
734 case kLeft: |
|
735 case kRight: |
|
736 player->SkipSeconds(jumpmm*d * ((Key==kLeft || Key==kFastRew) ? -1:1)); |
|
737 // fall through |
|
738 default: |
|
739 jumpactive=false; |
|
740 break; |
|
741 } |
|
742 |
|
743 if(!jumpactive) { |
|
744 if(jumphide) Hide(); |
|
745 #if APIVERSNUM >= 10307 |
|
746 else if(MP3Setup.ReplayDisplay) disp->SetJump(0); |
|
747 #endif |
|
748 } |
|
749 } |
|
750 |
|
751 void cMP3Control::Jump(void) |
|
752 { |
|
753 jumpmm=0; jumphide=jumpsecs=false; |
|
754 if(!visible) { |
|
755 ShowTimed(); if(!visible) return; |
|
756 jumphide=true; |
|
757 } |
|
758 JumpDisplay(); |
|
759 jumpactive=true; fliptime=0; flip=-1; |
|
760 } |
|
761 |
|
762 eOSState cMP3Control::ProcessKey(eKeys Key) |
|
763 { |
|
764 if(!player->Active()) return osEnd; |
|
765 |
|
766 if(visible && timeoutShow && time(0)>timeoutShow) { Hide(); timeoutShow=0; } |
|
767 ShowProgress(); |
|
768 #if APIVERSNUM >= 10307 |
|
769 ShowStatus(Key==kNone && !Skins.IsOpen()); |
|
770 #else |
|
771 ShowStatus(Key==kNone && !Interface->IsOpen()); |
|
772 #endif |
|
773 |
|
774 if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; } |
|
775 |
|
776 switch(Key) { |
|
777 case kUp: |
|
778 case kUp|k_Repeat: |
|
779 #if APIVERSNUM >= 10347 |
|
780 case kNext: |
|
781 case kNext|k_Repeat: |
|
782 #endif |
|
783 mgr->Next(); player->Play(); |
|
784 break; |
|
785 case kDown: |
|
786 case kDown|k_Repeat: |
|
787 #if APIVERSNUM >= 10347 |
|
788 case kPrev: |
|
789 case kPrev|k_Repeat: |
|
790 #endif |
|
791 if(!player->PrevCheck()) mgr->Prev(); |
|
792 player->Play(); |
|
793 break; |
|
794 case kLeft: |
|
795 case kLeft|k_Repeat: |
|
796 if(bigwin) { |
|
797 if(top>0) { top-=rows; if(top<1) top=1; } |
|
798 break; |
|
799 } |
|
800 // fall through |
|
801 case kFastRew: |
|
802 case kFastRew|k_Repeat: |
|
803 if(!player->IsStream()) player->SkipSeconds(-JUMPSIZE); |
|
804 break; |
|
805 case kRight: |
|
806 case kRight|k_Repeat: |
|
807 if(bigwin) { |
|
808 if(top>0) top+=rows; |
|
809 break; |
|
810 } |
|
811 // fall through |
|
812 case kFastFwd: |
|
813 case kFastFwd|k_Repeat: |
|
814 if(!player->IsStream()) player->SkipSeconds(JUMPSIZE); |
|
815 break; |
|
816 case kRed: |
|
817 if(!player->IsStream()) Jump(); |
|
818 break; |
|
819 case kGreen: |
|
820 if(lastMode) { |
|
821 if(time(0)>greentime) { |
|
822 if(lastMode->Loop || (!lastMode->Loop && !lastMode->Shuffle)) mgr->ToggleLoop(); |
|
823 if(lastMode->Shuffle) mgr->ToggleShuffle(); |
|
824 } |
|
825 else { |
|
826 if(!lastMode->Loop) mgr->ToggleLoop(); |
|
827 else if(!lastMode->Shuffle) mgr->ToggleShuffle(); |
|
828 else mgr->ToggleLoop(); |
|
829 } |
|
830 greentime=time(0)+MULTI_TIMEOUT; |
|
831 } |
|
832 break; |
|
833 case kPlay: |
|
834 player->Play(); |
|
835 break; |
|
836 case kPause: |
|
837 case kYellow: |
|
838 if(!player->IsStream()) player->Pause(); |
|
839 break; |
|
840 case kStop: |
|
841 case kBlue: |
|
842 Hide(); |
|
843 Stop(); |
|
844 return osEnd; |
|
845 case kBack: |
|
846 Hide(); |
|
847 #if APIVERSNUM >= 10332 |
|
848 cRemote::CallPlugin(i18n_name); |
|
849 return osBack; |
|
850 #else |
|
851 return osEnd; |
|
852 #endif |
|
853 |
|
854 case k0 ... k9: |
|
855 number=number*10+Key-k0; |
|
856 if(lastMode && number>0 && number<=lastMode->MaxNum) { |
|
857 if(!visible) { ShowTimed(); selecthide=true; } |
|
858 selecting=true; lastkeytime=time_ms(); |
|
859 char buf[32]; |
|
860 #if APIVERSNUM >= 10307 |
|
861 if(MP3Setup.ReplayDisplay) { |
|
862 snprintf(buf,sizeof(buf),"%s%d-/%d",tr("Jump: "),number,lastMode->MaxNum); |
|
863 disp->SetJump(buf); |
|
864 } |
|
865 else { |
|
866 #endif |
|
867 snprintf(buf,sizeof(buf),"(%d-/%d)",number,lastMode->MaxNum); |
|
868 Write(0,-2,CTAB,buf); |
|
869 #if APIVERSNUM >= 10307 |
|
870 } |
|
871 #endif |
|
872 Flush(); |
|
873 break; |
|
874 } |
|
875 number=0; lastkeytime=0; |
|
876 // fall through |
|
877 case kNone: |
|
878 if(selecting && time_ms()-lastkeytime>SELECT_TIMEOUT) { |
|
879 if(number>0) { mgr->Goto(number); player->Play(); } |
|
880 if(selecthide) timeoutShow=time(0)+SELECTHIDE_TIMEOUT; |
|
881 if(lastMode) lastMode->Hash=-1; |
|
882 number=0; selecting=selecthide=false; |
|
883 #if APIVERSNUM >= 10307 |
|
884 if(MP3Setup.ReplayDisplay) disp->SetJump(0); |
|
885 #endif |
|
886 } |
|
887 break; |
|
888 case kOk: |
|
889 if(time(0)>oktime || MP3Setup.ReplayDisplay) { |
|
890 visible ? Hide() : ShowTimed(); |
|
891 } |
|
892 else { |
|
893 if(visible && !bigwin) { Hide(); ShowProgress(true,true); } |
|
894 else { Hide(); ShowTimed(); } |
|
895 } |
|
896 oktime=time(0)+MULTI_TIMEOUT; |
|
897 ShowStatus(true); |
|
898 break; |
|
899 default: |
|
900 return osUnknown; |
|
901 } |
|
902 return osContinue; |
|
903 } |
|
904 |
|
905 // --- cMenuID3Info ------------------------------------------------------------ |
|
906 |
|
907 class cMenuID3Info : public cOsdMenu { |
|
908 private: |
|
909 cOsdItem *Item(const char *name, const char *text); |
|
910 cOsdItem *Item(const char *name, const char *format, const float num); |
|
911 void Build(cSongInfo *info, const char *name); |
|
912 public: |
|
913 cMenuID3Info(cSong *song); |
|
914 cMenuID3Info(cSongInfo *si, const char *name); |
|
915 virtual eOSState ProcessKey(eKeys Key); |
|
916 }; |
|
917 |
|
918 cMenuID3Info::cMenuID3Info(cSong *song) |
|
919 :cOsdMenu(tr("ID3 information"),12) |
|
920 { |
|
921 Build(song->Info(),song->Name()); |
|
922 } |
|
923 |
|
924 cMenuID3Info::cMenuID3Info(cSongInfo *si, const char *name) |
|
925 :cOsdMenu(tr("ID3 information"),12) |
|
926 { |
|
927 Build(si,name); |
|
928 } |
|
929 |
|
930 void cMenuID3Info::Build(cSongInfo *si, const char *name) |
|
931 { |
|
932 if(si) { |
|
933 Item(tr("Filename"),name); |
|
934 if(si->HasInfo() && si->Total>0) { |
|
935 char *buf=0; |
|
936 asprintf(&buf,"%02d:%02d",si->Total/60,si->Total%60); |
|
937 Item(tr("Length"),buf); |
|
938 free(buf); |
|
939 Item(tr("Title"),si->Title); |
|
940 Item(tr("Artist"),si->Artist); |
|
941 Item(tr("Album"),si->Album); |
|
942 Item(tr("Year"),0,(float)si->Year); |
|
943 Item(tr("Samplerate"),"%.1f kHz",si->SampleFreq/1000.0); |
|
944 Item(tr("Bitrate"),"%.f kbit/s",si->Bitrate/1000.0); |
|
945 Item(tr("Channels"),0,(float)si->Channels); |
|
946 } |
|
947 Display(); |
|
948 } |
|
949 } |
|
950 |
|
951 cOsdItem *cMenuID3Info::Item(const char *name, const char *format, const float num) |
|
952 { |
|
953 cOsdItem *item; |
|
954 if(num>=0.0) { |
|
955 char *buf=0; |
|
956 asprintf(&buf,format?format:"%.f",num); |
|
957 item=Item(name,buf); |
|
958 free(buf); |
|
959 } |
|
960 else item=Item(name,""); |
|
961 return item; |
|
962 } |
|
963 |
|
964 cOsdItem *cMenuID3Info::Item(const char *name, const char *text) |
|
965 { |
|
966 char *buf=0; |
|
967 asprintf(&buf,"%s:\t%s",name,text?text:""); |
|
968 cOsdItem *item = new cOsdItem(buf,osBack); |
|
969 #if APIVERSNUM >= 10307 |
|
970 item->SetSelectable(false); |
|
971 #else |
|
972 item->SetColor(clrWhite, clrBackground); |
|
973 #endif |
|
974 free(buf); |
|
975 Add(item); return item; |
|
976 } |
|
977 |
|
978 eOSState cMenuID3Info::ProcessKey(eKeys Key) |
|
979 { |
|
980 eOSState state = cOsdMenu::ProcessKey(Key); |
|
981 |
|
982 if(state==osUnknown) { |
|
983 switch(Key) { |
|
984 case kRed: |
|
985 case kGreen: |
|
986 case kYellow: |
|
987 case kBlue: return osContinue; |
|
988 case kMenu: return osEnd; |
|
989 default: break; |
|
990 } |
|
991 } |
|
992 return state; |
|
993 } |
|
994 |
|
995 // --- cMenuInstantBrowse ------------------------------------------------------- |
|
996 |
|
997 class cMenuInstantBrowse : public cMenuBrowse { |
|
998 private: |
|
999 const char *selecttext, *alltext; |
|
1000 virtual void SetButtons(void); |
|
1001 virtual eOSState ID3Info(void); |
|
1002 public: |
|
1003 cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext); |
|
1004 virtual eOSState ProcessKey(eKeys Key); |
|
1005 }; |
|
1006 |
|
1007 cMenuInstantBrowse::cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext) |
|
1008 :cMenuBrowse(Source,true,true,tr("Directory browser"),excl_br) |
|
1009 { |
|
1010 selecttext=Selecttext; alltext=Alltext; |
|
1011 SetButtons(); |
|
1012 } |
|
1013 |
|
1014 void cMenuInstantBrowse::SetButtons(void) |
|
1015 { |
|
1016 SetHelp(selecttext, currentdir?tr("Parent"):0, currentdir?0:alltext, tr("ID3 info")); |
|
1017 Display(); |
|
1018 } |
|
1019 |
|
1020 eOSState cMenuInstantBrowse::ID3Info(void) |
|
1021 { |
|
1022 cFileObj *item=CurrentItem(); |
|
1023 if(item && item->Type()==otFile) { |
|
1024 cSong *song=new cSong(item); |
|
1025 cSongInfo *si; |
|
1026 if(song && (si=song->Info())) { |
|
1027 AddSubMenu(new cMenuID3Info(si,item->Path())); |
|
1028 } |
|
1029 delete song; |
|
1030 } |
|
1031 return osContinue; |
|
1032 } |
|
1033 |
|
1034 eOSState cMenuInstantBrowse::ProcessKey(eKeys Key) |
|
1035 { |
|
1036 eOSState state=cOsdMenu::ProcessKey(Key); |
|
1037 if(state==osUnknown) { |
|
1038 switch (Key) { |
|
1039 case kYellow: lastselect=new cFileObj(source,0,0,otBase); |
|
1040 return osBack; |
|
1041 default: break; |
|
1042 } |
|
1043 } |
|
1044 if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state); |
|
1045 return state; |
|
1046 } |
|
1047 |
|
1048 // --- cMenuPlayListItem ------------------------------------------------------- |
|
1049 |
|
1050 class cMenuPlayListItem : public cOsdItem { |
|
1051 private: |
|
1052 bool showID3; |
|
1053 cSong *song; |
|
1054 public: |
|
1055 cMenuPlayListItem(cSong *Song, bool showid3); |
|
1056 cSong *Song(void) { return song; } |
|
1057 virtual void Set(void); |
|
1058 void Set(bool showid3); |
|
1059 }; |
|
1060 |
|
1061 cMenuPlayListItem::cMenuPlayListItem(cSong *Song, bool showid3) |
|
1062 { |
|
1063 song=Song; |
|
1064 Set(showid3); |
|
1065 } |
|
1066 |
|
1067 void cMenuPlayListItem::Set(bool showid3) |
|
1068 { |
|
1069 showID3=showid3; |
|
1070 Set(); |
|
1071 } |
|
1072 |
|
1073 void cMenuPlayListItem::Set(void) |
|
1074 { |
|
1075 char *buffer=0; |
|
1076 cSongInfo *si=song->Info(false); |
|
1077 if(showID3 && !si) si=song->Info(); |
|
1078 if(showID3 && si && si->Title) |
|
1079 asprintf(&buffer, "%d.\t%s",song->Index()+1,TitleArtist(si->Title,si->Artist)); |
|
1080 else |
|
1081 asprintf(&buffer, "%d.\t<%s>",song->Index()+1,song->Name()); |
|
1082 SetText(buffer,false); |
|
1083 } |
|
1084 |
|
1085 // --- cMenuPlayList ------------------------------------------------------ |
|
1086 |
|
1087 class cMenuPlayList : public cOsdMenu { |
|
1088 private: |
|
1089 cPlayList *playlist; |
|
1090 bool browsing, showid3; |
|
1091 void Buttons(void); |
|
1092 void Refresh(bool all = false); |
|
1093 void Add(void); |
|
1094 virtual void Move(int From, int To); |
|
1095 eOSState Remove(void); |
|
1096 eOSState ShowID3(void); |
|
1097 eOSState ID3Info(void); |
|
1098 public: |
|
1099 cMenuPlayList(cPlayList *Playlist); |
|
1100 virtual eOSState ProcessKey(eKeys Key); |
|
1101 }; |
|
1102 |
|
1103 cMenuPlayList::cMenuPlayList(cPlayList *Playlist) |
|
1104 :cOsdMenu(tr("Playlist editor"),4) |
|
1105 { |
|
1106 browsing=showid3=false; |
|
1107 playlist=Playlist; |
|
1108 if(MP3Setup.EditorMode) showid3=true; |
|
1109 |
|
1110 cSong *mp3 = playlist->First(); |
|
1111 while(mp3) { |
|
1112 cOsdMenu::Add(new cMenuPlayListItem(mp3,showid3)); |
|
1113 mp3 = playlist->cList<cSong>::Next(mp3); |
|
1114 } |
|
1115 Buttons(); Display(); |
|
1116 } |
|
1117 |
|
1118 void cMenuPlayList::Buttons(void) |
|
1119 { |
|
1120 SetHelp(tr("Add"), showid3?tr("Filenames"):tr("ID3 names"), tr("Remove"), tr(BUTTON"Mark")); |
|
1121 } |
|
1122 |
|
1123 void cMenuPlayList::Refresh(bool all) |
|
1124 { |
|
1125 cMenuPlayListItem *cur=(cMenuPlayListItem *)((all || Count()<2) ? First() : Get(Current())); |
|
1126 while(cur) { |
|
1127 cur->Set(showid3); |
|
1128 cur=(cMenuPlayListItem *)Next(cur); |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 void cMenuPlayList::Add(void) |
|
1133 { |
|
1134 cFileObj *item=cMenuInstantBrowse::GetSelected(); |
|
1135 if(item) { |
|
1136 Status(tr("Scanning directory...")); |
|
1137 cInstantPlayList *newpl=new cInstantPlayList(item); |
|
1138 if(newpl->Load()) { |
|
1139 if(newpl->Count()) { |
|
1140 if(newpl->Count()==1 || Interface->Confirm(tr("Add recursivly?"))) { |
|
1141 cSong *mp3=newpl->First(); |
|
1142 while(mp3) { |
|
1143 cSong *n=new cSong(mp3); |
|
1144 if(Count()>0) { |
|
1145 cMenuPlayListItem *current=(cMenuPlayListItem *)Get(Current()); |
|
1146 playlist->Add(n,current->Song()); |
|
1147 cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true,current); |
|
1148 } |
|
1149 else { |
|
1150 playlist->Add(n); |
|
1151 cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true); |
|
1152 } |
|
1153 mp3=newpl->cList<cSong>::Next(mp3); |
|
1154 } |
|
1155 playlist->Save(); |
|
1156 Refresh(); Display(); |
|
1157 } |
|
1158 } |
|
1159 else Error(tr("Empty directory!")); |
|
1160 } |
|
1161 else Error(tr("Error scanning directory!")); |
|
1162 delete newpl; |
|
1163 Status(0); |
|
1164 } |
|
1165 } |
|
1166 |
|
1167 void cMenuPlayList::Move(int From, int To) |
|
1168 { |
|
1169 playlist->Move(From,To); playlist->Save(); |
|
1170 cOsdMenu::Move(From,To); |
|
1171 Refresh(true); Display(); |
|
1172 } |
|
1173 |
|
1174 eOSState cMenuPlayList::ShowID3(void) |
|
1175 { |
|
1176 showid3=!showid3; |
|
1177 Buttons(); Refresh(true); Display(); |
|
1178 return osContinue; |
|
1179 } |
|
1180 |
|
1181 eOSState cMenuPlayList::ID3Info(void) |
|
1182 { |
|
1183 if(Count()>0) { |
|
1184 cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); |
|
1185 AddSubMenu(new cMenuID3Info(current->Song())); |
|
1186 } |
|
1187 return osContinue; |
|
1188 } |
|
1189 |
|
1190 eOSState cMenuPlayList::Remove(void) |
|
1191 { |
|
1192 if(Count()>0) { |
|
1193 cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current()); |
|
1194 if(Interface->Confirm(tr("Remove entry?"))) { |
|
1195 playlist->Del(current->Song()); playlist->Save(); |
|
1196 cOsdMenu::Del(Current()); |
|
1197 Refresh(); Display(); |
|
1198 } |
|
1199 } |
|
1200 return osContinue; |
|
1201 } |
|
1202 |
|
1203 eOSState cMenuPlayList::ProcessKey(eKeys Key) |
|
1204 { |
|
1205 eOSState state = cOsdMenu::ProcessKey(Key); |
|
1206 |
|
1207 if(browsing && !HasSubMenu() && state==osContinue) { Add(); browsing=false; } |
|
1208 |
|
1209 if(state==osUnknown) { |
|
1210 switch(Key) { |
|
1211 case kOk: return ID3Info(); |
|
1212 case kRed: browsing=true; |
|
1213 return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr("Add"),tr("Add all"))); |
|
1214 case kGreen: return ShowID3(); |
|
1215 case kYellow: return Remove(); |
|
1216 case kBlue: Mark(); return osContinue; |
|
1217 case kMenu: return osEnd; |
|
1218 default: break; |
|
1219 } |
|
1220 } |
|
1221 return state; |
|
1222 } |
|
1223 |
|
1224 // --- cPlaylistRename -------------------------------------------------------- |
|
1225 |
|
1226 class cPlaylistRename : public cOsdMenu { |
|
1227 private: |
|
1228 static char *newname; |
|
1229 const char *oldname; |
|
1230 char data[64]; |
|
1231 public: |
|
1232 cPlaylistRename(const char *Oldname); |
|
1233 virtual eOSState ProcessKey(eKeys Key); |
|
1234 static const char *GetNewname(void) { return newname; } |
|
1235 }; |
|
1236 |
|
1237 char *cPlaylistRename::newname = NULL; |
|
1238 |
|
1239 cPlaylistRename::cPlaylistRename(const char *Oldname) |
|
1240 :cOsdMenu(tr("Rename playlist"), 15) |
|
1241 { |
|
1242 free(newname); newname=0; |
|
1243 |
|
1244 oldname=Oldname; |
|
1245 char *buf=NULL; |
|
1246 asprintf(&buf,"%s\t%s",tr("Old name:"),oldname); |
|
1247 cOsdItem *old = new cOsdItem(buf,osContinue); |
|
1248 #if APIVERSNUM >= 10307 |
|
1249 old->SetSelectable(false); |
|
1250 #else |
|
1251 old->SetColor(clrWhite, clrBackground); |
|
1252 #endif |
|
1253 Add(old); |
|
1254 free(buf); |
|
1255 |
|
1256 data[0]=0; |
|
1257 Add(new cMenuEditStrItem( tr("New name"), data, sizeof(data)-1, tr(FileNameChars)),true); |
|
1258 } |
|
1259 |
|
1260 eOSState cPlaylistRename::ProcessKey(eKeys Key) |
|
1261 { |
|
1262 eOSState state = cOsdMenu::ProcessKey(Key); |
|
1263 |
|
1264 if (state == osUnknown) { |
|
1265 switch (Key) { |
|
1266 case kOk: if(data[0] && strcmp(data,oldname)) newname=strdup(data); |
|
1267 return osBack; |
|
1268 case kRed: |
|
1269 case kGreen: |
|
1270 case kYellow: |
|
1271 case kBlue: return osContinue; |
|
1272 default: break; |
|
1273 } |
|
1274 } |
|
1275 return state; |
|
1276 } |
|
1277 |
|
1278 // --- cMenuMP3Item ----------------------------------------------------- |
|
1279 |
|
1280 class cMenuMP3Item : public cOsdItem { |
|
1281 private: |
|
1282 cPlayList *playlist; |
|
1283 virtual void Set(void); |
|
1284 public: |
|
1285 cMenuMP3Item(cPlayList *PlayList); |
|
1286 cPlayList *List(void) { return playlist; } |
|
1287 }; |
|
1288 |
|
1289 cMenuMP3Item::cMenuMP3Item(cPlayList *PlayList) |
|
1290 { |
|
1291 playlist=PlayList; |
|
1292 Set(); |
|
1293 } |
|
1294 |
|
1295 void cMenuMP3Item::Set(void) |
|
1296 { |
|
1297 char *buffer=0; |
|
1298 asprintf(&buffer," %s",playlist->BaseName()); |
|
1299 SetText(buffer,false); |
|
1300 } |
|
1301 |
|
1302 // --- cMenuMP3 -------------------------------------------------------- |
|
1303 |
|
1304 class cMenuMP3 : public cOsdMenu { |
|
1305 private: |
|
1306 cPlayLists *lists; |
|
1307 bool renaming, sourcing, instanting; |
|
1308 int buttonnum; |
|
1309 eOSState Play(void); |
|
1310 eOSState Edit(void); |
|
1311 eOSState New(void); |
|
1312 eOSState Delete(void); |
|
1313 eOSState Rename(bool second); |
|
1314 eOSState Source(bool second); |
|
1315 eOSState Instant(bool second); |
|
1316 void ScanLists(void); |
|
1317 eOSState SetButtons(int num); |
|
1318 public: |
|
1319 cMenuMP3(void); |
|
1320 ~cMenuMP3(void); |
|
1321 virtual eOSState ProcessKey(eKeys Key); |
|
1322 }; |
|
1323 |
|
1324 cMenuMP3::cMenuMP3(void) |
|
1325 :cOsdMenu(tr("MP3")) |
|
1326 { |
|
1327 renaming=sourcing=instanting=false; |
|
1328 lists=new cPlayLists; |
|
1329 ScanLists(); SetButtons(1); |
|
1330 if(MP3Setup.MenuMode) Instant(false); |
|
1331 } |
|
1332 |
|
1333 cMenuMP3::~cMenuMP3(void) |
|
1334 { |
|
1335 delete lists; |
|
1336 } |
|
1337 |
|
1338 eOSState cMenuMP3::SetButtons(int num) |
|
1339 { |
|
1340 switch(num) { |
|
1341 case 1: |
|
1342 SetHelp(tr(BUTTON"Edit"), tr("Source"), tr("Browse"), ">>"); |
|
1343 break; |
|
1344 case 2: |
|
1345 SetHelp("<<", tr(BUTTON"New"), tr(BUTTON"Delete"), tr("Rename")); |
|
1346 break; |
|
1347 } |
|
1348 buttonnum=num; Display(); |
|
1349 return osContinue; |
|
1350 } |
|
1351 |
|
1352 void cMenuMP3::ScanLists(void) |
|
1353 { |
|
1354 Clear(); |
|
1355 Status(tr("Scanning playlists...")); |
|
1356 bool res=lists->Load(MP3Sources.GetSource()); |
|
1357 Status(0); |
|
1358 if(res) { |
|
1359 cPlayList *plist=lists->First(); |
|
1360 while(plist) { |
|
1361 Add(new cMenuMP3Item(plist)); |
|
1362 plist=lists->Next(plist); |
|
1363 } |
|
1364 } |
|
1365 else Error(tr("Error scanning playlists!")); |
|
1366 } |
|
1367 |
|
1368 eOSState cMenuMP3::Delete(void) |
|
1369 { |
|
1370 if(Count()>0) { |
|
1371 if(Interface->Confirm(tr("Delete playlist?")) && |
|
1372 Interface->Confirm(tr("Are you sure?")) ) { |
|
1373 cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); |
|
1374 if(plist->Delete()) { |
|
1375 lists->Del(plist); |
|
1376 cOsdMenu::Del(Current()); |
|
1377 Display(); |
|
1378 } |
|
1379 else Error(tr("Error deleting playlist!")); |
|
1380 } |
|
1381 } |
|
1382 return osContinue; |
|
1383 } |
|
1384 |
|
1385 eOSState cMenuMP3::New(void) |
|
1386 { |
|
1387 cPlayList *plist=new cPlayList(MP3Sources.GetSource(),0,0); |
|
1388 char name[32]; |
|
1389 int i=0; |
|
1390 do { |
|
1391 if(i) sprintf(name,"%s%d",tr("unnamed"),i++); |
|
1392 else { strcpy(name,tr("unnamed")); i++; } |
|
1393 } while(plist->TestName(name)); |
|
1394 |
|
1395 if(plist->Create(name)) { |
|
1396 lists->Add(plist); |
|
1397 Add(new cMenuMP3Item(plist), true); |
|
1398 |
|
1399 isyslog("MP3: playlist %s added", plist->Name()); |
|
1400 return AddSubMenu(new cMenuPlayList(plist)); |
|
1401 } |
|
1402 Error(tr("Error creating playlist!")); |
|
1403 delete plist; |
|
1404 return osContinue; |
|
1405 } |
|
1406 |
|
1407 eOSState cMenuMP3::Rename(bool second) |
|
1408 { |
|
1409 if(HasSubMenu() || Count() == 0) return osContinue; |
|
1410 |
|
1411 cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); |
|
1412 if(!second) { |
|
1413 renaming=true; |
|
1414 return AddSubMenu(new cPlaylistRename(plist->BaseName())); |
|
1415 } |
|
1416 renaming=false; |
|
1417 const char *newname=cPlaylistRename::GetNewname(); |
|
1418 if(newname) { |
|
1419 if(plist->Rename(newname)) { |
|
1420 RefreshCurrent(); |
|
1421 DisplayCurrent(true); |
|
1422 } |
|
1423 else Error(tr("Error renaming playlist!")); |
|
1424 } |
|
1425 return osContinue; |
|
1426 } |
|
1427 |
|
1428 eOSState cMenuMP3::Edit(void) |
|
1429 { |
|
1430 if(HasSubMenu() || Count() == 0) return osContinue; |
|
1431 |
|
1432 cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List(); |
|
1433 if(!plist->Load()) Error(tr("Error loading playlist!")); |
|
1434 else if(!plist->IsWinAmp()) { |
|
1435 isyslog("MP3: editing playlist %s", plist->Name()); |
|
1436 return AddSubMenu(new cMenuPlayList(plist)); |
|
1437 } |
|
1438 else Error(tr("Can't edit a WinAmp playlist!")); |
|
1439 return osContinue; |
|
1440 } |
|
1441 |
|
1442 eOSState cMenuMP3::Play(void) |
|
1443 { |
|
1444 if(HasSubMenu() || Count() == 0) return osContinue; |
|
1445 |
|
1446 Status(tr("Loading playlist...")); |
|
1447 cPlayList *newpl=new cPlayList(((cMenuMP3Item *)Get(Current()))->List()); |
|
1448 if(newpl->Load() && newpl->Count()) { |
|
1449 isyslog("mp3: playback started with playlist %s", newpl->Name()); |
|
1450 cMP3Control::SetPlayList(newpl); |
|
1451 if(MP3Setup.KeepSelect) { Status(0); return osContinue; } |
|
1452 return osEnd; |
|
1453 } |
|
1454 Status(0); |
|
1455 delete newpl; |
|
1456 Error(tr("Error loading playlist!")); |
|
1457 return osContinue; |
|
1458 } |
|
1459 |
|
1460 eOSState cMenuMP3::Source(bool second) |
|
1461 { |
|
1462 if(HasSubMenu()) return osContinue; |
|
1463 |
|
1464 if(!second) { |
|
1465 sourcing=true; |
|
1466 return AddSubMenu(new cMenuSource(&MP3Sources,tr("MP3 source"))); |
|
1467 } |
|
1468 sourcing=false; |
|
1469 cFileSource *src=cMenuSource::GetSelected(); |
|
1470 if(src) { |
|
1471 MP3Sources.SetSource(src); |
|
1472 ScanLists(); |
|
1473 Display(); |
|
1474 } |
|
1475 return osContinue; |
|
1476 } |
|
1477 |
|
1478 eOSState cMenuMP3::Instant(bool second) |
|
1479 { |
|
1480 if(HasSubMenu()) return osContinue; |
|
1481 |
|
1482 if(!second) { |
|
1483 instanting=true; |
|
1484 return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr(BUTTON"Play"),tr("Play all"))); |
|
1485 } |
|
1486 instanting=false; |
|
1487 cFileObj *item=cMenuInstantBrowse::GetSelected(); |
|
1488 if(item) { |
|
1489 Status(tr("Building playlist...")); |
|
1490 cInstantPlayList *newpl = new cInstantPlayList(item); |
|
1491 if(newpl->Load() && newpl->Count()) { |
|
1492 isyslog("mp3: playback started with instant playlist %s", newpl->Name()); |
|
1493 cMP3Control::SetPlayList(newpl); |
|
1494 if(MP3Setup.KeepSelect) { Status(0); return Instant(false); } |
|
1495 return osEnd; |
|
1496 } |
|
1497 Status(0); |
|
1498 delete newpl; |
|
1499 Error(tr("Error building playlist!")); |
|
1500 } |
|
1501 return osContinue; |
|
1502 } |
|
1503 |
|
1504 eOSState cMenuMP3::ProcessKey(eKeys Key) |
|
1505 { |
|
1506 eOSState state = cOsdMenu::ProcessKey(Key); |
|
1507 |
|
1508 if(!HasSubMenu() && state==osContinue) { // eval the return value from submenus |
|
1509 if(renaming) return Rename(true); |
|
1510 if(sourcing) return Source(true); |
|
1511 if(instanting) return Instant(true); |
|
1512 } |
|
1513 |
|
1514 if(state == osUnknown) { |
|
1515 switch(Key) { |
|
1516 case kOk: return Play(); |
|
1517 case kRed: return (buttonnum==1 ? Edit() : SetButtons(1)); |
|
1518 case kGreen: return (buttonnum==1 ? Source(false) : New()); |
|
1519 case kYellow: return (buttonnum==1 ? Instant(false) : Delete()); |
|
1520 case kBlue: return (buttonnum==1 ? SetButtons(2) : Rename(false)); |
|
1521 case kMenu: return osEnd; |
|
1522 default: break; |
|
1523 } |
|
1524 } |
|
1525 return state; |
|
1526 } |
|
1527 |
|
1528 // --- PropagateImage ---------------------------------------------------------- |
|
1529 |
|
1530 void PropagateImage(const char *image) |
|
1531 { |
|
1532 cPlugin *graphtft=cPluginManager::GetPlugin("graphtft"); |
|
1533 if(graphtft) graphtft->SetupParse("CoverImage",image ? image:""); |
|
1534 } |
|
1535 |
|
1536 // --- cPluginMP3 -------------------------------------------------------------- |
|
1537 |
|
1538 static const char *VERSION = PLUGIN_VERSION; |
|
1539 static const char *DESCRIPTION = "A versatile audio player"; |
|
1540 static const char *MAINMENUENTRY = "MP3"; |
|
1541 |
|
1542 class cPluginMp3 : public cPlugin { |
|
1543 private: |
|
1544 #if APIVERSNUM >= 10330 |
|
1545 bool ExternalPlay(const char *path, bool test); |
|
1546 #endif |
|
1547 public: |
|
1548 cPluginMp3(void); |
|
1549 virtual ~cPluginMp3(); |
|
1550 virtual const char *Version(void) { return VERSION; } |
|
1551 virtual const char *Description(void) { return tr(DESCRIPTION); } |
|
1552 virtual const char *CommandLineHelp(void); |
|
1553 virtual bool ProcessArgs(int argc, char *argv[]); |
|
1554 #if APIVERSNUM >= 10131 |
|
1555 virtual bool Initialize(void); |
|
1556 #else |
|
1557 virtual bool Start(void); |
|
1558 #endif |
|
1559 virtual void Housekeeping(void); |
|
1560 virtual const char *MainMenuEntry(void); |
|
1561 virtual cOsdObject *MainMenuAction(void); |
|
1562 virtual cMenuSetupPage *SetupMenu(void); |
|
1563 virtual bool SetupParse(const char *Name, const char *Value); |
|
1564 #if APIVERSNUM >= 10330 |
|
1565 virtual bool Service(const char *Id, void *Data); |
|
1566 #if APIVERSNUM >= 10331 |
|
1567 virtual const char **SVDRPHelpPages(void); |
|
1568 virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); |
|
1569 #endif |
|
1570 #endif |
|
1571 }; |
|
1572 |
|
1573 cPluginMp3::cPluginMp3(void) |
|
1574 { |
|
1575 // Initialize any member varaiables here. |
|
1576 // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL |
|
1577 // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! |
|
1578 } |
|
1579 |
|
1580 cPluginMp3::~cPluginMp3() |
|
1581 { |
|
1582 InfoCache.Save(); |
|
1583 delete mgr; |
|
1584 } |
|
1585 |
|
1586 const char *cPluginMp3::CommandLineHelp(void) |
|
1587 { |
|
1588 static char *help_str=0; |
|
1589 |
|
1590 free(help_str); // for easier orientation, this is column 80| |
|
1591 asprintf(&help_str," -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n" |
|
1592 " (default: %s)\n" |
|
1593 " -n CMD, --network=CMD execute CMD before & after network access\n" |
|
1594 " (default: %s)\n" |
|
1595 " -C DIR, --cache=DIR store ID3 cache file in DIR\n" |
|
1596 " (default: %s)\n" |
|
1597 " -B DIR, --cddb=DIR search CDDB files in DIR\n" |
|
1598 " (default: %s)\n" |
|
1599 " -D DEV, --dsp=DEV device for OSS output\n" |
|
1600 " (default: %s)\n" |
|
1601 " -i CMD, --iconv=CMD use CMD to convert background images\n" |
|
1602 " (default: %s)\n" |
|
1603 " -c DIR, --icache=DIR cache converted images in DIR\n" |
|
1604 " (default: %s)\n" |
|
1605 " -S SUB, --sources=SUB search sources config in SUB subdirectory\n" |
|
1606 " (default: %s)\n", |
|
1607 |
|
1608 mountscript, |
|
1609 netscript ? netscript:"none", |
|
1610 cachedir ? cachedir:"video dir", |
|
1611 #ifdef HAVE_SNDFILE |
|
1612 cddbpath, |
|
1613 #else |
|
1614 "none", |
|
1615 #endif |
|
1616 #ifdef WITH_OSS |
|
1617 dspdevice, |
|
1618 #else |
|
1619 "none", |
|
1620 #endif |
|
1621 imageconv, |
|
1622 imagecache, |
|
1623 sourcesSub ? sourcesSub:"empty" |
|
1624 ); |
|
1625 return help_str; |
|
1626 } |
|
1627 |
|
1628 bool cPluginMp3::ProcessArgs(int argc, char *argv[]) |
|
1629 { |
|
1630 static struct option long_options[] = { |
|
1631 { "mount", required_argument, NULL, 'm' }, |
|
1632 { "network", required_argument, NULL, 'n' }, |
|
1633 { "cddb", required_argument, NULL, 'B' }, |
|
1634 { "dsp", required_argument, NULL, 'D' }, |
|
1635 { "cache", required_argument, NULL, 'C' }, |
|
1636 { "icache", required_argument, NULL, 'c' }, |
|
1637 { "iconv", required_argument, NULL, 'i' }, |
|
1638 { "sources", required_argument, NULL, 'S' }, |
|
1639 { NULL } |
|
1640 }; |
|
1641 |
|
1642 int c, option_index = 0; |
|
1643 while((c=getopt_long(argc,argv,"c:i:m:n:B:C:D:S:",long_options,&option_index))!=-1) { |
|
1644 switch (c) { |
|
1645 case 'i': imageconv=optarg; break; |
|
1646 case 'c': imagecache=optarg; break; |
|
1647 case 'm': mountscript=optarg; break; |
|
1648 case 'n': netscript=optarg; break; |
|
1649 case 'C': cachedir=optarg; break; |
|
1650 case 'S': sourcesSub=optarg; break; |
|
1651 case 'B': |
|
1652 #ifdef HAVE_SNDFILE |
|
1653 cddbpath=optarg; break; |
|
1654 #else |
|
1655 fprintf(stderr, "mp3: libsndfile support has not been compiled in!\n"); return false; |
|
1656 #endif |
|
1657 case 'D': |
|
1658 #ifdef WITH_OSS |
|
1659 dspdevice=optarg; break; |
|
1660 #else |
|
1661 fprintf(stderr, "mp3: OSS output has not been compiled in!\n"); return false; |
|
1662 #endif |
|
1663 default: return false; |
|
1664 } |
|
1665 } |
|
1666 return true; |
|
1667 } |
|
1668 |
|
1669 #if APIVERSNUM >= 10131 |
|
1670 bool cPluginMp3::Initialize(void) |
|
1671 #else |
|
1672 bool cPluginMp3::Start(void) |
|
1673 #endif |
|
1674 { |
|
1675 if(!CheckVDRVersion(1,1,29,"mp3")) return false; |
|
1676 i18n_name=Name(); |
|
1677 MP3Sources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mp3sources.conf")); |
|
1678 if(MP3Sources.Count()<1) { |
|
1679 esyslog("ERROR: you should have defined at least one source in mp3sources.conf"); |
|
1680 fprintf(stderr,"No source(s) defined in mp3sources.conf\n"); |
|
1681 return false; |
|
1682 } |
|
1683 InfoCache.Load(); |
|
1684 RegisterI18n(Phrases); |
|
1685 mgr=new cPlayManager; |
|
1686 if(!mgr) { |
|
1687 esyslog("ERROR: creating playmanager failed"); |
|
1688 fprintf(stderr,"Creating playmanager failed\n"); |
|
1689 return false; |
|
1690 } |
|
1691 d(printf("mp3: using %s\n",mad_version)) |
|
1692 d(printf("mp3: compiled with %s\n",MAD_VERSION)) |
|
1693 return true; |
|
1694 } |
|
1695 |
|
1696 void cPluginMp3::Housekeeping(void) |
|
1697 { |
|
1698 InfoCache.Save(); |
|
1699 } |
|
1700 |
|
1701 const char *cPluginMp3::MainMenuEntry(void) |
|
1702 { |
|
1703 return MP3Setup.HideMainMenu ? 0 : tr(MAINMENUENTRY); |
|
1704 } |
|
1705 |
|
1706 cOsdObject *cPluginMp3::MainMenuAction(void) |
|
1707 { |
|
1708 return new cMenuMP3; |
|
1709 } |
|
1710 |
|
1711 cMenuSetupPage *cPluginMp3::SetupMenu(void) |
|
1712 { |
|
1713 return new cMenuSetupMP3; |
|
1714 } |
|
1715 |
|
1716 bool cPluginMp3::SetupParse(const char *Name, const char *Value) |
|
1717 { |
|
1718 if (!strcasecmp(Name, "InitLoopMode")) MP3Setup.InitLoopMode = atoi(Value); |
|
1719 else if (!strcasecmp(Name, "InitShuffleMode")) MP3Setup.InitShuffleMode = atoi(Value); |
|
1720 else if (!strcasecmp(Name, "AudioMode")) MP3Setup.AudioMode = atoi(Value); |
|
1721 else if (!strcasecmp(Name, "BgrScan")) MP3Setup.BgrScan = atoi(Value); |
|
1722 else if (!strcasecmp(Name, "EditorMode")) MP3Setup.EditorMode = atoi(Value); |
|
1723 else if (!strcasecmp(Name, "DisplayMode")) MP3Setup.DisplayMode = atoi(Value); |
|
1724 else if (!strcasecmp(Name, "BackgrMode")) MP3Setup.BackgrMode = atoi(Value); |
|
1725 else if (!strcasecmp(Name, "MenuMode")) MP3Setup.MenuMode = atoi(Value); |
|
1726 else if (!strcasecmp(Name, "TargetLevel")) MP3Setup.TargetLevel = atoi(Value); |
|
1727 else if (!strcasecmp(Name, "LimiterLevel")) MP3Setup.LimiterLevel = atoi(Value); |
|
1728 else if (!strcasecmp(Name, "Only48kHz")) MP3Setup.Only48kHz = atoi(Value); |
|
1729 else if (!strcasecmp(Name, "UseProxy")) MP3Setup.UseProxy = atoi(Value); |
|
1730 else if (!strcasecmp(Name, "ProxyHost")) strn0cpy(MP3Setup.ProxyHost,Value,MAX_HOSTNAME); |
|
1731 else if (!strcasecmp(Name, "ProxyPort")) MP3Setup.ProxyPort = atoi(Value); |
|
1732 else if (!strcasecmp(Name, "UseCddb")) MP3Setup.UseCddb = atoi(Value); |
|
1733 else if (!strcasecmp(Name, "CddbHost")) strn0cpy(MP3Setup.CddbHost,Value,MAX_HOSTNAME); |
|
1734 else if (!strcasecmp(Name, "CddbPort")) MP3Setup.CddbPort = atoi(Value); |
|
1735 else if (!strcasecmp(Name, "AbortAtEOL")) MP3Setup.AbortAtEOL = atoi(Value); |
|
1736 else if (!strcasecmp(Name, "AudioOutMode")) { |
|
1737 MP3Setup.AudioOutMode = atoi(Value); |
|
1738 #ifndef WITH_OSS |
|
1739 if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) { |
|
1740 esyslog("WARNING: AudioOutMode OSS not supported, falling back to DVB"); |
|
1741 MP3Setup.AudioOutMode=AUDIOOUTMODE_DVB; |
|
1742 } |
|
1743 #endif |
|
1744 } |
|
1745 #if APIVERSNUM >= 10307 |
|
1746 else if (!strcasecmp(Name, "ReplayDisplay")) MP3Setup.ReplayDisplay = atoi(Value); |
|
1747 #endif |
|
1748 else if (!strcasecmp(Name, "HideMainMenu")) MP3Setup.HideMainMenu = atoi(Value); |
|
1749 else if (!strcasecmp(Name, "KeepSelect")) MP3Setup.KeepSelect = atoi(Value); |
|
1750 else if (!strcasecmp(Name, "TitleArtistOrder")) MP3Setup.TitleArtistOrder = atoi(Value); |
|
1751 else return false; |
|
1752 return true; |
|
1753 } |
|
1754 |
|
1755 #if APIVERSNUM >= 10330 |
|
1756 |
|
1757 bool cPluginMp3::ExternalPlay(const char *path, bool test) |
|
1758 { |
|
1759 char real[PATH_MAX+1]; |
|
1760 if(realpath(path,real)) { |
|
1761 cFileSource *src=MP3Sources.FindSource(real); |
|
1762 if(src) { |
|
1763 cFileObj *item=new cFileObj(src,0,0,otFile); |
|
1764 if(item) { |
|
1765 item->SplitAndSet(real); |
|
1766 if(item->GuessType()) { |
|
1767 if(item->Exists()) { |
|
1768 cInstantPlayList *pl=new cInstantPlayList(item); |
|
1769 if(pl && pl->Load() && pl->Count()) { |
|
1770 if(!test) cMP3Control::SetPlayList(pl); |
|
1771 else delete pl; |
|
1772 delete item; |
|
1773 return true; |
|
1774 } |
|
1775 else dsyslog("MP3 service: error building playlist"); |
|
1776 delete pl; |
|
1777 } |
|
1778 else dsyslog("MP3 service: cannot play '%s'",path); |
|
1779 } |
|
1780 else dsyslog("MP3 service: GuessType() failed for '%s'",path); |
|
1781 delete item; |
|
1782 } |
|
1783 } |
|
1784 else dsyslog("MP3 service: cannot find source for '%s', real '%s'",path,real); |
|
1785 } |
|
1786 else if(errno!=ENOENT && errno!=ENOTDIR) |
|
1787 esyslog("ERROR: realpath: %s: %s",path,strerror(errno)); |
|
1788 return false; |
|
1789 } |
|
1790 |
|
1791 bool cPluginMp3::Service(const char *Id, void *Data) |
|
1792 { |
|
1793 if(!strcasecmp(Id,"MP3-Play-v1")) { |
|
1794 if(Data) { |
|
1795 struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; |
|
1796 msd->result=ExternalPlay(msd->data.filename,false); |
|
1797 } |
|
1798 return true; |
|
1799 } |
|
1800 else if(!strcasecmp(Id,"MP3-Test-v1")) { |
|
1801 if(Data) { |
|
1802 struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data; |
|
1803 msd->result=ExternalPlay(msd->data.filename,true); |
|
1804 } |
|
1805 return true; |
|
1806 } |
|
1807 return false; |
|
1808 } |
|
1809 |
|
1810 #if APIVERSNUM >= 10331 |
|
1811 |
|
1812 const char **cPluginMp3::SVDRPHelpPages(void) |
|
1813 { |
|
1814 static const char *HelpPages[] = { |
|
1815 "PLAY <filename>\n" |
|
1816 " Triggers playback of file 'filename'.", |
|
1817 "TEST <filename>\n" |
|
1818 " Tests is playback of file 'filename' is possible.", |
|
1819 "CURR\n" |
|
1820 " Returns filename of song currently being replayed.", |
|
1821 NULL |
|
1822 }; |
|
1823 return HelpPages; |
|
1824 } |
|
1825 |
|
1826 cString cPluginMp3::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) |
|
1827 { |
|
1828 if(!strcasecmp(Command,"PLAY")) { |
|
1829 if(*Option) { |
|
1830 if(ExternalPlay(Option,false)) return "Playback triggered"; |
|
1831 else { ReplyCode=550; return "Playback failed"; } |
|
1832 } |
|
1833 else { ReplyCode=501; return "Missing filename"; } |
|
1834 } |
|
1835 else if(!strcasecmp(Command,"TEST")) { |
|
1836 if(*Option) { |
|
1837 if(ExternalPlay(Option,true)) return "Playback possible"; |
|
1838 else { ReplyCode=550; return "Playback not possible"; } |
|
1839 } |
|
1840 else { ReplyCode=501; return "Missing filename"; } |
|
1841 } |
|
1842 else if(!strcasecmp(Command,"CURR")) { |
|
1843 cControl *control=cControl::Control(); |
|
1844 if(control && typeid(*control)==typeid(cMP3Control)) { |
|
1845 cMP3PlayInfo mode; |
|
1846 if(mgr->Info(-1,&mode)) return mode.Filename; |
|
1847 else return "<unknown>"; |
|
1848 } |
|
1849 else { ReplyCode=550; return "No running playback"; } |
|
1850 } |
|
1851 return NULL; |
|
1852 } |
|
1853 |
|
1854 #endif // 1.3.31 |
|
1855 #endif // 1.3.30 |
|
1856 |
|
1857 VDRPLUGINCREATOR(cPluginMp3); // Don't touch this! |