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 "vaudioplayer.h"
23 #include "demuxeraudio.h"
30 AudioPlayer * AudioPlayer::instance=NULL;
32 AudioPlayer * AudioPlayer::getInstance(Boxx * parent,bool create) {
33 // Log::getInstance()->log("AudioPlayer",Log::DEBUG,"getInstance for view %p, instance=%p",parent,instance);
34 AudioPlayer *np=instance;
35 if (! np && ! create) return NULL;
37 np=new AudioPlayer(parent);
41 instance->threadLock();
42 instance->frontend=parent;
43 instance->threadUnlock();
47 AudioPlayer::AudioPlayer(Boxx *parent) : afeed(this)
50 audio = Audio::getInstance();
51 logger = Log::getInstance();
52 vdr = VDR::getInstance();
53 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorI");
60 feederState=FEEDER_STOP;
64 Video::getInstance()->turnVideoOff();
68 currentPlaySequence=-1;
70 demuxer=new DemuxerAudio();
71 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorII");
72 if (!demuxer->init(this, audio, NULL, 0, DemuxerAudio::PACKET_SIZE+200))
74 logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init");
78 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorIII");
82 logger->log("AudioPlayer", Log::DEBUG, "Audio player created");
85 AudioPlayer::~AudioPlayer()
87 if (threadBuffer) free(threadBuffer);
88 Timers::getInstance()->cancelTimer(this,1);
89 controlFeeder(FEEDER_STOP);
91 audio->setStreamType(Audio::MPEG2_PES);
97 void AudioPlayer::controlFeeder(int feederAction) {
98 logger->log("AudioPlayer",Log::DEBUG,"control feeder old=%d, new=%d",feederState,feederAction);
99 switch (feederAction) {
102 if (feederState == FEEDER_STOP)
107 if (feederState != FEEDER_STOP)
114 feederState=feederAction;
118 void AudioPlayer::run() {
119 if (playerRunnig) return;
125 void AudioPlayer::shutdown()
129 threadSignalNoLock();
130 //wait for the player thread to stop
131 logger->log("AudioPlayer",Log::DEBUG,"shutdown - warting for player thread to stop");
133 for (int loopcount=200;playerRunnig && loopcount > 0;loopcount--) {
137 logger->log("AudioPlayer",Log::ERR,"shutdown - unable to stop player within 10s");
144 bool AudioPlayer::isPlayerRunning() {
148 int AudioPlayer::setRequestedState(UCHAR rstate) {
153 rt=requestedSequence;
159 UCHAR AudioPlayer::getState() {
167 void AudioPlayer::setState(UCHAR s) {
173 //------------------- externally called functions --------------------------
174 int AudioPlayer::play(const char * fn)
176 logger->log("AudioPlayer", Log::DEBUG, "play request for %s", fn);
179 if (filename) delete filename;
180 filename=new char[strlen(fn)+1];
184 rt=requestedSequence;
187 threadSignalNoLock();
191 int AudioPlayer::stop()
193 int rt= setRequestedState(S_STOP);
194 threadSignalNoLock();
198 int AudioPlayer::pause()
200 int rt= setRequestedState(S_PAUSE);
201 threadSignalNoLock();
204 int AudioPlayer::unpause()
206 int rt= setRequestedState(S_PLAY);
207 threadSignalNoLock();
211 int AudioPlayer::fastForward(){
212 int rt=setRequestedState(S_FF);
213 threadSignalNoLock();
217 int AudioPlayer::fastBackward(){
218 int rt=setRequestedState(S_BACK);
219 threadSignalNoLock();
222 int AudioPlayer::jumpToPercent(double percent){
224 ULONG fsec=demuxer->getSecondsFromLen(lenInBytes);
225 ULONG npos=streampos;
227 fsec=(ULONG)(((double)fsec*percent)/(double)100);
228 npos=demuxer->positionFromSeconds(fsec);
229 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld from demux",npos);
232 //the demuxer cannot help us
233 npos=(ULONG)(((double)lenInBytes*percent)/(double)100);
234 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld without demux",npos);
236 if (npos > lenInBytes) npos=lenInBytes-1;
237 requestedStreampos=npos;
238 requestState=S_POSITION;
241 //no need to wait here...
245 int AudioPlayer::skipForward(int seconds) {
247 ULONG curr=demuxer->getSecondsFromLen(streampos);
248 ULONG dest=demuxer->positionFromSeconds(curr+(UINT)seconds);
250 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
251 requestedStreampos=dest;
253 requestState=S_POSITION;
258 int AudioPlayer::skipBackward(int seconds) {
260 ULONG curr=demuxer->getSecondsFromLen(streampos);
261 if (curr > (UINT)seconds) {
262 ULONG dest=demuxer->positionFromSeconds(curr-(UINT)seconds);
264 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
265 requestedStreampos=dest;
266 requestState=S_POSITION;
276 // ----------------------------------- Internal functions
279 void AudioPlayer::sendFrontendMessage(ULONG para)
281 logger->log("AudioPlayer", Log::DEBUG, "sending frontend message %ld",para);
282 Message* m = new Message();
287 m->message = Message::PLAYER_EVENT;
289 Command::getInstance()->postMessageFromOuterSpace(m);
292 void AudioPlayer::handleVDRerror(){
293 if (!vdr->isConnected())
295 logger->log("AudioPlayer", Log::ERR, "disconnect");
296 sendFrontendMessage(CONNECTION_LOST);
301 //called within the thread!
302 int AudioPlayer::openFile() {
306 fn=new char[strlen(filename)+1];
313 lenInBytes=vdr->loadImage(fn,0,0);
314 Log::getInstance()->log("Audioplayer", Log::DEBUG, "request file rt=%d file=%s",lenInBytes,fn);
316 if (lenInBytes <= 0) {
320 UCHAR *idbuf=vdr->getImageBlock(0,demuxer->headerBytes(),&rsize);
322 if (rsize < demuxer->headerBytes() || idbuf == NULL) {
323 if (idbuf) free(idbuf);
324 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "unable to get header for file %s",fn);
328 int hdrpos=demuxer->checkStart(idbuf,rsize);
333 if (idbuf) free(idbuf);
335 if (demuxer->getId3Tag() == NULL) {
336 //OK - look at the end
337 idbuf=vdr->getImageBlock(lenInBytes-demuxer->footerBytes(),demuxer->footerBytes(),&rsize);
339 if (rsize < demuxer->footerBytes() || idbuf == NULL) {
340 if (idbuf) free(idbuf);
341 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "unable to get footer for file %s",fn);
345 hdrpos=demuxer->checkID3(idbuf,rsize);
348 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "no ID3 in footer for file %s",fn);
354 //method called by the playing thread to handle
355 //"commands" by the frontend
356 UCHAR AudioPlayer::checkState()
359 UCHAR rstate=requestState;
361 int rseq=requestedSequence;
363 int fseq=playSequence;
365 //flag to decide which message to send
370 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u", cstate, rstate);
374 if (cstate != S_PLAY && cstate != S_FF) rstate=cstate; //ignore request
377 demuxer->setSkipFactor(0);
382 case S_PLAY: // to S_PLAY
384 demuxer->setSkipFactor(0);
385 if (fseq != currentPlaySequence || cstate == S_STOP || cstate == S_ERROR || cstate == S_DONE) {
386 //this is a new play request interrupting the current
387 logger->log("AudioPlayer", Log::DEBUG, "replay from start fseq=%d, startseq=%d", fseq, currentPlaySequence);
391 currentPlaySequence=fseq;
393 if (cstate != S_DONE) audio->mute();
400 if (cstate != S_DONE) {
401 //flush only if we are not coming from stream end
404 if (threadBuffer) free(threadBuffer);
406 controlFeeder(FEEDER_STOP);
408 controlFeeder(FEEDER_START);
410 audio->systemMuteOff();
411 audio->setStreamType(Audio::MP3);
417 else if (cstate == S_PAUSE){
422 else if (cstate == S_FF || S_BACK) {
430 Timers::getInstance()->setTimerD(this,1,4);
431 //inform the frontend
434 if (cstate != S_PLAY && cstate != S_PAUSE && cstate != S_FF) {
438 if (skipfactor == 0) skipfactor=2;
439 else skipfactor=skipfactor<<1;
440 if (skipfactor > 16 ) skipfactor=2;
441 demuxer->setSkipFactor(skipfactor);
443 if (cstate == S_PAUSE) {
449 if (cstate != S_PLAY && cstate != S_PAUSE) {
455 controlFeeder(FEEDER_STOP);
459 if (threadBuffer) free(threadBuffer);
461 streampos=requestedStreampos;
462 bytesWritten=streampos;
464 audio->setStreamType(Audio::MP3);
465 controlFeeder(FEEDER_START);
471 default: // to S_STOP
476 controlFeeder(FEEDER_STOP);
480 if (threadBuffer) free(threadBuffer);
482 logger->log("AudioPlayer", Log::DEBUG, "stop handled fseq: %d startseq %d completed", playSequence, currentPlaySequence);
489 if (newFile) sendFrontendMessage(NEW_SONG);
490 else if (cstate != rstate && rstate != S_DONE ) {
491 sendFrontendMessage(STATUS_CHANGE);
492 //any change after done cancels the "done" timer
493 Timers::getInstance()->cancelTimer(this,1);
495 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u completed nf=%s", cstate, rstate,newFile?"true":"false");
496 //we return the newly set state
499 //rstate could be different but no new request - so return cstate
506 // ----------------------------------- Feed thread
508 void AudioPlayer::waitTimed(int ms) {
512 int us=1000*(ms - 1000*sec);
515 gettimeofday(&ct,NULL);
516 nt.tv_sec=ct.tv_sec+sec;
517 nt.tv_nsec=1000*us+1000*ct.tv_usec;
519 DWORD ct=timeGetTime();
520 nt.tv_sec=ct/1000+sec;
521 nt.tv_nsec=1000*us+1000*ct*1000;
523 threadWaitForSignalTimed(&nt);
527 void AudioPlayer::threadMethod()
529 logger->log("AudioPlayer", Log::DEBUG, "player thread started");
534 UCHAR cstate=checkState();
538 if (cstate != S_PLAY && cstate != S_FF && cstate != S_BACK) {
544 if (thisWrite == thisRead) {
545 //TODO: use normal blocks...
548 threadBuffer = vdr->getImageBlock(streampos, BUFLEN , &thisRead);
550 if (!threadBuffer || thisRead == 0) {
551 //OK we count this as end of stream
552 //hmm --- we should be able to detect if the audio has gone...
553 logger->log("AudioPlayer", Log::DEBUG, "stream end");
554 setRequestedState(S_DONE);
557 //logger->log("AudioPlayer", Log::DEBUG, "read %ld bytes at pos %ld",thisRead,streampos);
564 memset(&p,sizeof(p),0);
569 audio->PrepareMediaSample(pl,0);
571 UINT rt=audio->DeliverMediaSample(threadBuffer,&bytesWritten);
572 ULONG written=thisRead;
574 written=bytesWritten;
576 ULONG written= demuxer->put(threadBuffer + thisWrite, thisRead - thisWrite);
578 bytesWritten+=written;
579 if (thisWrite < thisRead) {
581 // demuxer is full and can't take anymore
586 //logger->log("AudioPlayer", Log::DEBUG, "block written %d", thisWrite);
595 logger->log("AudioPlayer", Log::DEBUG, "finished");
600 int AudioPlayer::waitForSequence(int timeout, int seq) {
601 time_t starttime=time(NULL)+timeout;
603 logger->log("AudioPlayer", Log::DEBUG, "waiting for sequence %d",seq);
604 while ((curtime=time(NULL)) < starttime) {
605 int cseq=getSequence();
606 if (cseq >= seq) return cseq;
612 int AudioPlayer::getSequence() {
622 void AudioPlayer::threadPostStopCleanup()
626 delete(threadBuffer);
632 void AudioPlayer::call(void *) {
633 threadSignalNoLock();
636 void AudioPlayer::timercall(int ref) {
638 logger->log("AudioPlayer", Log::DEBUG, "stream end - informing frontend");
639 sendFrontendMessage(STREAM_END);
643 //--------------------------- info functions -------------------
645 char * AudioPlayer::getTitle() {
646 logger->log("AudioPlayer", Log::DEBUG, "getTitle");
648 const id3_tag * tag=demuxer->getId3Tag();
649 const char * title=NULL;
654 if (title && strlen(title) != 0) {
655 rt=new char[strlen(title)+1];
659 //let the frontend fill in something
664 char * AudioPlayer::getID3Info() {
665 logger->log("AudioPlayer", Log::DEBUG, "getID3Info");
668 const id3_tag * tag=demuxer->getId3Tag();
670 if (tag) taglen=tag->stringlen(false);
672 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
676 char bitrateType='C';
677 if (info && info->avrBitrate != info->bitRate) bitrateType='V';
680 SNPRINTF(rt,len-1,"%s: %s/L%d %cBR,SR=%dk,%s\n",tr("MpegInfo"),
681 info->mpegVersion,info->mpegLayer,bitrateType,info->sampleRate/1000,
684 else if (tag && info){
685 char *tmp=new char[taglen+1];
686 SNPRINTF(rt,len-1,"%s\n"
687 "%s: %s/L%d %cBR,SR=%dk,%s\n",
688 tag->toString(tmp,taglen,false),
690 info->mpegVersion,info->mpegLayer,bitrateType,info->sampleRate/1000,
694 else if (tag && !info){
695 char *tmp=new char[taglen+1];
696 SNPRINTF(rt,len-1,"%s\n",
697 tag->toString(tmp,taglen,false));
703 logger->log("AudioPlayer", Log::DEBUG, "getID3Info returns %s",rt);
707 ULONG AudioPlayer::getCurrentTimes(){
711 rt=demuxer->getSecondsFromLen(bytesWritten);
714 rt= bytesWritten/DEFAULT_BITRATE;
721 ULONG AudioPlayer::getSonglen(){
724 const DemuxerAudio::vbrInfo * vbr=demuxer->getVBRINfo();
725 if (vbr) rt=vbr->fileSeconds;
727 if (lenInBytes != 0) {
728 rt=demuxer->getSecondsFromLen(lenInBytes);
731 rt= lenInBytes/DEFAULT_BITRATE;
739 int AudioPlayer::getCurrentBitrate(){
740 int rt=DEFAULT_BITRATE;
742 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
743 if (info) rt=info->bitRate;