2 Copyright 2004-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "audioplayer.h"
22 #include "demuxeraudio.h"
30 #include "mediaplayer.h"
32 //how often do we retry if there is no data in stream
35 AudioPlayer * AudioPlayer::instance=NULL;
37 AudioPlayer * AudioPlayer::getInstance(Boxx * parent,bool create) {
38 // Log::getInstance()->log("AudioPlayer",Log::DEBUG,"getInstance for view %p, instance=%p",parent,instance);
39 AudioPlayer *np=instance;
40 if (! np && ! create) return NULL;
42 np=new AudioPlayer(parent);
46 instance->threadLock();
47 instance->frontend=parent;
48 instance->threadUnlock();
52 AudioPlayer::AudioPlayer(Boxx *parent) : afeed(this)
55 audio = Audio::getInstance();
56 logger = Log::getInstance();
57 vdr = VDR::getInstance();
58 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorI");
65 feederState=FEEDER_STOP;
69 Video::getInstance()->turnVideoOff();
73 currentPlaySequence=-1;
75 demuxer=new DemuxerAudio();
76 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorII");
77 if (!demuxer->init(this, audio, NULL, NULL, 0, DemuxerAudio::PACKET_SIZE+200,0))
79 logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init");
83 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorIII");
87 logger->log("AudioPlayer", Log::DEBUG, "Audio player created");
91 AudioPlayer::~AudioPlayer()
93 if (threadBuffer) free(threadBuffer);
94 Timers::getInstance()->cancelTimer(this,1);
95 controlFeeder(FEEDER_STOP);
97 audio->setStreamType(Audio::MPEG2_PES);
103 void AudioPlayer::controlFeeder(int feederAction) {
104 logger->log("AudioPlayer",Log::DEBUG,"control feeder old=%d, new=%d",feederState,feederAction);
105 switch (feederAction) {
108 if (feederState == FEEDER_STOP)
113 if (feederState != FEEDER_STOP)
120 feederState=feederAction;
124 void AudioPlayer::run() {
125 if (playerRunnig) return;
131 void AudioPlayer::shutdown()
135 threadSignalNoLock();
136 //wait for the player thread to stop
137 logger->log("AudioPlayer",Log::DEBUG,"shutdown - warting for player thread to stop");
139 for (int loopcount=200;playerRunnig && loopcount > 0;loopcount--) {
143 logger->log("AudioPlayer",Log::ERR,"shutdown - unable to stop player within 10s");
150 bool AudioPlayer::isPlayerRunning() {
154 int AudioPlayer::setRequestedState(UCHAR rstate) {
159 rt=requestedSequence;
165 UCHAR AudioPlayer::getState() {
173 void AudioPlayer::setState(UCHAR s) {
179 //------------------- externally called functions --------------------------
180 int AudioPlayer::play(const MediaURI * u)
182 logger->log("AudioPlayer", Log::DEBUG, "play request for %s", u->getName());
189 rt=requestedSequence;
192 threadSignalNoLock();
196 int AudioPlayer::stop()
198 int rt= setRequestedState(S_STOP);
199 threadSignalNoLock();
203 int AudioPlayer::pause()
205 int rt= setRequestedState(S_PAUSE);
206 threadSignalNoLock();
209 int AudioPlayer::unpause()
211 int rt= setRequestedState(S_PLAY);
212 threadSignalNoLock();
216 int AudioPlayer::fastForward(){
217 if (! canPosition) return 1;
218 int rt=setRequestedState(S_FF);
219 threadSignalNoLock();
223 int AudioPlayer::fastBackward(){
224 if (! canPosition) return 1;
225 int rt=setRequestedState(S_BACK);
226 threadSignalNoLock();
229 int AudioPlayer::jumpToPercent(double percent){
230 if (! canPosition) return 1;
232 ULONG fsec=demuxer->getSecondsFromLen(lenInBytes);
233 ULONG npos=streampos;
235 fsec=(ULONG)(((double)fsec*percent)/(double)100);
236 npos=demuxer->positionFromSeconds(fsec);
237 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld from demux",npos);
240 //the demuxer cannot help us
241 npos=(ULONG)(((double)lenInBytes*percent)/(double)100);
242 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld without demux",npos);
244 if (npos > lenInBytes) npos=lenInBytes-1;
245 requestedStreampos=npos;
246 requestState=S_POSITION;
249 //no need to wait here...
253 int AudioPlayer::skipForward(int seconds) {
254 if (! canPosition) return 1;
256 ULONG curr=demuxer->getSecondsFromLen(streampos);
257 ULONG dest=demuxer->positionFromSeconds(curr+(UINT)seconds);
259 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
260 requestedStreampos=dest;
262 requestState=S_POSITION;
267 int AudioPlayer::skipBackward(int seconds) {
268 if (! canPosition) return 1;
270 ULONG curr=demuxer->getSecondsFromLen(streampos);
271 if (curr > (UINT)seconds) {
272 ULONG dest=demuxer->positionFromSeconds(curr-(UINT)seconds);
274 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
275 requestedStreampos=dest;
276 requestState=S_POSITION;
286 // ----------------------------------- Internal functions
289 void AudioPlayer::sendFrontendMessage(ULONG para)
291 logger->log("AudioPlayer", Log::DEBUG, "sending frontend message %ld",para);
292 Message* m = new Message();
297 m->message = Message::PLAYER_EVENT;
299 Command::getInstance()->postMessageFromOuterSpace(m);
303 //called within the thread!
304 int AudioPlayer::openFile() {
311 MediaPlayer::getInstance()->closeMediaChannel(2);
312 int rt=MediaPlayer::getInstance()->openMedium(2,&fn,&lenInBytes,0,0);
313 Log::getInstance()->log("Audioplayer", Log::DEBUG, "request file rt=%d file=%s",rt,fn.getDisplayName());
318 rt=MediaPlayer::getInstance()->getMediaInfo(2,&mi);
319 canPosition=mi.canPosition;
323 rt=MediaPlayer::getInstance()->getMediaBlock(2,0,demuxer->headerBytes(),&rsize,&idbuf);
328 if (rsize < demuxer->headerBytes() || rt != 0 ) {
329 if (idbuf) free(idbuf);
330 Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get header for file %s",fn.getName());
334 int hdrpos=demuxer->checkStart(idbuf,rsize);
339 if (idbuf) free(idbuf);
341 if (demuxer->getId3Tag() == NULL && canPosition) {
342 //OK - look at the end
343 rt=MediaPlayer::getInstance()->getMediaBlock(2,lenInBytes-demuxer->footerBytes(),demuxer->footerBytes(),&rsize,&idbuf);
344 if (rsize < demuxer->footerBytes() || rt != 0) {
345 if (idbuf) free(idbuf);
346 Log::getInstance()->log("Audioplayer", Log::DEBUG, "unable to get footer for file %s",fn.getName());
350 hdrpos=demuxer->checkID3(idbuf,rsize);
353 Log::getInstance()->log("Audioplayer", Log::DEBUG, "no ID3 in footer for file %s",fn.getName());
359 //method called by the playing thread to handle
360 //"commands" by the frontend
361 UCHAR AudioPlayer::checkState()
364 UCHAR rstate=requestState;
366 int rseq=requestedSequence;
368 int fseq=playSequence;
370 //flag to decide which message to send
375 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u", cstate, rstate);
379 if (cstate != S_PLAY && cstate != S_FF && cstate != S_PAUSE) {
380 rstate=cstate; //ignore request
384 if (cstate != S_PAUSE) {
386 demuxer->setSkipFactor(0);
392 //if cstate==S_PAUSE fallthrough to S_PLAY
394 case S_PLAY: // to S_PLAY
396 demuxer->setSkipFactor(0);
397 if (fseq != currentPlaySequence || cstate == S_STOP || cstate == S_ERROR || cstate == S_DONE) {
398 //this is a new play request interrupting the current
399 logger->log("AudioPlayer", Log::DEBUG, "replay from start fseq=%d, startseq=%d", fseq, currentPlaySequence);
403 currentPlaySequence=fseq;
405 if (cstate != S_DONE) audio->mute();
412 if (cstate != S_DONE) {
413 //flush only if we are not coming from stream end
416 if (threadBuffer) free(threadBuffer);
418 controlFeeder(FEEDER_STOP);
420 controlFeeder(FEEDER_START);
422 audio->systemMuteOff();
423 audio->setStreamType(Audio::MP3);
429 else if (cstate == S_PAUSE){
434 else if (cstate == S_FF || S_BACK) {
442 Timers::getInstance()->setTimerD(this,1,4);
443 //inform the frontend
446 if (cstate != S_PLAY && cstate != S_PAUSE && cstate != S_FF) {
450 if (skipfactor == 0) skipfactor=2;
451 else skipfactor=skipfactor<<1;
452 if (skipfactor > 16 ) skipfactor=2;
453 demuxer->setSkipFactor(skipfactor);
455 if (cstate == S_PAUSE) {
461 if (cstate != S_PLAY && cstate != S_PAUSE) {
467 controlFeeder(FEEDER_STOP);
471 if (threadBuffer) free(threadBuffer);
473 streampos=requestedStreampos;
474 bytesWritten=streampos;
476 audio->setStreamType(Audio::MP3);
477 controlFeeder(FEEDER_START);
483 default: // to S_STOP
488 controlFeeder(FEEDER_STOP);
492 if (threadBuffer) free(threadBuffer);
494 logger->log("AudioPlayer", Log::DEBUG, "stop handled fseq: %d startseq %d completed", playSequence, currentPlaySequence);
501 if (newFile) sendFrontendMessage(NEW_SONG);
502 else if (cstate != rstate && rstate != S_DONE ) {
503 sendFrontendMessage(STATUS_CHANGE);
504 //any change after done cancels the "done" timer
505 Timers::getInstance()->cancelTimer(this,1);
507 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u completed seq=%d, nf=%s", cstate, rstate,rseq,newFile?"true":"false");
508 //we return the newly set state
511 //rstate could be different but no new request - so return cstate
518 // ----------------------------------- Feed thread
520 void AudioPlayer::waitTimed(int ms) {
524 int us=1000*(ms - 1000*sec);
527 gettimeofday(&ct,NULL);
528 nt.tv_sec=ct.tv_sec+sec;
529 nt.tv_nsec=1000*us+1000*ct.tv_usec;
531 DWORD ct=timeGetTime();
532 nt.tv_sec=ct/1000+sec;
533 nt.tv_nsec=1000*us+1000*ct*1000;
535 threadWaitForSignalTimed(&nt);
539 void AudioPlayer::threadMethod()
541 logger->log("AudioPlayer", Log::DEBUG, "player thread started");
547 UCHAR cstate=checkState();
551 if (cstate != S_PLAY && cstate != S_FF && cstate != S_BACK) {
557 if (thisWrite == thisRead) {
558 //TODO: use normal blocks...
562 int rt=MediaPlayer::getInstance()->getMediaBlock(2,streampos,BUFLEN,&thisRead,&threadBuffer);
563 if (thisRead == 0 && threadBuffer) {
567 if ((!threadBuffer || thisRead == 0 ) && rt == 0) {
569 if (retrycount > MAXTRY) rt=-1;
571 logger->log("AudioPlayer", Log::DEBUG, "no data read, retrying");
576 if (!threadBuffer || thisRead == 0 || rt != 0) {
577 //OK we count this as end of stream
578 //hmm --- we should be able to detect if the audio has gone...
579 logger->log("AudioPlayer", Log::DEBUG, "stream end");
580 setRequestedState(S_DONE);
581 MediaPlayer::getInstance()->closeMediaChannel(2);
586 //logger->log("AudioPlayer", Log::DEBUG, "read %ld bytes at pos %ld",thisRead,streampos);
593 memset(&p,sizeof(p),0);
598 audio->PrepareMediaSample(pl,0);
600 UINT rt=audio->DeliverMediaSample(threadBuffer,&bytesWritten);
601 ULONG written=thisRead;
603 written=bytesWritten;
605 ULONG written= demuxer->put(threadBuffer + thisWrite, thisRead - thisWrite);
607 bytesWritten+=written;
608 if (thisWrite < thisRead) {
610 // demuxer is full and can't take anymore
615 //logger->log("AudioPlayer", Log::DEBUG, "block written %d", thisWrite);
624 logger->log("AudioPlayer", Log::DEBUG, "finished");
625 MediaPlayer::getInstance()->closeMediaChannel(2);
630 int AudioPlayer::waitForSequence(int timeout, int seq) {
631 time_t starttime=time(NULL)+timeout;
633 logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d",seq);
635 while ((curtime=time(NULL)) < starttime) {
636 int cseq=getSequence();
641 //logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence loop");
644 logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d returns %d",seq,rt);
648 int AudioPlayer::getSequence() {
658 void AudioPlayer::threadPostStopCleanup()
662 delete(threadBuffer);
668 void AudioPlayer::call(void *) {
669 threadSignalNoLock();
672 void AudioPlayer::timercall(int ref) {
674 logger->log("AudioPlayer", Log::DEBUG, "stream end - informing frontend");
675 sendFrontendMessage(STREAM_END);
679 //--------------------------- info functions -------------------
681 char * AudioPlayer::getTitle() {
682 logger->log("AudioPlayer", Log::DEBUG, "getTitle");
684 const id3_tag * tag=demuxer->getId3Tag();
685 const char * title=NULL;
690 if (title && strlen(title) != 0) {
691 rt=new char[strlen(title)+1];
695 //let the frontend fill in something
700 char * AudioPlayer::getID3Info() {
701 logger->log("AudioPlayer", Log::DEBUG, "getID3Info");
704 const id3_tag * tag=demuxer->getId3Tag();
706 if (tag) taglen=tag->stringlen(false);
708 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
712 char bitrateType='C';
713 if (info && info->avrBitrate != info->bitRate) bitrateType='V';
716 int sr=info->sampleRate/1000;
717 SNPRINTF(rt,len-1,"%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n",tr("MpegInfo"),
718 info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100),
721 else if (tag && info){
722 int sr=info->sampleRate/1000;
723 char *tmp=new char[taglen+1];
724 SNPRINTF(rt,len-1,"%s\n"
725 "%s: %s/L%d %cBR,SR=%d.%02dkBit/s,%s\n",
726 tag->toString(tmp,taglen,false),
728 info->mpegVersion,info->mpegLayer,bitrateType,sr,(info->sampleRate/10-sr*100),
732 else if (tag && !info){
733 char *tmp=new char[taglen+1];
734 SNPRINTF(rt,len-1,"%s\n",
735 tag->toString(tmp,taglen,false));
741 logger->log("AudioPlayer", Log::DEBUG, "getID3Info returns %s",rt);
745 ULONG AudioPlayer::getCurrentTimes(){
749 rt=demuxer->getSecondsFromLen(bytesWritten);
752 rt= bytesWritten/DEFAULT_BITRATE;
759 ULONG AudioPlayer::getSonglen(){
762 const DemuxerAudio::vbrInfo * vbr=demuxer->getVBRINfo();
763 if (vbr) rt=vbr->fileSeconds;
765 if (lenInBytes != 0) {
766 rt=demuxer->getSecondsFromLen(lenInBytes);
769 rt= lenInBytes/DEFAULT_BITRATE;
777 int AudioPlayer::getCurrentBitrate(){
778 int rt=DEFAULT_BITRATE;
780 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
781 if (info) rt=info->bitRate;