2 Copyright 2004-2005 Chris Tallon, Andreas Vogel
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "vaudioplayer.h"
22 #include "audioplayer.h"
25 VAudioplayer::VAudioplayer(VMediaList *p)
28 Video* video = Video::getInstance();
29 create(video->getScreenWidth(),video->getScreenHeight());
37 numentries=p->getNumEntries(MEDIA_TYPE_AUDIO);
40 barBlue.set(0, 0, 150, 150);
44 AudioPlayer * VAudioplayer::getPlayer(bool createIfNeeded)
46 AudioPlayer* rt=AudioPlayer::getInstance(this,false);
47 if (! createIfNeeded && rt == NULL) return NULL;
49 rt=AudioPlayer::getInstance(this);
55 VAudioplayer::~VAudioplayer()
57 if (banner) ViewMan::getInstance()->removeView(banner);
58 if (fullname) delete fullname;
59 if (filename) delete filename;
60 Timers::getInstance()->cancelTimer(this,1);
61 Timers::getInstance()->cancelTimer(this,2);
62 Timers::getInstance()->cancelTimer(this,3);
63 //TODO leave this to medialist and stop only...
64 if (getPlayer(false)) {
65 AudioPlayer::getInstance(NULL,false)->shutdown();
71 void VAudioplayer::draw()
73 Log::getInstance()->log("VAudioplayer::draw", Log::DEBUG, "p=%p", this);
77 int VAudioplayer::handleCommand(int command)
79 Log::getInstance()->log("VAudioplayer::handleCommand", Log::DEBUG, "p=%p,cmd=%d", this,command);
80 Timers::getInstance()->cancelTimer(this,1);
86 play(VMediaList::MV_PREV);
87 ViewMan::getInstance()->updateView(this);
91 getPlayer()->fastForward();
96 play(VMediaList::MV_NEXT);
97 ViewMan::getInstance()->updateView(this);
100 case Remote::SKIPFORWARD:
101 getPlayer()->skipForward(10);
104 case Remote::SKIPBACK:
105 getPlayer()->skipBackward(10);
108 case Remote::REVERSE:
112 getPlayer()->jumpToPercent(0);
116 getPlayer()->jumpToPercent(10);
120 getPlayer()->jumpToPercent(20);
124 getPlayer()->jumpToPercent(30);
128 getPlayer()->jumpToPercent(40);
132 getPlayer()->jumpToPercent(50);
136 getPlayer()->jumpToPercent(60);
140 getPlayer()->jumpToPercent(70);
144 getPlayer()->jumpToPercent(80);
148 getPlayer()->jumpToPercent(90);
157 else showBanner(true);
158 if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
159 if (playall) play(VMediaList::MV_NEXT);
166 getPlayer()->unpause();
167 if (getPlayer()->getState() != AudioPlayer::S_ERROR) justPlaying=true;
168 else if (playall) play(VMediaList::MV_NEXT);
174 getPlayer()->pause();
189 if (playall) startPlayall();
190 if (rt == 2) retriggerBanner();
191 // stop command getting to any more views
192 Log::getInstance()->log("VAudioplayer::handleCommand", Log::DEBUG, "returns p=%p,cmd=%d, rt=%d", this,command,rt);
196 void VAudioplayer::processMessage(Message* m)
198 if (m->message == Message::MOUSE_MOVE)
202 else if (m->message == Message::MOUSE_LBDOWN)
205 //check if press is outside this view! then simulate cancel
206 int x=(m->parameter>>16)-getScreenX();
207 int y=(m->parameter&0xFFFF)-getScreenY();
208 if (x<0 || y <0 || x>getWidth() || y>getHeight())
210 ViewMan::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
213 else if (m->message == Message::PLAYER_EVENT) {
214 switch (m->parameter) {
215 case AudioPlayer::STREAM_ERR:
216 case AudioPlayer::STREAM_END:
217 if (playall) play(VMediaList::MV_NEXT);
218 else sendViewMsg(this,true);
220 case AudioPlayer::STATUS_CHANGE:
223 case AudioPlayer::SHORT_UPDATE:
226 ViewMan::getInstance()->updateView(banner,&clocksRegion);
227 ViewMan::getInstance()->updateView(banner,&barRegion);
228 Timers::getInstance()->setTimerD(this, 3, 1);
231 case AudioPlayer::NEW_SONG:
234 case AudioPlayer::CONNECTION_LOST:
236 if (AudioPlayer *player=getPlayer(false)) {
240 Command::getInstance()->connectionLost();
246 VAudioplayer * VAudioplayer::createPlayer(VMediaList * mparent, bool bplayall) {
247 Log::getInstance()->log("VAudioplayer::createPlayer", Log::DEBUG, "p=%p",
249 VAudioplayer *vmn=new VAudioplayer(mparent);
250 ViewMan::getInstance()->add(vmn);
251 ViewMan::getInstance()->updateView(vmn);
253 if (bplayall) vmn->startPlayall();
254 ViewMan::getInstance()->updateView(vmn);
258 void VAudioplayer::startPlayall() {
262 void VAudioplayer::play(ULONG move) {
263 currentMedia=parent->getMedia(MEDIA_TYPE_AUDIO,move);
265 const char *fname=currentMedia->getFileName();
266 ftime=currentMedia->getTime();
267 int len=strlen(fname)+2+strlen(parent->getDirname());
272 fullname=new char[len];
273 sprintf(fullname,"%s/%s",parent->getDirname(),fname);
274 if (filename) delete filename;
276 filename=new char[len];
277 strcpy(filename,fname);
278 Log::getInstance()->log("VAudioplayer::load", Log::DEBUG, "filename=%s,p=%p",
280 VDR* vdr=VDR::getInstance();
281 if (vdr->isConnected()) {
282 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "request file %s",filename);
283 int wseq=getPlayer()->play(fullname);
284 if (getPlayer()->waitForSequence(wseq,2)<0) {
285 mediaError=tr("unable to open audio file");
288 //leave this to the update message from the player:
292 if (AudioPlayer * player=getPlayer(false)) {
295 Command::getInstance()->connectionLost();
300 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "player started for %s",filename);
303 void VAudioplayer::retriggerBanner() {
304 if (! banner) return;
305 bannerTime=time(NULL);
308 void VAudioplayer::showBanner(bool forceNewTime) {
309 //if the loading flag is set,
310 //we are in the main thread - so we can (and must) safely hard destroy/create the banner
311 Timers::getInstance()->cancelTimer(this,1);
312 Timers::getInstance()->cancelTimer(this,3);
313 if (! filename || ! currentMedia) {
319 time_t curtime=time(NULL);
320 if (forceNewTime) retriggerBanner();
321 time_t remainingTime=BANNER_TIME+2-(curtime-bannerTime);
322 if (remainingTime < 2) remainingTime=2;
323 bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR;
324 if (remainingTime < BANNER_ERROR_TIME+2 && playerError) remainingTime=BANNER_ERROR_TIME+2;
325 Timers::getInstance()->setTimerD(this,1,remainingTime);
326 if (playerError) Timers::getInstance()->setTimerD(this,2,BANNER_ERROR_TIME);
327 Timers::getInstance()->setTimerD(this,3, 1);
328 ViewMan::getInstance()->updateView(banner);
331 void VAudioplayer::destroyBanner() {
333 ViewMan::getInstance()->removeView(banner);
336 Timers::getInstance()->cancelTimer(this,1);
337 Timers::getInstance()->cancelTimer(this,3);
339 void VAudioplayer::updateBanner(bool restart) {
340 time_t currTime=time(NULL);
341 time_t lastBanner=bannerTime;
342 if (currTime - lastBanner > BANNER_TIME){
345 if (banner||restart) {
349 void VAudioplayer::timercall(int clientref) {
350 Log::getInstance()->log("VAudioplayer::timercall", Log::DEBUG, "id=%d",clientref);
356 Message* m = new Message();
357 //we misuse PLAYER_EVENT here
358 m->message = Message::PLAYER_EVENT;
361 m->parameter=(clientref==1)?AudioPlayer::STATUS_CHANGE:
362 AudioPlayer::SHORT_UPDATE;
363 Command::getInstance()->postMessageFromOuterSpace(m);
368 bool stillError=false;
369 if (AudioPlayer * player=getPlayer(false)) {
370 stillError=player->getState()==AudioPlayer::S_ERROR;
373 //send a stream end to trigger nex in playlist
374 Message* m = new Message();
375 //we misuse PLAYER_EVENT here
376 m->message = Message::PLAYER_EVENT;
379 m->parameter=AudioPlayer::STREAM_END;
380 Command::getInstance()->postMessageFromOuterSpace(m);
388 void VAudioplayer::sendViewMsg(View *v,bool vdestroy) {
389 Message* m = new Message();
390 m->message = vdestroy?Message::CLOSE_ME:Message::ADD_VIEW;
391 m->to = ViewMan::getInstance();
393 m->parameter=(ULONG)v;
394 Command::getInstance()->postMessageFromOuterSpace(m);
397 View * VAudioplayer::createBannerView(int numlines) {
399 UINT height=numlines*30+60;
400 UINT vheight=Video::getInstance()->getScreenHeight();
401 UINT vwidth=Video::getInstance()->getScreenWidth();
402 if (height > vheight-2*BANNER_BOTTOM_MARGIN)
403 height=vheight-2*BANNER_BOTTOM_MARGIN;
404 rt->create(vwidth -2*BANNER_X_MARGIN, height);
405 if (Video::getInstance()->getFormat() == Video::PAL)
407 rt->setScreenPos(BANNER_X_MARGIN, vheight-height-BANNER_BOTTOM_MARGIN);
411 rt->setScreenPos(BANNER_X_MARGIN, vheight-height-BANNER_BOTTOM_MARGIN);
414 rt->setBackgroundColour(Colour::VIEWBACKGROUND);
415 rt->setTitleBarOn(0);
417 //set the regions for the closcks and bars on banner
418 barRegion.x = rt->area.w-BARLEN-20;
419 barRegion.y = rt->area.h - 30; // FIXME, need to be - 1? and below?
420 barRegion.w = rt->area.w-BARLEN+10;
423 clocksRegion.x = 130;
424 clocksRegion.y = barRegion.y + 3;
425 clocksRegion.w = 190;
426 clocksRegion.h = surface->getFontHeight();
427 Log::getInstance()->log("VAudioPlayer",Log::DEBUG,"created banner %p",rt);
428 ViewMan::getInstance()->add(rt);
433 void VAudioplayer::drawBanner(){
434 Log::getInstance()->log("VAudioPlayer",Log::DEBUG, "draw banner for %p",banner);
436 char *playerTitle=getPlayer()->getTitle();
437 if (playerTitle) title=playerTitle;
439 char *pl=tr("Playlist");
440 int num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentMedia->index);
441 bool playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
442 //1more line for long dirs
443 int numlines=playall?5:4;
446 char *playerInfo=NULL;
449 first=tr("Unable to play audio file");
453 playerInfo=getPlayer()->getID3Info();
454 len=strlen(filename)+strlen(pl)+30+strlen(parent->getDirname())+Media::TIMEBUFLEN+100;
456 for (UINT i=0;i<strlen(playerInfo);i++)
457 if (playerInfo[i] == '\n') numlines++;
458 len+=strlen(playerInfo);
465 if (numlines != bannerlines) {
466 if (banner) destroyBanner();
467 banner=createBannerView(numlines);
470 banner=createBannerView(numlines);
472 bannerlines=numlines;
475 snprintf(buf,len,"%s",first);
478 char tbuf[Media::TIMEBUFLEN];
480 snprintf(buf,len,"%s\n"
486 tr("FileName"),currentMedia->getFileName(),
488 tr("Directory"),parent->getDirname(),
489 tr("Time"),currentMedia->getTimeString(tbuf));
492 snprintf(buf,len,"%s\n"
497 tr("FileName"),currentMedia->getFileName(),
498 tr("Directory"),parent->getDirname(),
499 tr("Time"),currentMedia->getTimeString(tbuf));
502 Log::getInstance()->log("VAudioPlayer",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
503 //now the real drawing functions
506 w.setSurface(banner->surface);
508 banner->rectangle(0, 0, banner->area.w, 30, Colour::TITLEBARBACKGROUND);
509 banner->drawText(title, 5, 5, Colour::LIGHTTEXT);
510 banner->drawPara(buf,5,32,Colour::LIGHTTEXT);
512 int ybottom=banner->area.h;
513 banner->rectangle(0, ybottom - barRegion.h, banner->area.w, barRegion.h, Colour::TITLEBARBACKGROUND);
514 bool drawSymbol=true;
515 switch(getPlayer()->getState()) {
516 case AudioPlayer::S_PAUSE:
517 w.nextSymbol = WSymbol::PAUSE;
519 case AudioPlayer::S_PLAY:
520 w.nextSymbol = WSymbol::PLAY;
522 case AudioPlayer::S_DONE:
524 w.nextSymbol = WSymbol::PLAY;
528 case AudioPlayer::S_BACK:
529 w.nextSymbol = WSymbol::FBWD ;
531 case AudioPlayer::S_FF:
532 w.nextSymbol = WSymbol::FFWD ;
539 w.setSurfaceOffset(x, ybottom-24);
544 banner->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);
547 if (playerInfo) delete playerInfo;
548 if (playerTitle) delete playerTitle;
552 void VAudioplayer::drawClocks() {
553 if (! banner) return;
554 //draw clocks and bar
555 banner->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);
557 time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
558 time_t lengthSec=(time_t)(getPlayer()->getSonglen());
561 gmtime_r(¤tSec,&cpos);
562 gmtime_r(&lengthSec,&slen);
565 if (currentSec >= lengthSec)
567 snprintf(buffer,99, "-:--:-- / -:--:-- %03dk",getPlayer()->getCurrentBitrate()/1000);
571 SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,
572 getPlayer()->getCurrentBitrate()/1000);
573 //Log::getInstance()->log("VAudioplayer", Log::DEBUG, buffer);
576 banner->drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
579 int progBarXbase = 0;
582 banner->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);
583 banner->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
585 if (currentSec > lengthSec) currentSec=lengthSec;
586 if (lengthSec == 0) return;
588 // Draw yellow portion
589 int progressWidth = (barlen+2) * currentSec / lengthSec;
590 banner->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);