1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/mp3.c Sat Dec 29 14:47:40 2007 +0100
1.3 @@ -0,0 +1,1857 @@
1.4 +/*
1.5 + * MP3/MPlayer plugin to VDR (C++)
1.6 + *
1.7 + * (C) 2001-2007 Stefan Huelswitt <s.huelswitt@gmx.de>
1.8 + *
1.9 + * This code is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License
1.11 + * as published by the Free Software Foundation; either version 2
1.12 + * of the License, or (at your option) any later version.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1.22 + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
1.23 + */
1.24 +
1.25 +#include <stdlib.h>
1.26 +#include <getopt.h>
1.27 +#include <strings.h>
1.28 +#include <typeinfo>
1.29 +
1.30 +#include "common.h"
1.31 +
1.32 +#include <vdr/menuitems.h>
1.33 +#include <vdr/status.h>
1.34 +#include <vdr/plugin.h>
1.35 +#if APIVERSNUM >= 10307
1.36 +#include <vdr/interface.h>
1.37 +#include <vdr/skins.h>
1.38 +#endif
1.39 +
1.40 +#include "setup.h"
1.41 +#include "setup-mp3.h"
1.42 +#include "data-mp3.h"
1.43 +#include "data-src.h"
1.44 +#include "player-mp3.h"
1.45 +#include "menu.h"
1.46 +#include "menu-async.h"
1.47 +#include "decoder.h"
1.48 +#include "i18n.h"
1.49 +#include "version.h"
1.50 +#include "service.h"
1.51 +
1.52 +#ifdef DEBUG
1.53 +#include <mad.h>
1.54 +#endif
1.55 +
1.56 +const char *sourcesSub=0;
1.57 +cFileSources MP3Sources;
1.58 +
1.59 +// --- cMenuSetupMP3 --------------------------------------------------------
1.60 +
1.61 +class cMenuSetupMP3 : public cMenuSetupPage {
1.62 +private:
1.63 + cMP3Setup data;
1.64 + //
1.65 + const char *cddb[3], *disp[2], *scan[3], *bgr[3];
1.66 + const char *aout[AUDIOOUTMODES];
1.67 + int amode, amodes[AUDIOOUTMODES];
1.68 +protected:
1.69 + virtual void Store(void);
1.70 +public:
1.71 + cMenuSetupMP3(void);
1.72 + };
1.73 +
1.74 +cMenuSetupMP3::cMenuSetupMP3(void)
1.75 +{
1.76 + static const char allowed[] = { "abcdefghijklmnopqrstuvwxyz0123456789-_" };
1.77 + int numModes=0;
1.78 + aout[numModes]=tr("DVB"); amodes[numModes]=AUDIOOUTMODE_DVB; numModes++;
1.79 +#ifdef WITH_OSS
1.80 + aout[numModes]=tr("OSS"); amodes[numModes]=AUDIOOUTMODE_OSS; numModes++;
1.81 +#endif
1.82 + data=MP3Setup;
1.83 + amode=0;
1.84 + for(int i=0; i<numModes; i++)
1.85 + if(amodes[i]==data.AudioOutMode) { amode=i; break; }
1.86 +
1.87 + SetSection(tr("MP3"));
1.88 + Add(new cMenuEditStraItem(tr("Setup.MP3$Audio output mode"), &amode,numModes,aout));
1.89 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Audio mode"), &data.AudioMode, tr("Round"), tr("Dither")));
1.90 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Use 48kHz mode only"), &data.Only48kHz));
1.91 +#if APIVERSNUM >= 10307
1.92 + disp[0]=tr("classic");
1.93 + disp[1]=tr("via skin");
1.94 + Add(new cMenuEditStraItem(tr("Setup.MP3$Replay display"), &data.ReplayDisplay, 2, disp));
1.95 +#endif
1.96 + Add(new cMenuEditIntItem( tr("Setup.MP3$Display mode"), &data.DisplayMode, 1, 3));
1.97 + bgr[0]=tr("Black");
1.98 + bgr[1]=tr("Live");
1.99 + bgr[2]=tr("Images");
1.100 + Add(new cMenuEditStraItem(tr("Setup.MP3$Background mode"), &data.BackgrMode, 3, bgr));
1.101 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial loop mode"), &data.InitLoopMode));
1.102 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Initial shuffle mode"), &data.InitShuffleMode));
1.103 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Abort player at end of list"),&data.AbortAtEOL));
1.104 + scan[0]=tr("disabled");
1.105 + scan[1]=tr("ID3 only");
1.106 + scan[2]=tr("ID3 & Level");
1.107 + Add(new cMenuEditStraItem(tr("Setup.MP3$Background scan"), &data.BgrScan, 3, scan));
1.108 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Editor display mode"), &data.EditorMode, tr("Filenames"), tr("ID3 names")));
1.109 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Mainmenu mode"), &data.MenuMode, tr("Playlists"), tr("Browser")));
1.110 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Keep selection menu"), &data.KeepSelect));
1.111 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Title/Artist order"), &data.TitleArtistOrder, tr("Normal"), tr("Reversed")));
1.112 + Add(new cMenuEditBoolItem(tr("Hide mainmenu entry"), &data.HideMainMenu));
1.113 + Add(new cMenuEditIntItem( tr("Setup.MP3$Normalizer level"), &data.TargetLevel, 0, MAX_TARGET_LEVEL));
1.114 + Add(new cMenuEditIntItem( tr("Setup.MP3$Limiter level"), &data.LimiterLevel, MIN_LIMITER_LEVEL, 100));
1.115 + Add(new cMenuEditBoolItem(tr("Setup.MP3$Use HTTP proxy"), &data.UseProxy));
1.116 + Add(new cMenuEditStrItem( tr("Setup.MP3$HTTP proxy host"), data.ProxyHost,MAX_HOSTNAME,allowed));
1.117 + Add(new cMenuEditIntItem( tr("Setup.MP3$HTTP proxy port"), &data.ProxyPort,1,65535));
1.118 + cddb[0]=tr("disabled");
1.119 + cddb[1]=tr("local only");
1.120 + cddb[2]=tr("local&remote");
1.121 + Add(new cMenuEditStraItem(tr("Setup.MP3$CDDB for CD-Audio"), &data.UseCddb,3,cddb));
1.122 + Add(new cMenuEditStrItem( tr("Setup.MP3$CDDB server"), data.CddbHost,MAX_HOSTNAME,allowed));
1.123 + Add(new cMenuEditIntItem( tr("Setup.MP3$CDDB port"), &data.CddbPort,1,65535));
1.124 +}
1.125 +
1.126 +void cMenuSetupMP3::Store(void)
1.127 +{
1.128 + data.AudioOutMode=amodes[amode];
1.129 +
1.130 + MP3Setup=data;
1.131 + SetupStore("InitLoopMode", MP3Setup.InitLoopMode );
1.132 + SetupStore("InitShuffleMode", MP3Setup.InitShuffleMode);
1.133 + SetupStore("AudioMode", MP3Setup.AudioMode );
1.134 + SetupStore("AudioOutMode", MP3Setup.AudioOutMode );
1.135 + SetupStore("BgrScan", MP3Setup.BgrScan );
1.136 + SetupStore("EditorMode", MP3Setup.EditorMode );
1.137 + SetupStore("DisplayMode", MP3Setup.DisplayMode );
1.138 + SetupStore("BackgrMode", MP3Setup.BackgrMode );
1.139 + SetupStore("MenuMode", MP3Setup.MenuMode );
1.140 + SetupStore("TargetLevel", MP3Setup.TargetLevel );
1.141 + SetupStore("LimiterLevel", MP3Setup.LimiterLevel );
1.142 + SetupStore("Only48kHz", MP3Setup.Only48kHz );
1.143 + SetupStore("UseProxy", MP3Setup.UseProxy );
1.144 + SetupStore("ProxyHost", MP3Setup.ProxyHost );
1.145 + SetupStore("ProxyPort", MP3Setup.ProxyPort );
1.146 + SetupStore("UseCddb", MP3Setup.UseCddb );
1.147 + SetupStore("CddbHost", MP3Setup.CddbHost );
1.148 + SetupStore("CddbPort", MP3Setup.CddbPort );
1.149 + SetupStore("AbortAtEOL", MP3Setup.AbortAtEOL );
1.150 +#if APIVERSNUM >= 10307
1.151 + SetupStore("ReplayDisplay", MP3Setup.ReplayDisplay );
1.152 +#endif
1.153 + SetupStore("HideMainMenu", MP3Setup.HideMainMenu );
1.154 + SetupStore("KeepSelect", MP3Setup.KeepSelect );
1.155 + SetupStore("TitleArtistOrder", MP3Setup.TitleArtistOrder);
1.156 +}
1.157 +
1.158 +// --- cAsyncStatus ------------------------------------------------------------
1.159 +
1.160 +cAsyncStatus asyncStatus;
1.161 +
1.162 +cAsyncStatus::cAsyncStatus(void)
1.163 +{
1.164 + text=0;
1.165 + changed=false;
1.166 +}
1.167 +
1.168 +cAsyncStatus::~cAsyncStatus()
1.169 +{
1.170 + free((void *)text);
1.171 +}
1.172 +
1.173 +void cAsyncStatus::Set(const char *Text)
1.174 +{
1.175 + Lock();
1.176 + free((void *)text);
1.177 + text=Text ? strdup(Text) : 0;
1.178 + changed=true;
1.179 + Unlock();
1.180 +}
1.181 +
1.182 +const char *cAsyncStatus::Begin(void)
1.183 +{
1.184 + Lock();
1.185 + return text;
1.186 +}
1.187 +
1.188 +void cAsyncStatus::Finish(void)
1.189 +{
1.190 + changed=false;
1.191 + Unlock();
1.192 +}
1.193 +
1.194 +// --- --------------------------------------------------------------------
1.195 +
1.196 +static const char *TitleArtist(const char *title, const char *artist)
1.197 +{
1.198 + static char buf[256]; // clearly not multi-thread save!
1.199 + char *fmt;
1.200 + if(artist && artist[0]) {
1.201 + if(MP3Setup.TitleArtistOrder) fmt="%2$s - %1$s";
1.202 + else fmt="%s - %s";
1.203 + }
1.204 + else fmt="%s";
1.205 + snprintf(buf,sizeof(buf),fmt,title,artist);
1.206 + return buf;
1.207 +}
1.208 +
1.209 +// --- cMP3Control --------------------------------------------------------
1.210 +
1.211 +#if APIVERSNUM >= 10307
1.212 +#define clrBackground clrGray50
1.213 +#define eDvbColor int
1.214 +#define MAXROWS 120
1.215 +#define INLINE
1.216 +#else
1.217 +#define MAXROWS MAXOSDHEIGHT
1.218 +#define INLINE inline
1.219 +#endif
1.220 +
1.221 +class cMP3Control : public cControl {
1.222 +private:
1.223 +#if APIVERSNUM >= 10307
1.224 + cOsd *osd;
1.225 + const cFont *font;
1.226 + cSkinDisplayReplay *disp;
1.227 +#else
1.228 + bool statusInterfaceOpen;
1.229 +#endif
1.230 + int bw, bh, bwc, fw, fh;
1.231 + //
1.232 + cMP3Player *player;
1.233 + bool visible, shown, bigwin, statusActive;
1.234 + time_t timeoutShow, greentime, oktime;
1.235 + int lastkeytime, number;
1.236 + bool selecting, selecthide;
1.237 + //
1.238 + cMP3PlayInfo *lastMode;
1.239 + time_t fliptime, listtime;
1.240 + int hashlist[MAXROWS];
1.241 + int flip, flipint, top, rows;
1.242 + int lastIndex, lastTotal, lastTop;
1.243 + int framesPerSecond;
1.244 + //
1.245 + bool jumpactive, jumphide, jumpsecs;
1.246 + int jumpmm;
1.247 + //
1.248 + void ShowTimed(int Seconds=0);
1.249 + void ShowProgress(bool open=false, bool bigWin=false);
1.250 + void ShowStatus(bool force);
1.251 + void HideStatus(void);
1.252 + void DisplayInfo(const char *s=0);
1.253 + void JumpDisplay(void);
1.254 + void JumpProcess(eKeys Key);
1.255 + void Jump(void);
1.256 + void Stop(void);
1.257 + INLINE void Write(int x, int y, int w, const char *text, eDvbColor fg=clrWhite, eDvbColor bg=clrBackground);
1.258 + INLINE void Fill(int x, int y, int w, int h, eDvbColor fg);
1.259 + inline void Flush(void);
1.260 +public:
1.261 + cMP3Control(void);
1.262 + virtual ~cMP3Control();
1.263 + virtual eOSState ProcessKey(eKeys Key);
1.264 + virtual void Show(void) { ShowTimed(); }
1.265 + virtual void Hide(void);
1.266 + bool Visible(void) { return visible; }
1.267 + static bool SetPlayList(cPlayList *plist);
1.268 + };
1.269 +
1.270 +cMP3Control::cMP3Control(void)
1.271 +:cControl(player=new cMP3Player)
1.272 +{
1.273 + visible=shown=bigwin=selecting=selecthide=jumpactive=jumphide=statusActive=false;
1.274 + timeoutShow=greentime=oktime=0;
1.275 + lastkeytime=number=0;
1.276 + lastMode=0;
1.277 + framesPerSecond=SecondsToFrames(1);
1.278 +#if APIVERSNUM >= 10307
1.279 + osd=0; disp=0;
1.280 + font=cFont::GetFont(fontOsd);
1.281 +#else
1.282 + statusInterfaceOpen=false;
1.283 +#endif
1.284 +#if APIVERSNUM >= 10338
1.285 + cStatus::MsgReplaying(this,"MP3",0,true);
1.286 +#else
1.287 + cStatus::MsgReplaying(this,"MP3");
1.288 +#endif
1.289 +}
1.290 +
1.291 +cMP3Control::~cMP3Control()
1.292 +{
1.293 + delete lastMode;
1.294 + Hide();
1.295 + Stop();
1.296 +}
1.297 +
1.298 +void cMP3Control::Stop(void)
1.299 +{
1.300 +#if APIVERSNUM >= 10338
1.301 + cStatus::MsgReplaying(this,0,0,false);
1.302 +#else
1.303 + cStatus::MsgReplaying(this,0);
1.304 +#endif
1.305 + delete player; player=0;
1.306 + mgr->Halt();
1.307 + mgr->Flush(); //XXX remove later
1.308 +}
1.309 +
1.310 +bool cMP3Control::SetPlayList(cPlayList *plist)
1.311 +{
1.312 + bool res;
1.313 + cControl *control=cControl::Control();
1.314 + // is there a running MP3 player?
1.315 + if(control && typeid(*control)==typeid(cMP3Control)) {
1.316 + // add songs to running playlist
1.317 + mgr->Add(plist);
1.318 + res=true;
1.319 + }
1.320 + else {
1.321 + mgr->Flush();
1.322 + mgr->Add(plist);
1.323 + cControl::Launch(new cMP3Control);
1.324 + res=false;
1.325 + }
1.326 + delete plist;
1.327 + return res;
1.328 +}
1.329 +
1.330 +void cMP3Control::ShowTimed(int Seconds)
1.331 +{
1.332 + if(!visible) {
1.333 + ShowProgress(true);
1.334 + if(Seconds>0) timeoutShow=time(0)+Seconds;
1.335 + }
1.336 +}
1.337 +
1.338 +void cMP3Control::Hide(void)
1.339 +{
1.340 + HideStatus();
1.341 + if(visible) {
1.342 +#if APIVERSNUM >= 10307
1.343 + delete osd; osd=0;
1.344 + delete disp; disp=0;
1.345 +#else
1.346 + Interface->Close();
1.347 +#endif
1.348 + visible=bigwin=false;
1.349 +#if APIVERSNUM >= 10500
1.350 + SetNeedsFastResponse(false);
1.351 +#else
1.352 + needsFastResponse=false;
1.353 +#endif
1.354 + }
1.355 +}
1.356 +
1.357 +void cMP3Control::ShowStatus(bool force)
1.358 +{
1.359 + if((asyncStatus.Changed() || (force && !statusActive)) && !jumpactive) {
1.360 + const char *text=asyncStatus.Begin();
1.361 + if(text) {
1.362 +#if APIVERSNUM >= 10307
1.363 + if(MP3Setup.ReplayDisplay || !osd) {
1.364 + if(statusActive) Skins.Message(mtStatus,0);
1.365 + Skins.Message(mtStatus,text);
1.366 + }
1.367 + else {
1.368 + if(!statusActive) osd->SaveRegion(0,bh-2*fh,bw-1,bh-fh-1);
1.369 + osd->DrawText(0,bh-2*fh,text,clrBlack,clrCyan,font,bw,fh,taCenter);
1.370 + osd->Flush();
1.371 + }
1.372 +#else
1.373 + if(!Interface->IsOpen()) {
1.374 + Interface->Open(0,-1);
1.375 + statusInterfaceOpen=true;
1.376 + }
1.377 + Interface->Status(text);
1.378 + Interface->Flush();
1.379 +#endif
1.380 + statusActive=true;
1.381 + }
1.382 + else
1.383 + HideStatus();
1.384 + asyncStatus.Finish();
1.385 + }
1.386 +}
1.387 +
1.388 +void cMP3Control::HideStatus(void)
1.389 +{
1.390 + if(statusActive) {
1.391 +#if APIVERSNUM >= 10307
1.392 + if(MP3Setup.ReplayDisplay || !osd)
1.393 + Skins.Message(mtStatus,0);
1.394 + else {
1.395 + osd->RestoreRegion();
1.396 + osd->Flush();
1.397 + }
1.398 +#else
1.399 + if(statusInterfaceOpen) {
1.400 + Interface->Close();
1.401 + statusInterfaceOpen=false;
1.402 + }
1.403 + else {
1.404 + Interface->Status(0);
1.405 + Interface->Flush();
1.406 + }
1.407 +#endif
1.408 + }
1.409 + statusActive=false;
1.410 +}
1.411 +
1.412 +#define CTAB 11 // some tabbing values for the progress display
1.413 +#define CTAB2 5
1.414 +
1.415 +void cMP3Control::Write(int x, int y, int w, const char *text, eDvbColor fg, eDvbColor bg)
1.416 +{
1.417 +#if APIVERSNUM >= 10307
1.418 + if(osd) {
1.419 + //d(printf("write x=%d y=%d w=%d ->",x,y,w))
1.420 + x*=fw; if(x<0) x+=bw;
1.421 + y*=fh; if(y<0) y+=bh;
1.422 + osd->DrawText(x,y,text,fg,bg,font,w*fw);
1.423 + //d(printf(" x=%d y=%d w=%d\n",x,y,w*fw))
1.424 + }
1.425 +#else
1.426 + if(w>0) Fill(x,y,w,1,bg);
1.427 + Interface->Write(x,y,text,fg,bg);
1.428 +#endif
1.429 +}
1.430 +
1.431 +void cMP3Control::Fill(int x, int y, int w, int h, eDvbColor fg)
1.432 +{
1.433 +#if APIVERSNUM >= 10307
1.434 + if(osd) {
1.435 + //d(printf("fill x=%d y=%d w=%d h=%d ->",x,y,w,h))
1.436 + x*=fw; if(x<0) x+=bw;
1.437 + y*=fh; if(y<0) y+=bh;
1.438 + osd->DrawRectangle(x,y,x+w*fw-1,y+h*fh-1,fg);
1.439 + //d(printf(" x=%d y=%d x2=%d y2=%d\n",x,y,x+h*fh-1,y+w*fw-1))
1.440 + }
1.441 +#else
1.442 + Interface->Fill(x,y,w,h,fg);
1.443 +#endif
1.444 +}
1.445 +
1.446 +void cMP3Control::Flush(void)
1.447 +{
1.448 +#if APIVERSNUM >= 10307
1.449 + if(MP3Setup.ReplayDisplay) Skins.Flush();
1.450 + else if(osd) osd->Flush();
1.451 +#else
1.452 + Interface->Flush();
1.453 +#endif
1.454 +}
1.455 +
1.456 +void cMP3Control::ShowProgress(bool open, bool bigWin)
1.457 +{
1.458 + int index, total;
1.459 +
1.460 + if(player->GetIndex(index,total) && total>=0) {
1.461 + if(!visible && open) {
1.462 + HideStatus();
1.463 +#if APIVERSNUM >= 10307
1.464 + if(MP3Setup.ReplayDisplay) {
1.465 + disp=Skins.Current()->DisplayReplay(false);
1.466 + if(!disp) return;
1.467 + bigWin=false;
1.468 + }
1.469 + else {
1.470 + int bt, bp;
1.471 + fw=font->Width(' ')*2;
1.472 + fh=font->Height();
1.473 + if(bigWin) {
1.474 + bw=Setup.OSDWidth;
1.475 + bh=Setup.OSDHeight;
1.476 + bt=0;
1.477 + bp=2*fh;
1.478 + rows=(bh-bp-fh/3)/fh;
1.479 + }
1.480 + else {
1.481 + bw=Setup.OSDWidth;
1.482 + bh=bp=2*fh;
1.483 + bt=Setup.OSDHeight-bh;
1.484 + rows=0;
1.485 + }
1.486 + bwc=bw/fw+1;
1.487 + //d(printf("mp3: bw=%d bh=%d bt=%d bp=%d bwc=%d rows=%d fw=%d fh=%d\n",
1.488 + // bw,bh,bt,bp,bwc,rows,fw,fh))
1.489 + osd=cOsdProvider::NewOsd(Setup.OSDLeft,Setup.OSDTop+bt);
1.490 + if(!osd) return;
1.491 + if(bigWin) {
1.492 + tArea Areas[] = { { 0,0,bw-1,bh-bp-1,2 }, { 0,bh-bp,bw-1,bh-1,4 } };
1.493 + osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea));
1.494 + }
1.495 + else {
1.496 + tArea Areas[] = { { 0,0,bw-1,bh-1,4 } };
1.497 + osd->SetAreas(Areas,sizeof(Areas)/sizeof(tArea));
1.498 + }
1.499 + osd->DrawRectangle(0,0,bw-1,bh-1,clrGray50);
1.500 + osd->Flush();
1.501 + }
1.502 +#else
1.503 + fw=cOsd::CellWidth();
1.504 + fh=cOsd::LineHeight();
1.505 + bh=bigWin ? Setup.OSDheight : -2;
1.506 + bw=bwc=Setup.OSDwidth;
1.507 + rows=Setup.OSDheight-3;
1.508 + Interface->Open(bw,bh);
1.509 + Interface->Clear();
1.510 +#endif
1.511 + ShowStatus(true);
1.512 + bigwin=bigWin;
1.513 + visible=true;
1.514 +#if APIVERSNUM >= 10500
1.515 + SetNeedsFastResponse(true);
1.516 +#else
1.517 + needsFastResponse=true;
1.518 +#endif
1.519 + fliptime=listtime=0; flipint=0; flip=-1; top=lastTop=-1; lastIndex=lastTotal=-1;
1.520 + delete lastMode; lastMode=0;
1.521 + }
1.522 +
1.523 + cMP3PlayInfo *mode=new cMP3PlayInfo;
1.524 + bool valid=mgr->Info(-1,mode);
1.525 + bool changed=(!lastMode || mode->Hash!=lastMode->Hash);
1.526 + char buf[256];
1.527 + if(changed) { d(printf("mp3-ctrl: mode change detected\n")) }
1.528 +
1.529 + if(valid) { // send progress to status monitor
1.530 + if(changed || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle) {
1.531 + snprintf(buf,sizeof(buf),"[%c%c] (%d/%d) %s",
1.532 + mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,TitleArtist(mode->Title,mode->Artist));
1.533 +#if APIVERSNUM >= 10338
1.534 + cStatus::MsgReplaying(this,buf,mode->Filename[0]?mode->Filename:0,true);
1.535 +#else
1.536 + cStatus::MsgReplaying(this,buf);
1.537 +#endif
1.538 + }
1.539 + }
1.540 +
1.541 + if(visible) { // refresh the OSD progress display
1.542 + bool flush=false;
1.543 +
1.544 +#if APIVERSNUM >= 10307
1.545 + if(MP3Setup.ReplayDisplay) {
1.546 + if(!statusActive) {
1.547 + if(total>0) disp->SetProgress(index,total);
1.548 + disp->SetCurrent(IndexToHMSF(index));
1.549 + disp->SetTotal(IndexToHMSF(total));
1.550 + bool Play, Forward;
1.551 + int Speed;
1.552 + if(GetReplayMode(Play,Forward,Speed))
1.553 + disp->SetMode(Play, Forward, Speed);
1.554 + flush=true;
1.555 + }
1.556 + }
1.557 + else {
1.558 +#endif
1.559 + if(!selecting && changed && !statusActive) {
1.560 + snprintf(buf,sizeof(buf),"(%d/%d)",mode->Num,mode->MaxNum);
1.561 + Write(0,-2,CTAB,buf);
1.562 + flush=true;
1.563 + }
1.564 +
1.565 + if(!lastMode || mode->Loop!=lastMode->Loop) {
1.566 + if(mode->Loop) Write(-4,-1,0,"L",clrBlack,clrYellow);
1.567 + else Fill(-4,-1,2,1,clrBackground);
1.568 + flush=true;
1.569 + }
1.570 + if(!lastMode || mode->Shuffle!=lastMode->Shuffle) {
1.571 + if(mode->Shuffle) Write(-2,-1,0,"S",clrWhite,clrRed);
1.572 + else Fill(-2,-1,2,1,clrBackground);
1.573 + flush=true;
1.574 + }
1.575 +
1.576 + index/=framesPerSecond; total/=framesPerSecond;
1.577 + if(index!=lastIndex || total!=lastTotal) {
1.578 + if(total>0) {
1.579 +#if APIVERSNUM >= 10307
1.580 + cProgressBar ProgressBar(bw-(CTAB+CTAB2)*fw,fh,index,total);
1.581 + osd->DrawBitmap(CTAB*fw,bh-fh,ProgressBar);
1.582 +#else
1.583 + cProgressBar ProgressBar((bw-CTAB-CTAB2)*fw,fh,index,total);
1.584 + Interface->SetBitmap(CTAB*fw,(abs(bh)-1)*fh,ProgressBar);
1.585 +#endif
1.586 + }
1.587 + snprintf(buf,sizeof(buf),total?"%02d:%02d/%02d:%02d":"%02d:%02d",index/60,index%60,total/60,total%60);
1.588 + Write(0,-1,11,buf);
1.589 + flush=true;
1.590 + }
1.591 +#if APIVERSNUM >= 10307
1.592 + }
1.593 +#endif
1.594 +
1.595 + if(!jumpactive) {
1.596 + bool doflip=false;
1.597 + if(MP3Setup.ReplayDisplay && (!lastMode || mode->Loop!=lastMode->Loop || mode->Shuffle!=lastMode->Shuffle))
1.598 + doflip=true;
1.599 + if(!valid || changed) {
1.600 + fliptime=time(0); flip=0;
1.601 + doflip=true;
1.602 + }
1.603 + else if(time(0)>fliptime+flipint) {
1.604 + fliptime=time(0);
1.605 + flip++; if(flip>=MP3Setup.DisplayMode) flip=0;
1.606 + doflip=true;
1.607 + }
1.608 + if(doflip) {
1.609 + buf[0]=0;
1.610 + switch(flip) {
1.611 + default:
1.612 + flip=0;
1.613 + // fall through
1.614 + case 0:
1.615 + snprintf(buf,sizeof(buf),"%s",TitleArtist(mode->Title,mode->Artist));
1.616 + flipint=6;
1.617 + break;
1.618 + case 1:
1.619 + if(mode->Album[0]) {
1.620 + snprintf(buf,sizeof(buf),mode->Year>0?"from: %s (%d)":"from: %s",mode->Album,mode->Year);
1.621 + flipint=4;
1.622 + }
1.623 + else fliptime=0;
1.624 + break;
1.625 + case 2:
1.626 + if(mode->MaxBitrate>0)
1.627 + snprintf(buf,sizeof(buf),"%.1f kHz, %d-%d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->MaxBitrate/1000,mode->SMode);
1.628 + else
1.629 + snprintf(buf,sizeof(buf),"%.1f kHz, %d kbps, %s",mode->SampleFreq/1000.0,mode->Bitrate/1000,mode->SMode);
1.630 + flipint=3;
1.631 + break;
1.632 + }
1.633 + if(buf[0]) {
1.634 +#if APIVERSNUM >= 10307
1.635 + if(MP3Setup.ReplayDisplay) {
1.636 + char buf2[256];
1.637 + snprintf(buf2,sizeof(buf2),"[%c%c] (%d/%d) %s",
1.638 + mode->Loop?'L':'.',mode->Shuffle?'S':'.',mode->Num,mode->MaxNum,buf);
1.639 + disp->SetTitle(buf2);
1.640 + flush=true;
1.641 + }
1.642 + else {
1.643 +#endif
1.644 + if(!statusActive) {
1.645 + DisplayInfo(buf);
1.646 + flush=true;
1.647 + }
1.648 + else { d(printf("mp3-ctrl: display info skip due to status active\n")) }
1.649 +#if APIVERSNUM >= 10307
1.650 + }
1.651 +#endif
1.652 + }
1.653 + }
1.654 + }
1.655 +
1.656 + if(bigwin) {
1.657 + bool all=(top!=lastTop || changed);
1.658 + if(all || time(0)>listtime+2) {
1.659 + int num=(top>0 && mode->Num==lastMode->Num) ? top : mode->Num - rows/2;
1.660 + if(num+rows>mode->MaxNum) num=mode->MaxNum-rows+1;
1.661 + if(num<1) num=1;
1.662 + top=num;
1.663 + for(int i=0 ; i<rows && i<MAXROWS && num<=mode->MaxNum ; i++,num++) {
1.664 + cMP3PlayInfo pi;
1.665 + mgr->Info(num,&pi); if(!pi.Title[0]) break;
1.666 + snprintf(buf,sizeof(buf),"%d.\t%s",num,TitleArtist(pi.Title,pi.Artist));
1.667 + eDvbColor fg=clrWhite, bg=clrBackground;
1.668 + int hash=MakeHash(buf);
1.669 + if(num==mode->Num) { fg=clrBlack; bg=clrCyan; hash=(hash^77) + 23; }
1.670 + if(all || hash!=hashlist[i]) {
1.671 + char *s=rindex(buf,'\t');
1.672 + if(s) {
1.673 + *s++=0;
1.674 + Write(0,i,5,buf,fg,bg);
1.675 + Write(5,i,bwc-5,s,fg,bg);
1.676 + }
1.677 + else
1.678 + Write(0,i,bwc,buf,fg,bg);
1.679 + flush=true;
1.680 + hashlist[i]=hash;
1.681 + }
1.682 + }
1.683 + listtime=time(0); lastTop=top;
1.684 + }
1.685 + }
1.686 +
1.687 + if(flush) Flush();
1.688 + }
1.689 +
1.690 + lastIndex=index; lastTotal=total;
1.691 + delete lastMode; lastMode=mode;
1.692 + }
1.693 +}
1.694 +
1.695 +void cMP3Control::DisplayInfo(const char *s)
1.696 +{
1.697 + if(s) Write(CTAB,-2,bwc-CTAB,s);
1.698 + else Fill(CTAB,-2,bwc-CTAB,1,clrBackground);
1.699 +}
1.700 +
1.701 +void cMP3Control::JumpDisplay(void)
1.702 +{
1.703 + char buf[64];
1.704 + const char *j=tr("Jump: "), u=jumpsecs?'s':'m';
1.705 + if(!jumpmm) sprintf(buf,"%s- %c", j,u);
1.706 + else sprintf(buf,"%s%d- %c",j,jumpmm,u);
1.707 +#if APIVERSNUM >= 10307
1.708 + if(MP3Setup.ReplayDisplay) {
1.709 + disp->SetJump(buf);
1.710 + }
1.711 + else {
1.712 +#endif
1.713 + DisplayInfo(buf);
1.714 +#if APIVERSNUM >= 10307
1.715 + }
1.716 +#endif
1.717 +}
1.718 +
1.719 +void cMP3Control::JumpProcess(eKeys Key)
1.720 +{
1.721 + int n=Key-k0, d=jumpsecs?1:60;
1.722 + switch (Key) {
1.723 + case k0 ... k9:
1.724 + if(jumpmm*10+n <= lastTotal/d) jumpmm=jumpmm*10+n;
1.725 + JumpDisplay();
1.726 + break;
1.727 + case kBlue:
1.728 + jumpsecs=!jumpsecs;
1.729 + JumpDisplay();
1.730 + break;
1.731 + case kPlay:
1.732 + case kUp:
1.733 + jumpmm-=lastIndex/d;
1.734 + // fall through
1.735 + case kFastRew:
1.736 + case kFastFwd:
1.737 + case kLeft:
1.738 + case kRight:
1.739 + player->SkipSeconds(jumpmm*d * ((Key==kLeft || Key==kFastRew) ? -1:1));
1.740 + // fall through
1.741 + default:
1.742 + jumpactive=false;
1.743 + break;
1.744 + }
1.745 +
1.746 + if(!jumpactive) {
1.747 + if(jumphide) Hide();
1.748 +#if APIVERSNUM >= 10307
1.749 + else if(MP3Setup.ReplayDisplay) disp->SetJump(0);
1.750 +#endif
1.751 + }
1.752 +}
1.753 +
1.754 +void cMP3Control::Jump(void)
1.755 +{
1.756 + jumpmm=0; jumphide=jumpsecs=false;
1.757 + if(!visible) {
1.758 + ShowTimed(); if(!visible) return;
1.759 + jumphide=true;
1.760 + }
1.761 + JumpDisplay();
1.762 + jumpactive=true; fliptime=0; flip=-1;
1.763 +}
1.764 +
1.765 +eOSState cMP3Control::ProcessKey(eKeys Key)
1.766 +{
1.767 + if(!player->Active()) return osEnd;
1.768 +
1.769 + if(visible && timeoutShow && time(0)>timeoutShow) { Hide(); timeoutShow=0; }
1.770 + ShowProgress();
1.771 +#if APIVERSNUM >= 10307
1.772 + ShowStatus(Key==kNone && !Skins.IsOpen());
1.773 +#else
1.774 + ShowStatus(Key==kNone && !Interface->IsOpen());
1.775 +#endif
1.776 +
1.777 + if(jumpactive && Key!=kNone) { JumpProcess(Key); return osContinue; }
1.778 +
1.779 + switch(Key) {
1.780 + case kUp:
1.781 + case kUp|k_Repeat:
1.782 +#if APIVERSNUM >= 10347
1.783 + case kNext:
1.784 + case kNext|k_Repeat:
1.785 +#endif
1.786 + mgr->Next(); player->Play();
1.787 + break;
1.788 + case kDown:
1.789 + case kDown|k_Repeat:
1.790 +#if APIVERSNUM >= 10347
1.791 + case kPrev:
1.792 + case kPrev|k_Repeat:
1.793 +#endif
1.794 + if(!player->PrevCheck()) mgr->Prev();
1.795 + player->Play();
1.796 + break;
1.797 + case kLeft:
1.798 + case kLeft|k_Repeat:
1.799 + if(bigwin) {
1.800 + if(top>0) { top-=rows; if(top<1) top=1; }
1.801 + break;
1.802 + }
1.803 + // fall through
1.804 + case kFastRew:
1.805 + case kFastRew|k_Repeat:
1.806 + if(!player->IsStream()) player->SkipSeconds(-JUMPSIZE);
1.807 + break;
1.808 + case kRight:
1.809 + case kRight|k_Repeat:
1.810 + if(bigwin) {
1.811 + if(top>0) top+=rows;
1.812 + break;
1.813 + }
1.814 + // fall through
1.815 + case kFastFwd:
1.816 + case kFastFwd|k_Repeat:
1.817 + if(!player->IsStream()) player->SkipSeconds(JUMPSIZE);
1.818 + break;
1.819 + case kRed:
1.820 + if(!player->IsStream()) Jump();
1.821 + break;
1.822 + case kGreen:
1.823 + if(lastMode) {
1.824 + if(time(0)>greentime) {
1.825 + if(lastMode->Loop || (!lastMode->Loop && !lastMode->Shuffle)) mgr->ToggleLoop();
1.826 + if(lastMode->Shuffle) mgr->ToggleShuffle();
1.827 + }
1.828 + else {
1.829 + if(!lastMode->Loop) mgr->ToggleLoop();
1.830 + else if(!lastMode->Shuffle) mgr->ToggleShuffle();
1.831 + else mgr->ToggleLoop();
1.832 + }
1.833 + greentime=time(0)+MULTI_TIMEOUT;
1.834 + }
1.835 + break;
1.836 + case kPlay:
1.837 + player->Play();
1.838 + break;
1.839 + case kPause:
1.840 + case kYellow:
1.841 + if(!player->IsStream()) player->Pause();
1.842 + break;
1.843 + case kStop:
1.844 + case kBlue:
1.845 + Hide();
1.846 + Stop();
1.847 + return osEnd;
1.848 + case kBack:
1.849 + Hide();
1.850 +#if APIVERSNUM >= 10332
1.851 + cRemote::CallPlugin(i18n_name);
1.852 + return osBack;
1.853 +#else
1.854 + return osEnd;
1.855 +#endif
1.856 +
1.857 + case k0 ... k9:
1.858 + number=number*10+Key-k0;
1.859 + if(lastMode && number>0 && number<=lastMode->MaxNum) {
1.860 + if(!visible) { ShowTimed(); selecthide=true; }
1.861 + selecting=true; lastkeytime=time_ms();
1.862 + char buf[32];
1.863 +#if APIVERSNUM >= 10307
1.864 + if(MP3Setup.ReplayDisplay) {
1.865 + snprintf(buf,sizeof(buf),"%s%d-/%d",tr("Jump: "),number,lastMode->MaxNum);
1.866 + disp->SetJump(buf);
1.867 + }
1.868 + else {
1.869 +#endif
1.870 + snprintf(buf,sizeof(buf),"(%d-/%d)",number,lastMode->MaxNum);
1.871 + Write(0,-2,CTAB,buf);
1.872 +#if APIVERSNUM >= 10307
1.873 + }
1.874 +#endif
1.875 + Flush();
1.876 + break;
1.877 + }
1.878 + number=0; lastkeytime=0;
1.879 + // fall through
1.880 + case kNone:
1.881 + if(selecting && time_ms()-lastkeytime>SELECT_TIMEOUT) {
1.882 + if(number>0) { mgr->Goto(number); player->Play(); }
1.883 + if(selecthide) timeoutShow=time(0)+SELECTHIDE_TIMEOUT;
1.884 + if(lastMode) lastMode->Hash=-1;
1.885 + number=0; selecting=selecthide=false;
1.886 +#if APIVERSNUM >= 10307
1.887 + if(MP3Setup.ReplayDisplay) disp->SetJump(0);
1.888 +#endif
1.889 + }
1.890 + break;
1.891 + case kOk:
1.892 + if(time(0)>oktime || MP3Setup.ReplayDisplay) {
1.893 + visible ? Hide() : ShowTimed();
1.894 + }
1.895 + else {
1.896 + if(visible && !bigwin) { Hide(); ShowProgress(true,true); }
1.897 + else { Hide(); ShowTimed(); }
1.898 + }
1.899 + oktime=time(0)+MULTI_TIMEOUT;
1.900 + ShowStatus(true);
1.901 + break;
1.902 + default:
1.903 + return osUnknown;
1.904 + }
1.905 + return osContinue;
1.906 +}
1.907 +
1.908 +// --- cMenuID3Info ------------------------------------------------------------
1.909 +
1.910 +class cMenuID3Info : public cOsdMenu {
1.911 +private:
1.912 + cOsdItem *Item(const char *name, const char *text);
1.913 + cOsdItem *Item(const char *name, const char *format, const float num);
1.914 + void Build(cSongInfo *info, const char *name);
1.915 +public:
1.916 + cMenuID3Info(cSong *song);
1.917 + cMenuID3Info(cSongInfo *si, const char *name);
1.918 + virtual eOSState ProcessKey(eKeys Key);
1.919 + };
1.920 +
1.921 +cMenuID3Info::cMenuID3Info(cSong *song)
1.922 +:cOsdMenu(tr("ID3 information"),12)
1.923 +{
1.924 + Build(song->Info(),song->Name());
1.925 +}
1.926 +
1.927 +cMenuID3Info::cMenuID3Info(cSongInfo *si, const char *name)
1.928 +:cOsdMenu(tr("ID3 information"),12)
1.929 +{
1.930 + Build(si,name);
1.931 +}
1.932 +
1.933 +void cMenuID3Info::Build(cSongInfo *si, const char *name)
1.934 +{
1.935 + if(si) {
1.936 + Item(tr("Filename"),name);
1.937 + if(si->HasInfo() && si->Total>0) {
1.938 + char *buf=0;
1.939 + asprintf(&buf,"%02d:%02d",si->Total/60,si->Total%60);
1.940 + Item(tr("Length"),buf);
1.941 + free(buf);
1.942 + Item(tr("Title"),si->Title);
1.943 + Item(tr("Artist"),si->Artist);
1.944 + Item(tr("Album"),si->Album);
1.945 + Item(tr("Year"),0,(float)si->Year);
1.946 + Item(tr("Samplerate"),"%.1f kHz",si->SampleFreq/1000.0);
1.947 + Item(tr("Bitrate"),"%.f kbit/s",si->Bitrate/1000.0);
1.948 + Item(tr("Channels"),0,(float)si->Channels);
1.949 + }
1.950 + Display();
1.951 + }
1.952 +}
1.953 +
1.954 +cOsdItem *cMenuID3Info::Item(const char *name, const char *format, const float num)
1.955 +{
1.956 + cOsdItem *item;
1.957 + if(num>=0.0) {
1.958 + char *buf=0;
1.959 + asprintf(&buf,format?format:"%.f",num);
1.960 + item=Item(name,buf);
1.961 + free(buf);
1.962 + }
1.963 + else item=Item(name,"");
1.964 + return item;
1.965 +}
1.966 +
1.967 +cOsdItem *cMenuID3Info::Item(const char *name, const char *text)
1.968 +{
1.969 + char *buf=0;
1.970 + asprintf(&buf,"%s:\t%s",name,text?text:"");
1.971 + cOsdItem *item = new cOsdItem(buf,osBack);
1.972 +#if APIVERSNUM >= 10307
1.973 + item->SetSelectable(false);
1.974 +#else
1.975 + item->SetColor(clrWhite, clrBackground);
1.976 +#endif
1.977 + free(buf);
1.978 + Add(item); return item;
1.979 +}
1.980 +
1.981 +eOSState cMenuID3Info::ProcessKey(eKeys Key)
1.982 +{
1.983 + eOSState state = cOsdMenu::ProcessKey(Key);
1.984 +
1.985 + if(state==osUnknown) {
1.986 + switch(Key) {
1.987 + case kRed:
1.988 + case kGreen:
1.989 + case kYellow:
1.990 + case kBlue: return osContinue;
1.991 + case kMenu: return osEnd;
1.992 + default: break;
1.993 + }
1.994 + }
1.995 + return state;
1.996 +}
1.997 +
1.998 +// --- cMenuInstantBrowse -------------------------------------------------------
1.999 +
1.1000 +class cMenuInstantBrowse : public cMenuBrowse {
1.1001 +private:
1.1002 + const char *selecttext, *alltext;
1.1003 + virtual void SetButtons(void);
1.1004 + virtual eOSState ID3Info(void);
1.1005 +public:
1.1006 + cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext);
1.1007 + virtual eOSState ProcessKey(eKeys Key);
1.1008 + };
1.1009 +
1.1010 +cMenuInstantBrowse::cMenuInstantBrowse(cFileSource *Source, const char *Selecttext, const char *Alltext)
1.1011 +:cMenuBrowse(Source,true,true,tr("Directory browser"),excl_br)
1.1012 +{
1.1013 + selecttext=Selecttext; alltext=Alltext;
1.1014 + SetButtons();
1.1015 +}
1.1016 +
1.1017 +void cMenuInstantBrowse::SetButtons(void)
1.1018 +{
1.1019 + SetHelp(selecttext, currentdir?tr("Parent"):0, currentdir?0:alltext, tr("ID3 info"));
1.1020 + Display();
1.1021 +}
1.1022 +
1.1023 +eOSState cMenuInstantBrowse::ID3Info(void)
1.1024 +{
1.1025 + cFileObj *item=CurrentItem();
1.1026 + if(item && item->Type()==otFile) {
1.1027 + cSong *song=new cSong(item);
1.1028 + cSongInfo *si;
1.1029 + if(song && (si=song->Info())) {
1.1030 + AddSubMenu(new cMenuID3Info(si,item->Path()));
1.1031 + }
1.1032 + delete song;
1.1033 + }
1.1034 + return osContinue;
1.1035 +}
1.1036 +
1.1037 +eOSState cMenuInstantBrowse::ProcessKey(eKeys Key)
1.1038 +{
1.1039 + eOSState state=cOsdMenu::ProcessKey(Key);
1.1040 + if(state==osUnknown) {
1.1041 + switch (Key) {
1.1042 + case kYellow: lastselect=new cFileObj(source,0,0,otBase);
1.1043 + return osBack;
1.1044 + default: break;
1.1045 + }
1.1046 + }
1.1047 + if(state==osUnknown) state=cMenuBrowse::ProcessStdKey(Key,state);
1.1048 + return state;
1.1049 +}
1.1050 +
1.1051 +// --- cMenuPlayListItem -------------------------------------------------------
1.1052 +
1.1053 +class cMenuPlayListItem : public cOsdItem {
1.1054 + private:
1.1055 + bool showID3;
1.1056 + cSong *song;
1.1057 +public:
1.1058 + cMenuPlayListItem(cSong *Song, bool showid3);
1.1059 + cSong *Song(void) { return song; }
1.1060 + virtual void Set(void);
1.1061 + void Set(bool showid3);
1.1062 + };
1.1063 +
1.1064 +cMenuPlayListItem::cMenuPlayListItem(cSong *Song, bool showid3)
1.1065 +{
1.1066 + song=Song;
1.1067 + Set(showid3);
1.1068 +}
1.1069 +
1.1070 +void cMenuPlayListItem::Set(bool showid3)
1.1071 +{
1.1072 + showID3=showid3;
1.1073 + Set();
1.1074 +}
1.1075 +
1.1076 +void cMenuPlayListItem::Set(void)
1.1077 +{
1.1078 + char *buffer=0;
1.1079 + cSongInfo *si=song->Info(false);
1.1080 + if(showID3 && !si) si=song->Info();
1.1081 + if(showID3 && si && si->Title)
1.1082 + asprintf(&buffer, "%d.\t%s",song->Index()+1,TitleArtist(si->Title,si->Artist));
1.1083 + else
1.1084 + asprintf(&buffer, "%d.\t<%s>",song->Index()+1,song->Name());
1.1085 + SetText(buffer,false);
1.1086 +}
1.1087 +
1.1088 +// --- cMenuPlayList ------------------------------------------------------
1.1089 +
1.1090 +class cMenuPlayList : public cOsdMenu {
1.1091 +private:
1.1092 + cPlayList *playlist;
1.1093 + bool browsing, showid3;
1.1094 + void Buttons(void);
1.1095 + void Refresh(bool all = false);
1.1096 + void Add(void);
1.1097 + virtual void Move(int From, int To);
1.1098 + eOSState Remove(void);
1.1099 + eOSState ShowID3(void);
1.1100 + eOSState ID3Info(void);
1.1101 +public:
1.1102 + cMenuPlayList(cPlayList *Playlist);
1.1103 + virtual eOSState ProcessKey(eKeys Key);
1.1104 + };
1.1105 +
1.1106 +cMenuPlayList::cMenuPlayList(cPlayList *Playlist)
1.1107 +:cOsdMenu(tr("Playlist editor"),4)
1.1108 +{
1.1109 + browsing=showid3=false;
1.1110 + playlist=Playlist;
1.1111 + if(MP3Setup.EditorMode) showid3=true;
1.1112 +
1.1113 + cSong *mp3 = playlist->First();
1.1114 + while(mp3) {
1.1115 + cOsdMenu::Add(new cMenuPlayListItem(mp3,showid3));
1.1116 + mp3 = playlist->cList<cSong>::Next(mp3);
1.1117 + }
1.1118 + Buttons(); Display();
1.1119 +}
1.1120 +
1.1121 +void cMenuPlayList::Buttons(void)
1.1122 +{
1.1123 + SetHelp(tr("Add"), showid3?tr("Filenames"):tr("ID3 names"), tr("Remove"), tr(BUTTON"Mark"));
1.1124 +}
1.1125 +
1.1126 +void cMenuPlayList::Refresh(bool all)
1.1127 +{
1.1128 + cMenuPlayListItem *cur=(cMenuPlayListItem *)((all || Count()<2) ? First() : Get(Current()));
1.1129 + while(cur) {
1.1130 + cur->Set(showid3);
1.1131 + cur=(cMenuPlayListItem *)Next(cur);
1.1132 + }
1.1133 +}
1.1134 +
1.1135 +void cMenuPlayList::Add(void)
1.1136 +{
1.1137 + cFileObj *item=cMenuInstantBrowse::GetSelected();
1.1138 + if(item) {
1.1139 + Status(tr("Scanning directory..."));
1.1140 + cInstantPlayList *newpl=new cInstantPlayList(item);
1.1141 + if(newpl->Load()) {
1.1142 + if(newpl->Count()) {
1.1143 + if(newpl->Count()==1 || Interface->Confirm(tr("Add recursivly?"))) {
1.1144 + cSong *mp3=newpl->First();
1.1145 + while(mp3) {
1.1146 + cSong *n=new cSong(mp3);
1.1147 + if(Count()>0) {
1.1148 + cMenuPlayListItem *current=(cMenuPlayListItem *)Get(Current());
1.1149 + playlist->Add(n,current->Song());
1.1150 + cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true,current);
1.1151 + }
1.1152 + else {
1.1153 + playlist->Add(n);
1.1154 + cOsdMenu::Add(new cMenuPlayListItem(n,showid3),true);
1.1155 + }
1.1156 + mp3=newpl->cList<cSong>::Next(mp3);
1.1157 + }
1.1158 + playlist->Save();
1.1159 + Refresh(); Display();
1.1160 + }
1.1161 + }
1.1162 + else Error(tr("Empty directory!"));
1.1163 + }
1.1164 + else Error(tr("Error scanning directory!"));
1.1165 + delete newpl;
1.1166 + Status(0);
1.1167 + }
1.1168 +}
1.1169 +
1.1170 +void cMenuPlayList::Move(int From, int To)
1.1171 +{
1.1172 + playlist->Move(From,To); playlist->Save();
1.1173 + cOsdMenu::Move(From,To);
1.1174 + Refresh(true); Display();
1.1175 +}
1.1176 +
1.1177 +eOSState cMenuPlayList::ShowID3(void)
1.1178 +{
1.1179 + showid3=!showid3;
1.1180 + Buttons(); Refresh(true); Display();
1.1181 + return osContinue;
1.1182 +}
1.1183 +
1.1184 +eOSState cMenuPlayList::ID3Info(void)
1.1185 +{
1.1186 + if(Count()>0) {
1.1187 + cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current());
1.1188 + AddSubMenu(new cMenuID3Info(current->Song()));
1.1189 + }
1.1190 + return osContinue;
1.1191 +}
1.1192 +
1.1193 +eOSState cMenuPlayList::Remove(void)
1.1194 +{
1.1195 + if(Count()>0) {
1.1196 + cMenuPlayListItem *current = (cMenuPlayListItem *)Get(Current());
1.1197 + if(Interface->Confirm(tr("Remove entry?"))) {
1.1198 + playlist->Del(current->Song()); playlist->Save();
1.1199 + cOsdMenu::Del(Current());
1.1200 + Refresh(); Display();
1.1201 + }
1.1202 + }
1.1203 + return osContinue;
1.1204 +}
1.1205 +
1.1206 +eOSState cMenuPlayList::ProcessKey(eKeys Key)
1.1207 +{
1.1208 + eOSState state = cOsdMenu::ProcessKey(Key);
1.1209 +
1.1210 + if(browsing && !HasSubMenu() && state==osContinue) { Add(); browsing=false; }
1.1211 +
1.1212 + if(state==osUnknown) {
1.1213 + switch(Key) {
1.1214 + case kOk: return ID3Info();
1.1215 + case kRed: browsing=true;
1.1216 + return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr("Add"),tr("Add all")));
1.1217 + case kGreen: return ShowID3();
1.1218 + case kYellow: return Remove();
1.1219 + case kBlue: Mark(); return osContinue;
1.1220 + case kMenu: return osEnd;
1.1221 + default: break;
1.1222 + }
1.1223 + }
1.1224 + return state;
1.1225 +}
1.1226 +
1.1227 +// --- cPlaylistRename --------------------------------------------------------
1.1228 +
1.1229 +class cPlaylistRename : public cOsdMenu {
1.1230 +private:
1.1231 + static char *newname;
1.1232 + const char *oldname;
1.1233 + char data[64];
1.1234 +public:
1.1235 + cPlaylistRename(const char *Oldname);
1.1236 + virtual eOSState ProcessKey(eKeys Key);
1.1237 + static const char *GetNewname(void) { return newname; }
1.1238 + };
1.1239 +
1.1240 +char *cPlaylistRename::newname = NULL;
1.1241 +
1.1242 +cPlaylistRename::cPlaylistRename(const char *Oldname)
1.1243 +:cOsdMenu(tr("Rename playlist"), 15)
1.1244 +{
1.1245 + free(newname); newname=0;
1.1246 +
1.1247 + oldname=Oldname;
1.1248 + char *buf=NULL;
1.1249 + asprintf(&buf,"%s\t%s",tr("Old name:"),oldname);
1.1250 + cOsdItem *old = new cOsdItem(buf,osContinue);
1.1251 +#if APIVERSNUM >= 10307
1.1252 + old->SetSelectable(false);
1.1253 +#else
1.1254 + old->SetColor(clrWhite, clrBackground);
1.1255 +#endif
1.1256 + Add(old);
1.1257 + free(buf);
1.1258 +
1.1259 + data[0]=0;
1.1260 + Add(new cMenuEditStrItem( tr("New name"), data, sizeof(data)-1, tr(FileNameChars)),true);
1.1261 +}
1.1262 +
1.1263 +eOSState cPlaylistRename::ProcessKey(eKeys Key)
1.1264 +{
1.1265 + eOSState state = cOsdMenu::ProcessKey(Key);
1.1266 +
1.1267 + if (state == osUnknown) {
1.1268 + switch (Key) {
1.1269 + case kOk: if(data[0] && strcmp(data,oldname)) newname=strdup(data);
1.1270 + return osBack;
1.1271 + case kRed:
1.1272 + case kGreen:
1.1273 + case kYellow:
1.1274 + case kBlue: return osContinue;
1.1275 + default: break;
1.1276 + }
1.1277 + }
1.1278 + return state;
1.1279 +}
1.1280 +
1.1281 +// --- cMenuMP3Item -----------------------------------------------------
1.1282 +
1.1283 +class cMenuMP3Item : public cOsdItem {
1.1284 + private:
1.1285 + cPlayList *playlist;
1.1286 + virtual void Set(void);
1.1287 +public:
1.1288 + cMenuMP3Item(cPlayList *PlayList);
1.1289 + cPlayList *List(void) { return playlist; }
1.1290 + };
1.1291 +
1.1292 +cMenuMP3Item::cMenuMP3Item(cPlayList *PlayList)
1.1293 +{
1.1294 + playlist=PlayList;
1.1295 + Set();
1.1296 +}
1.1297 +
1.1298 +void cMenuMP3Item::Set(void)
1.1299 +{
1.1300 + char *buffer=0;
1.1301 + asprintf(&buffer," %s",playlist->BaseName());
1.1302 + SetText(buffer,false);
1.1303 +}
1.1304 +
1.1305 +// --- cMenuMP3 --------------------------------------------------------
1.1306 +
1.1307 +class cMenuMP3 : public cOsdMenu {
1.1308 +private:
1.1309 + cPlayLists *lists;
1.1310 + bool renaming, sourcing, instanting;
1.1311 + int buttonnum;
1.1312 + eOSState Play(void);
1.1313 + eOSState Edit(void);
1.1314 + eOSState New(void);
1.1315 + eOSState Delete(void);
1.1316 + eOSState Rename(bool second);
1.1317 + eOSState Source(bool second);
1.1318 + eOSState Instant(bool second);
1.1319 + void ScanLists(void);
1.1320 + eOSState SetButtons(int num);
1.1321 +public:
1.1322 + cMenuMP3(void);
1.1323 + ~cMenuMP3(void);
1.1324 + virtual eOSState ProcessKey(eKeys Key);
1.1325 + };
1.1326 +
1.1327 +cMenuMP3::cMenuMP3(void)
1.1328 +:cOsdMenu(tr("MP3"))
1.1329 +{
1.1330 + renaming=sourcing=instanting=false;
1.1331 + lists=new cPlayLists;
1.1332 + ScanLists(); SetButtons(1);
1.1333 + if(MP3Setup.MenuMode) Instant(false);
1.1334 +}
1.1335 +
1.1336 +cMenuMP3::~cMenuMP3(void)
1.1337 +{
1.1338 + delete lists;
1.1339 +}
1.1340 +
1.1341 +eOSState cMenuMP3::SetButtons(int num)
1.1342 +{
1.1343 + switch(num) {
1.1344 + case 1:
1.1345 + SetHelp(tr(BUTTON"Edit"), tr("Source"), tr("Browse"), ">>");
1.1346 + break;
1.1347 + case 2:
1.1348 + SetHelp("<<", tr(BUTTON"New"), tr(BUTTON"Delete"), tr("Rename"));
1.1349 + break;
1.1350 + }
1.1351 + buttonnum=num; Display();
1.1352 + return osContinue;
1.1353 +}
1.1354 +
1.1355 +void cMenuMP3::ScanLists(void)
1.1356 +{
1.1357 + Clear();
1.1358 + Status(tr("Scanning playlists..."));
1.1359 + bool res=lists->Load(MP3Sources.GetSource());
1.1360 + Status(0);
1.1361 + if(res) {
1.1362 + cPlayList *plist=lists->First();
1.1363 + while(plist) {
1.1364 + Add(new cMenuMP3Item(plist));
1.1365 + plist=lists->Next(plist);
1.1366 + }
1.1367 + }
1.1368 + else Error(tr("Error scanning playlists!"));
1.1369 +}
1.1370 +
1.1371 +eOSState cMenuMP3::Delete(void)
1.1372 +{
1.1373 + if(Count()>0) {
1.1374 + if(Interface->Confirm(tr("Delete playlist?")) &&
1.1375 + Interface->Confirm(tr("Are you sure?")) ) {
1.1376 + cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List();
1.1377 + if(plist->Delete()) {
1.1378 + lists->Del(plist);
1.1379 + cOsdMenu::Del(Current());
1.1380 + Display();
1.1381 + }
1.1382 + else Error(tr("Error deleting playlist!"));
1.1383 + }
1.1384 + }
1.1385 + return osContinue;
1.1386 +}
1.1387 +
1.1388 +eOSState cMenuMP3::New(void)
1.1389 +{
1.1390 + cPlayList *plist=new cPlayList(MP3Sources.GetSource(),0,0);
1.1391 + char name[32];
1.1392 + int i=0;
1.1393 + do {
1.1394 + if(i) sprintf(name,"%s%d",tr("unnamed"),i++);
1.1395 + else { strcpy(name,tr("unnamed")); i++; }
1.1396 + } while(plist->TestName(name));
1.1397 +
1.1398 + if(plist->Create(name)) {
1.1399 + lists->Add(plist);
1.1400 + Add(new cMenuMP3Item(plist), true);
1.1401 +
1.1402 + isyslog("MP3: playlist %s added", plist->Name());
1.1403 + return AddSubMenu(new cMenuPlayList(plist));
1.1404 + }
1.1405 + Error(tr("Error creating playlist!"));
1.1406 + delete plist;
1.1407 + return osContinue;
1.1408 +}
1.1409 +
1.1410 +eOSState cMenuMP3::Rename(bool second)
1.1411 +{
1.1412 + if(HasSubMenu() || Count() == 0) return osContinue;
1.1413 +
1.1414 + cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List();
1.1415 + if(!second) {
1.1416 + renaming=true;
1.1417 + return AddSubMenu(new cPlaylistRename(plist->BaseName()));
1.1418 + }
1.1419 + renaming=false;
1.1420 + const char *newname=cPlaylistRename::GetNewname();
1.1421 + if(newname) {
1.1422 + if(plist->Rename(newname)) {
1.1423 + RefreshCurrent();
1.1424 + DisplayCurrent(true);
1.1425 + }
1.1426 + else Error(tr("Error renaming playlist!"));
1.1427 + }
1.1428 + return osContinue;
1.1429 +}
1.1430 +
1.1431 +eOSState cMenuMP3::Edit(void)
1.1432 +{
1.1433 + if(HasSubMenu() || Count() == 0) return osContinue;
1.1434 +
1.1435 + cPlayList *plist = ((cMenuMP3Item *)Get(Current()))->List();
1.1436 + if(!plist->Load()) Error(tr("Error loading playlist!"));
1.1437 + else if(!plist->IsWinAmp()) {
1.1438 + isyslog("MP3: editing playlist %s", plist->Name());
1.1439 + return AddSubMenu(new cMenuPlayList(plist));
1.1440 + }
1.1441 + else Error(tr("Can't edit a WinAmp playlist!"));
1.1442 + return osContinue;
1.1443 +}
1.1444 +
1.1445 +eOSState cMenuMP3::Play(void)
1.1446 +{
1.1447 + if(HasSubMenu() || Count() == 0) return osContinue;
1.1448 +
1.1449 + Status(tr("Loading playlist..."));
1.1450 + cPlayList *newpl=new cPlayList(((cMenuMP3Item *)Get(Current()))->List());
1.1451 + if(newpl->Load() && newpl->Count()) {
1.1452 + isyslog("mp3: playback started with playlist %s", newpl->Name());
1.1453 + cMP3Control::SetPlayList(newpl);
1.1454 + if(MP3Setup.KeepSelect) { Status(0); return osContinue; }
1.1455 + return osEnd;
1.1456 + }
1.1457 + Status(0);
1.1458 + delete newpl;
1.1459 + Error(tr("Error loading playlist!"));
1.1460 + return osContinue;
1.1461 +}
1.1462 +
1.1463 +eOSState cMenuMP3::Source(bool second)
1.1464 +{
1.1465 + if(HasSubMenu()) return osContinue;
1.1466 +
1.1467 + if(!second) {
1.1468 + sourcing=true;
1.1469 + return AddSubMenu(new cMenuSource(&MP3Sources,tr("MP3 source")));
1.1470 + }
1.1471 + sourcing=false;
1.1472 + cFileSource *src=cMenuSource::GetSelected();
1.1473 + if(src) {
1.1474 + MP3Sources.SetSource(src);
1.1475 + ScanLists();
1.1476 + Display();
1.1477 + }
1.1478 + return osContinue;
1.1479 +}
1.1480 +
1.1481 +eOSState cMenuMP3::Instant(bool second)
1.1482 +{
1.1483 + if(HasSubMenu()) return osContinue;
1.1484 +
1.1485 + if(!second) {
1.1486 + instanting=true;
1.1487 + return AddSubMenu(new cMenuInstantBrowse(MP3Sources.GetSource(),tr(BUTTON"Play"),tr("Play all")));
1.1488 + }
1.1489 + instanting=false;
1.1490 + cFileObj *item=cMenuInstantBrowse::GetSelected();
1.1491 + if(item) {
1.1492 + Status(tr("Building playlist..."));
1.1493 + cInstantPlayList *newpl = new cInstantPlayList(item);
1.1494 + if(newpl->Load() && newpl->Count()) {
1.1495 + isyslog("mp3: playback started with instant playlist %s", newpl->Name());
1.1496 + cMP3Control::SetPlayList(newpl);
1.1497 + if(MP3Setup.KeepSelect) { Status(0); return Instant(false); }
1.1498 + return osEnd;
1.1499 + }
1.1500 + Status(0);
1.1501 + delete newpl;
1.1502 + Error(tr("Error building playlist!"));
1.1503 + }
1.1504 + return osContinue;
1.1505 +}
1.1506 +
1.1507 +eOSState cMenuMP3::ProcessKey(eKeys Key)
1.1508 +{
1.1509 + eOSState state = cOsdMenu::ProcessKey(Key);
1.1510 +
1.1511 + if(!HasSubMenu() && state==osContinue) { // eval the return value from submenus
1.1512 + if(renaming) return Rename(true);
1.1513 + if(sourcing) return Source(true);
1.1514 + if(instanting) return Instant(true);
1.1515 + }
1.1516 +
1.1517 + if(state == osUnknown) {
1.1518 + switch(Key) {
1.1519 + case kOk: return Play();
1.1520 + case kRed: return (buttonnum==1 ? Edit() : SetButtons(1));
1.1521 + case kGreen: return (buttonnum==1 ? Source(false) : New());
1.1522 + case kYellow: return (buttonnum==1 ? Instant(false) : Delete());
1.1523 + case kBlue: return (buttonnum==1 ? SetButtons(2) : Rename(false));
1.1524 + case kMenu: return osEnd;
1.1525 + default: break;
1.1526 + }
1.1527 + }
1.1528 + return state;
1.1529 +}
1.1530 +
1.1531 +// --- PropagateImage ----------------------------------------------------------
1.1532 +
1.1533 +void PropagateImage(const char *image)
1.1534 +{
1.1535 + cPlugin *graphtft=cPluginManager::GetPlugin("graphtft");
1.1536 + if(graphtft) graphtft->SetupParse("CoverImage",image ? image:"");
1.1537 +}
1.1538 +
1.1539 +// --- cPluginMP3 --------------------------------------------------------------
1.1540 +
1.1541 +static const char *VERSION = PLUGIN_VERSION;
1.1542 +static const char *DESCRIPTION = "A versatile audio player";
1.1543 +static const char *MAINMENUENTRY = "MP3";
1.1544 +
1.1545 +class cPluginMp3 : public cPlugin {
1.1546 +private:
1.1547 +#if APIVERSNUM >= 10330
1.1548 + bool ExternalPlay(const char *path, bool test);
1.1549 +#endif
1.1550 +public:
1.1551 + cPluginMp3(void);
1.1552 + virtual ~cPluginMp3();
1.1553 + virtual const char *Version(void) { return VERSION; }
1.1554 + virtual const char *Description(void) { return tr(DESCRIPTION); }
1.1555 + virtual const char *CommandLineHelp(void);
1.1556 + virtual bool ProcessArgs(int argc, char *argv[]);
1.1557 +#if APIVERSNUM >= 10131
1.1558 + virtual bool Initialize(void);
1.1559 +#else
1.1560 + virtual bool Start(void);
1.1561 +#endif
1.1562 + virtual void Housekeeping(void);
1.1563 + virtual const char *MainMenuEntry(void);
1.1564 + virtual cOsdObject *MainMenuAction(void);
1.1565 + virtual cMenuSetupPage *SetupMenu(void);
1.1566 + virtual bool SetupParse(const char *Name, const char *Value);
1.1567 +#if APIVERSNUM >= 10330
1.1568 + virtual bool Service(const char *Id, void *Data);
1.1569 +#if APIVERSNUM >= 10331
1.1570 + virtual const char **SVDRPHelpPages(void);
1.1571 + virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
1.1572 +#endif
1.1573 +#endif
1.1574 + };
1.1575 +
1.1576 +cPluginMp3::cPluginMp3(void)
1.1577 +{
1.1578 + // Initialize any member varaiables here.
1.1579 + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
1.1580 + // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
1.1581 +}
1.1582 +
1.1583 +cPluginMp3::~cPluginMp3()
1.1584 +{
1.1585 + InfoCache.Save();
1.1586 + delete mgr;
1.1587 +}
1.1588 +
1.1589 +const char *cPluginMp3::CommandLineHelp(void)
1.1590 +{
1.1591 + static char *help_str=0;
1.1592 +
1.1593 + free(help_str); // for easier orientation, this is column 80|
1.1594 + asprintf(&help_str," -m CMD, --mount=CMD use CMD to mount/unmount/eject mp3 sources\n"
1.1595 + " (default: %s)\n"
1.1596 + " -n CMD, --network=CMD execute CMD before & after network access\n"
1.1597 + " (default: %s)\n"
1.1598 + " -C DIR, --cache=DIR store ID3 cache file in DIR\n"
1.1599 + " (default: %s)\n"
1.1600 + " -B DIR, --cddb=DIR search CDDB files in DIR\n"
1.1601 + " (default: %s)\n"
1.1602 + " -D DEV, --dsp=DEV device for OSS output\n"
1.1603 + " (default: %s)\n"
1.1604 + " -i CMD, --iconv=CMD use CMD to convert background images\n"
1.1605 + " (default: %s)\n"
1.1606 + " -c DIR, --icache=DIR cache converted images in DIR\n"
1.1607 + " (default: %s)\n"
1.1608 + " -S SUB, --sources=SUB search sources config in SUB subdirectory\n"
1.1609 + " (default: %s)\n",
1.1610 +
1.1611 + mountscript,
1.1612 + netscript ? netscript:"none",
1.1613 + cachedir ? cachedir:"video dir",
1.1614 +#ifdef HAVE_SNDFILE
1.1615 + cddbpath,
1.1616 +#else
1.1617 + "none",
1.1618 +#endif
1.1619 +#ifdef WITH_OSS
1.1620 + dspdevice,
1.1621 +#else
1.1622 + "none",
1.1623 +#endif
1.1624 + imageconv,
1.1625 + imagecache,
1.1626 + sourcesSub ? sourcesSub:"empty"
1.1627 + );
1.1628 + return help_str;
1.1629 +}
1.1630 +
1.1631 +bool cPluginMp3::ProcessArgs(int argc, char *argv[])
1.1632 +{
1.1633 + static struct option long_options[] = {
1.1634 + { "mount", required_argument, NULL, 'm' },
1.1635 + { "network", required_argument, NULL, 'n' },
1.1636 + { "cddb", required_argument, NULL, 'B' },
1.1637 + { "dsp", required_argument, NULL, 'D' },
1.1638 + { "cache", required_argument, NULL, 'C' },
1.1639 + { "icache", required_argument, NULL, 'c' },
1.1640 + { "iconv", required_argument, NULL, 'i' },
1.1641 + { "sources", required_argument, NULL, 'S' },
1.1642 + { NULL }
1.1643 + };
1.1644 +
1.1645 + int c, option_index = 0;
1.1646 + while((c=getopt_long(argc,argv,"c:i:m:n:B:C:D:S:",long_options,&option_index))!=-1) {
1.1647 + switch (c) {
1.1648 + case 'i': imageconv=optarg; break;
1.1649 + case 'c': imagecache=optarg; break;
1.1650 + case 'm': mountscript=optarg; break;
1.1651 + case 'n': netscript=optarg; break;
1.1652 + case 'C': cachedir=optarg; break;
1.1653 + case 'S': sourcesSub=optarg; break;
1.1654 + case 'B':
1.1655 +#ifdef HAVE_SNDFILE
1.1656 + cddbpath=optarg; break;
1.1657 +#else
1.1658 + fprintf(stderr, "mp3: libsndfile support has not been compiled in!\n"); return false;
1.1659 +#endif
1.1660 + case 'D':
1.1661 +#ifdef WITH_OSS
1.1662 + dspdevice=optarg; break;
1.1663 +#else
1.1664 + fprintf(stderr, "mp3: OSS output has not been compiled in!\n"); return false;
1.1665 +#endif
1.1666 + default: return false;
1.1667 + }
1.1668 + }
1.1669 + return true;
1.1670 +}
1.1671 +
1.1672 +#if APIVERSNUM >= 10131
1.1673 +bool cPluginMp3::Initialize(void)
1.1674 +#else
1.1675 +bool cPluginMp3::Start(void)
1.1676 +#endif
1.1677 +{
1.1678 + if(!CheckVDRVersion(1,1,29,"mp3")) return false;
1.1679 + i18n_name=Name();
1.1680 + MP3Sources.Load(AddDirectory(ConfigDirectory(sourcesSub),"mp3sources.conf"));
1.1681 + if(MP3Sources.Count()<1) {
1.1682 + esyslog("ERROR: you should have defined at least one source in mp3sources.conf");
1.1683 + fprintf(stderr,"No source(s) defined in mp3sources.conf\n");
1.1684 + return false;
1.1685 + }
1.1686 + InfoCache.Load();
1.1687 + RegisterI18n(Phrases);
1.1688 + mgr=new cPlayManager;
1.1689 + if(!mgr) {
1.1690 + esyslog("ERROR: creating playmanager failed");
1.1691 + fprintf(stderr,"Creating playmanager failed\n");
1.1692 + return false;
1.1693 + }
1.1694 + d(printf("mp3: using %s\n",mad_version))
1.1695 + d(printf("mp3: compiled with %s\n",MAD_VERSION))
1.1696 + return true;
1.1697 +}
1.1698 +
1.1699 +void cPluginMp3::Housekeeping(void)
1.1700 +{
1.1701 + InfoCache.Save();
1.1702 +}
1.1703 +
1.1704 +const char *cPluginMp3::MainMenuEntry(void)
1.1705 +{
1.1706 + return MP3Setup.HideMainMenu ? 0 : tr(MAINMENUENTRY);
1.1707 +}
1.1708 +
1.1709 +cOsdObject *cPluginMp3::MainMenuAction(void)
1.1710 +{
1.1711 + return new cMenuMP3;
1.1712 +}
1.1713 +
1.1714 +cMenuSetupPage *cPluginMp3::SetupMenu(void)
1.1715 +{
1.1716 + return new cMenuSetupMP3;
1.1717 +}
1.1718 +
1.1719 +bool cPluginMp3::SetupParse(const char *Name, const char *Value)
1.1720 +{
1.1721 + if (!strcasecmp(Name, "InitLoopMode")) MP3Setup.InitLoopMode = atoi(Value);
1.1722 + else if (!strcasecmp(Name, "InitShuffleMode")) MP3Setup.InitShuffleMode = atoi(Value);
1.1723 + else if (!strcasecmp(Name, "AudioMode")) MP3Setup.AudioMode = atoi(Value);
1.1724 + else if (!strcasecmp(Name, "BgrScan")) MP3Setup.BgrScan = atoi(Value);
1.1725 + else if (!strcasecmp(Name, "EditorMode")) MP3Setup.EditorMode = atoi(Value);
1.1726 + else if (!strcasecmp(Name, "DisplayMode")) MP3Setup.DisplayMode = atoi(Value);
1.1727 + else if (!strcasecmp(Name, "BackgrMode")) MP3Setup.BackgrMode = atoi(Value);
1.1728 + else if (!strcasecmp(Name, "MenuMode")) MP3Setup.MenuMode = atoi(Value);
1.1729 + else if (!strcasecmp(Name, "TargetLevel")) MP3Setup.TargetLevel = atoi(Value);
1.1730 + else if (!strcasecmp(Name, "LimiterLevel")) MP3Setup.LimiterLevel = atoi(Value);
1.1731 + else if (!strcasecmp(Name, "Only48kHz")) MP3Setup.Only48kHz = atoi(Value);
1.1732 + else if (!strcasecmp(Name, "UseProxy")) MP3Setup.UseProxy = atoi(Value);
1.1733 + else if (!strcasecmp(Name, "ProxyHost")) strn0cpy(MP3Setup.ProxyHost,Value,MAX_HOSTNAME);
1.1734 + else if (!strcasecmp(Name, "ProxyPort")) MP3Setup.ProxyPort = atoi(Value);
1.1735 + else if (!strcasecmp(Name, "UseCddb")) MP3Setup.UseCddb = atoi(Value);
1.1736 + else if (!strcasecmp(Name, "CddbHost")) strn0cpy(MP3Setup.CddbHost,Value,MAX_HOSTNAME);
1.1737 + else if (!strcasecmp(Name, "CddbPort")) MP3Setup.CddbPort = atoi(Value);
1.1738 + else if (!strcasecmp(Name, "AbortAtEOL")) MP3Setup.AbortAtEOL = atoi(Value);
1.1739 + else if (!strcasecmp(Name, "AudioOutMode")) {
1.1740 + MP3Setup.AudioOutMode = atoi(Value);
1.1741 +#ifndef WITH_OSS
1.1742 + if(MP3Setup.AudioOutMode==AUDIOOUTMODE_OSS) {
1.1743 + esyslog("WARNING: AudioOutMode OSS not supported, falling back to DVB");
1.1744 + MP3Setup.AudioOutMode=AUDIOOUTMODE_DVB;
1.1745 + }
1.1746 +#endif
1.1747 + }
1.1748 +#if APIVERSNUM >= 10307
1.1749 + else if (!strcasecmp(Name, "ReplayDisplay")) MP3Setup.ReplayDisplay = atoi(Value);
1.1750 +#endif
1.1751 + else if (!strcasecmp(Name, "HideMainMenu")) MP3Setup.HideMainMenu = atoi(Value);
1.1752 + else if (!strcasecmp(Name, "KeepSelect")) MP3Setup.KeepSelect = atoi(Value);
1.1753 + else if (!strcasecmp(Name, "TitleArtistOrder")) MP3Setup.TitleArtistOrder = atoi(Value);
1.1754 + else return false;
1.1755 + return true;
1.1756 +}
1.1757 +
1.1758 +#if APIVERSNUM >= 10330
1.1759 +
1.1760 +bool cPluginMp3::ExternalPlay(const char *path, bool test)
1.1761 +{
1.1762 + char real[PATH_MAX+1];
1.1763 + if(realpath(path,real)) {
1.1764 + cFileSource *src=MP3Sources.FindSource(real);
1.1765 + if(src) {
1.1766 + cFileObj *item=new cFileObj(src,0,0,otFile);
1.1767 + if(item) {
1.1768 + item->SplitAndSet(real);
1.1769 + if(item->GuessType()) {
1.1770 + if(item->Exists()) {
1.1771 + cInstantPlayList *pl=new cInstantPlayList(item);
1.1772 + if(pl && pl->Load() && pl->Count()) {
1.1773 + if(!test) cMP3Control::SetPlayList(pl);
1.1774 + else delete pl;
1.1775 + delete item;
1.1776 + return true;
1.1777 + }
1.1778 + else dsyslog("MP3 service: error building playlist");
1.1779 + delete pl;
1.1780 + }
1.1781 + else dsyslog("MP3 service: cannot play '%s'",path);
1.1782 + }
1.1783 + else dsyslog("MP3 service: GuessType() failed for '%s'",path);
1.1784 + delete item;
1.1785 + }
1.1786 + }
1.1787 + else dsyslog("MP3 service: cannot find source for '%s', real '%s'",path,real);
1.1788 + }
1.1789 + else if(errno!=ENOENT && errno!=ENOTDIR)
1.1790 + esyslog("ERROR: realpath: %s: %s",path,strerror(errno));
1.1791 + return false;
1.1792 +}
1.1793 +
1.1794 +bool cPluginMp3::Service(const char *Id, void *Data)
1.1795 +{
1.1796 + if(!strcasecmp(Id,"MP3-Play-v1")) {
1.1797 + if(Data) {
1.1798 + struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
1.1799 + msd->result=ExternalPlay(msd->data.filename,false);
1.1800 + }
1.1801 + return true;
1.1802 + }
1.1803 + else if(!strcasecmp(Id,"MP3-Test-v1")) {
1.1804 + if(Data) {
1.1805 + struct MPlayerServiceData *msd=(struct MPlayerServiceData *)Data;
1.1806 + msd->result=ExternalPlay(msd->data.filename,true);
1.1807 + }
1.1808 + return true;
1.1809 + }
1.1810 + return false;
1.1811 +}
1.1812 +
1.1813 +#if APIVERSNUM >= 10331
1.1814 +
1.1815 +const char **cPluginMp3::SVDRPHelpPages(void)
1.1816 +{
1.1817 + static const char *HelpPages[] = {
1.1818 + "PLAY <filename>\n"
1.1819 + " Triggers playback of file 'filename'.",
1.1820 + "TEST <filename>\n"
1.1821 + " Tests is playback of file 'filename' is possible.",
1.1822 + "CURR\n"
1.1823 + " Returns filename of song currently being replayed.",
1.1824 + NULL
1.1825 + };
1.1826 + return HelpPages;
1.1827 +}
1.1828 +
1.1829 +cString cPluginMp3::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
1.1830 +{
1.1831 + if(!strcasecmp(Command,"PLAY")) {
1.1832 + if(*Option) {
1.1833 + if(ExternalPlay(Option,false)) return "Playback triggered";
1.1834 + else { ReplyCode=550; return "Playback failed"; }
1.1835 + }
1.1836 + else { ReplyCode=501; return "Missing filename"; }
1.1837 + }
1.1838 + else if(!strcasecmp(Command,"TEST")) {
1.1839 + if(*Option) {
1.1840 + if(ExternalPlay(Option,true)) return "Playback possible";
1.1841 + else { ReplyCode=550; return "Playback not possible"; }
1.1842 + }
1.1843 + else { ReplyCode=501; return "Missing filename"; }
1.1844 + }
1.1845 + else if(!strcasecmp(Command,"CURR")) {
1.1846 + cControl *control=cControl::Control();
1.1847 + if(control && typeid(*control)==typeid(cMP3Control)) {
1.1848 + cMP3PlayInfo mode;
1.1849 + if(mgr->Info(-1,&mode)) return mode.Filename;
1.1850 + else return "<unknown>";
1.1851 + }
1.1852 + else { ReplyCode=550; return "No running playback"; }
1.1853 + }
1.1854 + return NULL;
1.1855 +}
1.1856 +
1.1857 +#endif // 1.3.31
1.1858 +#endif // 1.3.30
1.1859 +
1.1860 +VDRPLUGINCREATOR(cPluginMp3); // Don't touch this!