]> git.vomp.tv Git - vompclient.git/blob - audioplayer.cc
Windows fixes
[vompclient.git] / audioplayer.cc
1 /*
2     Copyright 2004-2006 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
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.
10
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.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "demuxeraudio.h"
21 #include "video.h"
22 #include "messagequeue.h"
23 #include "i18n.h"
24 #include "boxx.h"
25 #include "log.h"
26 #include "media.h"
27 #include "mediaplayer.h"
28
29 #include "audioplayer.h"
30
31 //how often do we retry if there is no data in stream
32 #define MAXTRY 50 
33
34 AudioPlayer * AudioPlayer::instance=NULL;
35
36 AudioPlayer * AudioPlayer::getInstance(Boxx * parent,bool create) {
37 //      Log::getInstance()->log("AudioPlayer",Log::DEBUG,"getInstance for view %p, instance=%p",parent,instance);
38         AudioPlayer *np=instance;
39         if (! np && ! create) return NULL;
40         if (! np) {
41                 np=new AudioPlayer(parent);
42                 np->run();
43                 instance=np;
44         }
45         instance->threadLock();
46         instance->frontend=parent;
47         instance->threadUnlock();
48         return instance;
49 }
50
51 AudioPlayer::AudioPlayer(Boxx *parent) : afeed(this)
52 {
53         frontend=parent;
54   audio = Audio::getInstance();
55   logger = Log::getInstance();
56   vdr = VDR::getInstance();
57   logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorI");
58   running=true;
59         playerRunnig=false;
60   streampos = 0;
61         bytesWritten=0;
62   state = S_STOP;
63         requestState=S_STOP;
64         feederState=FEEDER_STOP;
65
66   threadBuffer = NULL;
67   
68         Video::getInstance()->turnVideoOff();
69         requestedSequence=0;
70         sequence=0;
71         playSequence=0;
72         currentPlaySequence=-1;
73         uri=NULL;
74         demuxer=new DemuxerAudio();
75   logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorII");
76         if (!demuxer->init(this, audio, NULL, NULL, 0, DemuxerAudio::PACKET_SIZE+200,0))
77   {
78     logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init");
79     shutdown();
80     return ;
81   }
82   logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorIII");
83   afeed.init();
84         audio->reset();
85         lenInBytes=0;
86   logger->log("AudioPlayer", Log::DEBUG, "Audio player created");
87   canPosition=false;
88 }
89
90 AudioPlayer::~AudioPlayer()
91 {
92   if (threadBuffer) free(threadBuffer);
93         Timers::getInstance()->cancelTimer(this,1);
94         controlFeeder(FEEDER_STOP);
95         audio->reset();
96         audio->setStreamType(Audio::MPEG2_PES);
97         delete demuxer;
98         demuxer=NULL;
99         delete uri;
100 }
101
102 void AudioPlayer::controlFeeder(int feederAction) {
103         logger->log("AudioPlayer",Log::DEBUG,"control feeder old=%d, new=%d",feederState,feederAction);
104         switch (feederAction) {
105                 case FEEDER_START:
106                 case FEEDER_UNPAUSE:
107                         if (feederState == FEEDER_STOP) 
108                                 afeed.start();
109                         afeed.enable();
110                         break;
111                 case FEEDER_STOP:
112                         if (feederState != FEEDER_STOP)
113                                 afeed.stop();
114                         break;
115                 case FEEDER_PAUSE:
116                         afeed.disable();
117                         break;
118         }
119         feederState=feederAction;
120 }
121
122
123 void AudioPlayer::run() {
124         if (playerRunnig) return;
125         playerRunnig=true;
126         threadStart();
127 }
128
129
130 void AudioPlayer::shutdown()
131 {
132         running=false;
133         if (playerRunnig) {
134                 threadSignalNoLock();
135                 //wait for the player thread to stop
136                 logger->log("AudioPlayer",Log::DEBUG,"shutdown - warting for player thread to stop");
137                 //at most wait 10s
138                 for (int loopcount=200;playerRunnig && loopcount > 0;loopcount--) {
139                         MILLISLEEP(50);
140                 }
141                 if (playerRunnig) {
142                   logger->log("AudioPlayer",Log::ERR,"shutdown - unable to stop player within 10s");
143                 }
144         }
145         instance=NULL;
146         delete this;
147 }
148
149 bool AudioPlayer::isPlayerRunning() {
150         return playerRunnig;
151 }
152
153 int AudioPlayer::setRequestedState(UCHAR rstate) {
154         int rt=0;
155         threadLock();
156         requestState=rstate;
157         requestedSequence++;
158         rt=requestedSequence;
159         threadUnlock();
160         return rt;
161 }
162
163
164 UCHAR AudioPlayer::getState() {
165         UCHAR rt=0;
166         threadLock();
167         rt=state;
168         threadUnlock();
169         return rt;
170 }
171
172 void AudioPlayer::setState(UCHAR s) {
173         threadLock();
174         state=s;
175         threadUnlock();
176 }
177
178 //------------------- externally called functions --------------------------
179 int AudioPlayer::play(const MediaURI * u)
180 {
181         logger->log("AudioPlayer", Log::DEBUG, "play request for %s", u->getName());
182         int rt=0;
183         threadLock();
184         if (uri) delete uri;
185         uri=new MediaURI(u);
186         requestState=S_PLAY;
187         requestedSequence++;
188         rt=requestedSequence;
189         playSequence++;
190         threadUnlock();
191         threadSignalNoLock();
192         return rt;
193 }
194
195 int AudioPlayer::stop()
196 {
197         int rt= setRequestedState(S_STOP);
198         threadSignalNoLock();
199         return rt;
200 }
201
202 int AudioPlayer::pause()
203 {
204         int rt= setRequestedState(S_PAUSE);
205         threadSignalNoLock();
206         return rt;
207 }
208 int AudioPlayer::unpause()
209 {
210         int rt= setRequestedState(S_PLAY);
211         threadSignalNoLock();
212         return rt;
213 }
214
215 int AudioPlayer::fastForward(){
216   if (! canPosition) return 1;
217         int rt=setRequestedState(S_FF);
218         threadSignalNoLock();
219         return rt;
220 }
221
222 int AudioPlayer::fastBackward(){
223   if (! canPosition) return 1;
224         int rt=setRequestedState(S_BACK);
225         threadSignalNoLock();
226         return rt;
227 }
228 int AudioPlayer::jumpToPercent(double percent){
229   if (! canPosition) return 1;
230         threadLock();
231         ULONG fsec=demuxer->getSecondsFromLen(lenInBytes);
232         ULONG npos=streampos;
233         if (fsec != 0) {
234                 fsec=(ULONG)(((double)fsec*percent)/(double)100);
235                 npos=demuxer->positionFromSeconds(fsec);
236                 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld from demux",npos);
237         }
238         if (npos == 0) {
239                 //the demuxer cannot help us
240                 npos=(ULONG)(((double)lenInBytes*percent)/(double)100);
241                 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld without demux",npos);
242         }
243         if (npos > lenInBytes) npos=lenInBytes-1;
244         requestedStreampos=npos;
245         requestState=S_POSITION;
246         requestedSequence++;
247         threadUnlock();
248         //no need to wait here...
249         return 0;
250 }
251
252 int AudioPlayer::skipForward(int seconds) {
253   if (! canPosition) return 1;
254         threadLock();
255         ULONG curr=demuxer->getSecondsFromLen(streampos);
256         ULONG dest=demuxer->positionFromSeconds(curr+(UINT)seconds);
257         if (dest != 0) {
258                 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld  skip %ds",dest,seconds);
259                 requestedStreampos=dest;
260         }
261         requestState=S_POSITION;
262         requestedSequence++;
263         threadUnlock();
264         return 0;
265 }
266 int AudioPlayer::skipBackward(int seconds) {
267   if (! canPosition) return 1;
268         threadLock();
269         ULONG curr=demuxer->getSecondsFromLen(streampos);
270         if (curr > (UINT)seconds) {
271                 ULONG dest=demuxer->positionFromSeconds(curr-(UINT)seconds);
272                 if (dest != 0) {
273                         logger->log("AudioPlayer",Log::DEBUG,"new pos %ld  skip %ds",dest,seconds);
274                         requestedStreampos=dest;
275                         requestState=S_POSITION;
276                         requestedSequence++;
277                 }
278         }
279         threadUnlock();
280         return 0;
281 }
282
283
284
285 // ----------------------------------- Internal functions
286
287
288 void AudioPlayer::sendFrontendMessage(ULONG para)
289 {
290   logger->log("AudioPlayer", Log::DEBUG, "sending frontend message %ld",para);
291   Message* m = new Message();
292         threadLock();
293   m->to = frontend;
294         threadUnlock();
295   m->from = this;
296   m->message = Message::PLAYER_EVENT;
297   m->parameter = para;
298         MessageQueue::getInstance()->postMessage(m);
299 }
300
301 //open a new file
302 //called within the thread!
303 int AudioPlayer::openFile() {
304                 threadLock();
305           MediaURI  fn(uri);
306                 threadUnlock();
307     demuxer->reset();
308           streampos=0;
309                 bytesWritten=0;
310     MediaPlayer::getInstance()->closeMediaChannel(2);
311     int rt=MediaPlayer::getInstance()->openMedium(2,&fn,&lenInBytes,0,0);
312     Log::getInstance()->log("Audioplayer", Log::DEBUG, "request file rt=%d file=%s",rt,fn.getDisplayName());
313                 if (rt != 0) {
314                         return 1;
315                 }
316     MediaInfo mi;
317     rt=MediaPlayer::getInstance()->getMediaInfo(2,&mi);
318     canPosition=mi.canPosition;
319     ULONG rsize=0;
320     UCHAR *idbuf=NULL;
321     if (canPosition) {
322       rt=MediaPlayer::getInstance()->getMediaBlock(2,0,demuxer->headerBytes(),&rsize,&idbuf);
323     }
324     else {
325       rt=-1;
326     }
327     if (rsize < demuxer->headerBytes() || rt != 0 ) {
328       if (idbuf) free(idbuf);
329       Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get header for file %s",fn.getName());
330       return 0;
331     }
332     threadLock();
333     int hdrpos=demuxer->checkStart(idbuf,rsize);
334     threadUnlock();
335     if (hdrpos >= 0) {
336       streampos=hdrpos;
337     }
338     if (idbuf) free(idbuf);
339     idbuf=NULL;
340     if (demuxer->getId3Tag() == NULL && canPosition) {
341       //OK - look at the end
342       rt=MediaPlayer::getInstance()->getMediaBlock(2,lenInBytes-demuxer->footerBytes(),demuxer->footerBytes(),&rsize,&idbuf);
343       if (rsize < demuxer->footerBytes() || rt != 0) {
344         if (idbuf) free(idbuf);
345         Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get footer for file %s",fn.getName());
346         return 0;
347       }
348       threadLock();
349       hdrpos=demuxer->checkID3(idbuf,rsize);
350       threadUnlock();
351       if (hdrpos < 0) {
352         Log::getInstance()->log("Audioplayer", Log::DEBUG, "no ID3 in footer for file %s",fn.getName());
353       }
354       free(idbuf);
355     }
356                 return 0;
357 }
358 //method called by the playing thread to handle 
359 //"commands" by the frontend
360 UCHAR AudioPlayer::checkState()
361 {
362         threadLock();
363         UCHAR rstate=requestState;
364         UCHAR cstate=state;
365         int rseq=requestedSequence;
366         int cseq=sequence;
367         int fseq=playSequence;
368         threadUnlock();
369         //flag to decide which message to send
370         //to frontend
371         bool newFile=false;
372
373         if ( rseq > cseq) {
374                 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u", cstate, rstate);
375                 switch(rstate)
376                 {
377                         case S_PAUSE: 
378                                 if (cstate != S_PLAY && cstate != S_FF && cstate != S_PAUSE) {
379           rstate=cstate; //ignore request
380           break;
381         }
382                                 else {
383           if (cstate != S_PAUSE) {
384             skipfactor=0;
385             demuxer->setSkipFactor(0);
386             audio->mute();
387             audio->pause();
388                                     break;
389           }
390                                 }
391         //if cstate==S_PAUSE fallthrough to S_PLAY
392         rstate=S_PLAY;
393                         case S_PLAY: // to S_PLAY
394                                 skipfactor=0;
395                                 demuxer->setSkipFactor(0);
396                                 if (fseq != currentPlaySequence || cstate == S_STOP || cstate == S_ERROR || cstate == S_DONE) {
397                                         //this is a new play request interrupting the current
398                       logger->log("AudioPlayer", Log::DEBUG, "replay from start fseq=%d, startseq=%d", fseq, currentPlaySequence);
399                                         threadLock();
400                                         playSequence=fseq;
401                                         threadUnlock();
402                                         currentPlaySequence=fseq;
403                                         newFile=true;
404                                         if (cstate != S_DONE) audio->mute();
405                                         int rt=openFile();
406                                         if (rt != 0) {
407                                                 rstate=S_ERROR;
408                                         }
409                                         else {
410                                                 audio->unPause();
411                                                 if (cstate != S_DONE) {
412                                                         //flush only if we are not coming from stream end
413                                                         thisRead=0;
414                                                         thisWrite=0;
415                                                         if (threadBuffer) free(threadBuffer);
416                                                   threadBuffer=NULL;
417                                                         controlFeeder(FEEDER_STOP);
418                                                         demuxer->flush();
419                                                         controlFeeder(FEEDER_START);
420                                                         audio->reset();
421                                                         audio->systemMuteOff();
422                                                         audio->setStreamType(Audio::MP3); 
423                                                 }
424                                                 audio->unMute();
425                                                 audio->play();
426                                         }
427                                 }
428                                 else if (cstate == S_PAUSE){
429                                         newFile=true;
430                                         audio->unPause();
431                                         audio->unMute();
432                                 }
433                                 else if (cstate == S_FF || S_BACK) {
434                                         ;
435                                 }
436                                 else {
437                                         rstate=cstate;
438                                 }
439                                 break;
440                         case S_DONE:
441                                 Timers::getInstance()->setTimerD(this,1,4);
442                                 //inform the frontend
443                                 break;
444                         case S_FF:
445                                 if (cstate != S_PLAY && cstate != S_PAUSE && cstate != S_FF) {
446                                         rstate=cstate;
447                                 }
448                                 else {
449                                         if (skipfactor == 0) skipfactor=2;
450                                         else skipfactor=skipfactor<<1;
451                                         if (skipfactor > 16 ) skipfactor=2;
452                                         demuxer->setSkipFactor(skipfactor);
453                                 }
454                                 if (cstate == S_PAUSE) {
455                                         audio->unPause();
456                                         audio->unMute();
457                                 }
458                                 break;
459                         case S_POSITION:
460                                 if (cstate != S_PLAY && cstate != S_PAUSE) {
461                                         rstate=cstate;
462                                 }
463                                 else {
464                                         audio->mute();
465                                         audio->unPause();
466                                         controlFeeder(FEEDER_STOP);
467                                         demuxer->flush();
468                                         thisRead=0;
469                                         thisWrite=0;
470                                         if (threadBuffer) free(threadBuffer);
471                                         threadBuffer=NULL;
472                                         streampos=requestedStreampos;
473                                         bytesWritten=streampos;
474                                         audio->reset();
475                                         audio->setStreamType(Audio::MP3); 
476                                         controlFeeder(FEEDER_START);
477                                         audio->unMute();
478                                         audio->play();
479                                         rstate=S_PLAY;
480                                 }
481                                 break;
482                         default: // to S_STOP
483                                 rstate=S_STOP;
484                                 audio->mute();
485                                 audio->stop();
486                                 audio->unPause();
487                                 controlFeeder(FEEDER_STOP);
488                                 demuxer->flush();
489                                 thisRead=0;
490                                 thisWrite=0;
491                                 if (threadBuffer) free(threadBuffer);
492                                 threadBuffer=NULL;
493                     logger->log("AudioPlayer", Log::DEBUG, "stop handled fseq: %d startseq %d completed", playSequence, currentPlaySequence);
494                                 break;
495                 }
496                 threadLock();
497                 state=rstate;
498                 sequence=rseq;
499                 threadUnlock();
500                 if (newFile) sendFrontendMessage(NEW_SONG);
501                 else if (cstate != rstate && rstate != S_DONE ) {
502                         sendFrontendMessage(STATUS_CHANGE);
503                         //any change after done cancels the "done" timer
504                         Timers::getInstance()->cancelTimer(this,1);
505                 }
506                 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u completed seq=%d, nf=%s", cstate, rstate,rseq,newFile?"true":"false");
507                 //we return the newly set state
508                 return rstate;
509         }
510         //rstate could be different but no new request - so return cstate
511         return cstate;
512 }
513
514
515
516
517 // ----------------------------------- Feed thread
518
519 void AudioPlayer::waitTimed(int ms) {
520         threadLock();
521         struct timespec nt;
522         int sec=ms/1000;
523         int us=1000*(ms - 1000*sec);
524 #ifndef WIN32
525         struct timeval ct;
526         gettimeofday(&ct,NULL);
527         nt.tv_sec=ct.tv_sec+sec;
528         nt.tv_nsec=1000*us+1000*ct.tv_usec;
529 #else 
530     DWORD ct=timeGetTime();
531     nt.tv_sec=ct/1000+sec;
532     nt.tv_nsec=1000*us+1000*ct*1000;
533 #endif
534         threadWaitForSignalTimed(&nt);
535         threadUnlock();
536 }
537
538 void AudioPlayer::threadMethod()
539 {
540         logger->log("AudioPlayer", Log::DEBUG, "player thread started");
541         thisWrite=0;
542         thisRead=0;
543   int retrycount=0;
544   while(1)
545   {
546                 UCHAR cstate=checkState();
547     if (! running) {
548                         break;
549                 }
550                 if (cstate != S_PLAY && cstate != S_FF && cstate != S_BACK) {
551                         waitTimed(500);
552                         continue;
553                 }
554     threadCheckExit();
555
556                 if (thisWrite == thisRead) {
557                         //TODO: use normal blocks...
558                         thisRead=0;
559       thisWrite=0;
560       threadBuffer=NULL;
561       int rt=MediaPlayer::getInstance()->getMediaBlock(2,streampos,BUFLEN,&thisRead,&threadBuffer);
562       if (thisRead == 0 && threadBuffer) {
563         free(threadBuffer);
564         threadBuffer=NULL;
565       }
566                         if ((!threadBuffer || thisRead == 0 ) && rt == 0) {
567         retrycount++;
568         if (retrycount > MAXTRY) rt=-1;
569         else {
570                                   logger->log("AudioPlayer", Log::DEBUG, "no data read, retrying");
571           continue;
572         }
573       }
574
575                         if (!threadBuffer || thisRead == 0 || rt != 0) {
576                                 //OK we count this as end of stream
577                                 //hmm --- we should be able to detect if the audio has gone...
578                                 logger->log("AudioPlayer", Log::DEBUG, "stream end");
579                                 setRequestedState(S_DONE);
580         MediaPlayer::getInstance()->closeMediaChannel(2);
581         retrycount=0;
582                                 continue;
583                         }
584       retrycount=0;
585                         //logger->log("AudioPlayer", Log::DEBUG, "read %ld bytes at pos %ld",thisRead,streampos);
586                         streampos+=thisRead;
587                 }
588     
589     threadCheckExit();
590                 /*
591     MediaPacket p;
592                 memset(&p,sizeof(p),0);
593                 p.pos_buffer=0;
594                 p.length=thisRead;
595     MediaPacketList pl;
596                 pl.push_back(p);
597                 audio->PrepareMediaSample(pl,0);
598                 UINT bytesWritten=0;
599                 UINT rt=audio->DeliverMediaSample(threadBuffer,&bytesWritten);
600                 ULONG written=thisRead;
601                 if (rt == 0)
602                    written=bytesWritten;
603                 */
604     ULONG written= demuxer->put(threadBuffer + thisWrite, thisRead - thisWrite);
605     thisWrite+=written;
606                 bytesWritten+=written;
607                 if (thisWrite < thisRead) {
608                         if (written == 0) {
609         // demuxer is full and can't take anymore
610                                 waitTimed(200);
611                         }
612       }
613                 else {
614       //logger->log("AudioPlayer", Log::DEBUG, "block written %d", thisWrite);
615                         thisWrite=0;
616                         thisRead=0;
617       free(threadBuffer);
618       threadBuffer = NULL;
619                 }
620
621   }
622
623   logger->log("AudioPlayer", Log::DEBUG, "finished");
624   MediaPlayer::getInstance()->closeMediaChannel(2);
625         playerRunnig=false;
626         return;
627 }
628
629 int AudioPlayer::waitForSequence(int timeout, int seq) {
630         time_t starttime=time(NULL)+timeout;
631         time_t curtime=0;
632   logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d",seq);
633   int rt=-1;
634         while ((curtime=time(NULL)) < starttime) {
635                 int cseq=getSequence();
636                 if (cseq >= seq) {
637       rt=cseq;
638       break;
639     }
640     //logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence loop");
641                 MILLISLEEP(100);
642         }
643   logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d returns %d",seq,rt);
644         return rt;
645 }
646
647 int AudioPlayer::getSequence() {
648         int rt=0;
649         threadLock();
650         rt=sequence;
651         threadUnlock();
652         return rt;
653 }
654
655
656
657 void AudioPlayer::threadPostStopCleanup()
658 {
659   if (threadBuffer)
660   {
661     delete(threadBuffer);
662     threadBuffer = NULL;
663   }
664         playerRunnig=false;
665 }
666
667 void AudioPlayer::call(void *) {
668         threadSignalNoLock();
669 }
670
671 void AudioPlayer::timercall(int ref) {
672         if (ref == 1) {
673                 logger->log("AudioPlayer", Log::DEBUG, "stream end - informing frontend");
674                 sendFrontendMessage(STREAM_END);
675         }
676 }
677
678 //--------------------------- info functions -------------------
679
680 char * AudioPlayer::getTitle() {
681         logger->log("AudioPlayer", Log::DEBUG, "getTitle");
682         threadLock();
683         const id3_tag * tag=demuxer->getId3Tag();
684         const char * title=NULL;
685         char *rt=NULL;
686         if (tag != NULL) {
687                 title=tag->title;
688         }
689         if (title && strlen(title) != 0) {
690                 rt=new char[strlen(title)+1];
691                 strcpy(rt,title);
692                 rt[strlen(title)]=0;
693         }
694         //let the frontend fill in something
695         threadUnlock();
696         return rt;
697 }
698
699 char * AudioPlayer::getID3Info() {
700         logger->log("AudioPlayer", Log::DEBUG, "getID3Info");
701         threadLock();
702         int len=0;
703         const id3_tag * tag=demuxer->getId3Tag();
704         int taglen=0;
705         if (tag) taglen=tag->stringlen(false);
706         len+=taglen;
707         const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
708         if (info) len+=30;
709         char * rt=NULL;
710         if (len > 0) {
711                 char bitrateType='C';
712                 if (info && info->avrBitrate != info->bitRate) bitrateType='V';
713                 rt=new char[len];
714                 if (!tag && info) {
715       int sr=info->sampleRate/1000;
716                         SNPRINTF(rt,len-1,"%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n",tr("MpegInfo"),
717                                         info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100),
718                                         info->info);
719                 }
720                 else if (tag && info){
721       int sr=info->sampleRate/1000;
722                         char *tmp=new char[taglen+1];
723                         SNPRINTF(rt,len-1,"%s\n"
724                                         "%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n",
725                                         tag->toString(tmp,taglen,false),
726                                         tr("MpegInfo"),
727                                         info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100),
728                                         info->info);
729             delete [] tmp;
730                 }
731                 else if (tag && !info){
732                         char *tmp=new char[taglen+1];
733                         SNPRINTF(rt,len-1,"%s\n",
734                                         tag->toString(tmp,taglen,false));
735             delete [] tmp;
736                 }
737                 rt[len-1]=0;
738         }
739         threadUnlock();
740         logger->log("AudioPlayer", Log::DEBUG, "getID3Info returns %s",rt);
741         return rt;
742 }
743
744 ULONG AudioPlayer::getCurrentTimes(){
745         ULONG rt=0;
746         threadLock();
747         if (streampos != 0){
748           rt=demuxer->getSecondsFromLen(bytesWritten);
749           if (rt == 0) {
750                 //we can only guess
751                 rt= bytesWritten/DEFAULT_BITRATE;
752                 }
753         }
754         threadUnlock();
755         return rt;
756 }
757
758 ULONG AudioPlayer::getSonglen(){
759         ULONG rt=0;
760         threadLock();
761         const DemuxerAudio::vbrInfo * vbr=demuxer->getVBRINfo();
762         if (vbr) rt=vbr->fileSeconds;
763         else {
764                 if (lenInBytes != 0) {
765                         rt=demuxer->getSecondsFromLen(lenInBytes);
766                         if (rt == 0) {
767                                 //we can only guess
768                                 rt= lenInBytes/DEFAULT_BITRATE;
769                         }
770                 }
771         }
772         threadUnlock();
773         return rt;
774 }
775
776 int AudioPlayer::getCurrentBitrate(){
777         int rt=DEFAULT_BITRATE;
778         threadLock();
779         const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
780         if (info) rt=info->bitRate;
781         threadUnlock();
782         return rt;
783 }