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