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