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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "audioplayer.h"
22 #include "vaudioplayer.h"
23 #include "demuxeraudio.h"
26 AudioPlayer * AudioPlayer::instance=NULL;
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;
33 np=new AudioPlayer(parent);
37 instance->threadLock();
38 instance->frontend=parent;
39 instance->threadUnlock();
43 AudioPlayer::AudioPlayer(View *parent) : afeed(this)
46 audio = Audio::getInstance();
47 logger = Log::getInstance();
48 vdr = VDR::getInstance();
49 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorI");
56 feederState=FEEDER_STOP;
60 Video::getInstance()->turnVideoOff();
64 currentPlaySequence=-1;
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))
70 logger->log("AudioPlayer", Log::ERR, "Demuxer failed to init");
74 logger->log("AudioPlayer", Log::DEBUG, "Audio player ctorIII");
78 logger->log("AudioPlayer", Log::DEBUG, "Audio player created");
81 AudioPlayer::~AudioPlayer()
83 if (threadBuffer) free(threadBuffer);
84 Timers::getInstance()->cancelTimer(this,1);
85 controlFeeder(FEEDER_STOP);
87 audio->setStreamType(Audio::MPEG2_PES);
93 void AudioPlayer::controlFeeder(int feederAction) {
94 logger->log("AudioPlayer",Log::DEBUG,"control feeder old=%d, new=%d",feederState,feederAction);
95 switch (feederAction) {
98 if (feederState == FEEDER_STOP)
103 if (feederState != FEEDER_STOP)
110 feederState=feederAction;
114 void AudioPlayer::run() {
115 if (playerRunnig) return;
121 void AudioPlayer::shutdown()
125 threadSignalNoLock();
126 //wait for the player thread to stop
127 logger->log("AudioPlayer",Log::DEBUG,"shutdown - warting for player thread to stop");
129 for (int loopcount=200;playerRunnig && loopcount > 0;loopcount--) {
133 logger->log("AudioPlayer",Log::ERR,"shutdown - unable to stop player within 10s");
140 bool AudioPlayer::isPlayerRunning() {
144 int AudioPlayer::setRequestedState(UCHAR rstate) {
149 rt=requestedSequence;
155 UCHAR AudioPlayer::getState() {
163 void AudioPlayer::setState(UCHAR s) {
169 //------------------- externally called functions --------------------------
170 int AudioPlayer::play(const char * fn)
172 logger->log("AudioPlayer", Log::DEBUG, "play request for %s", fn);
175 if (filename) delete filename;
176 filename=new char[strlen(fn)+1];
180 rt=requestedSequence;
183 threadSignalNoLock();
187 int AudioPlayer::stop()
189 int rt= setRequestedState(S_STOP);
190 threadSignalNoLock();
194 int AudioPlayer::pause()
196 int rt= setRequestedState(S_PAUSE);
197 threadSignalNoLock();
200 int AudioPlayer::unpause()
202 int rt= setRequestedState(S_PLAY);
203 threadSignalNoLock();
207 int AudioPlayer::fastForward(){
208 int rt=setRequestedState(S_FF);
209 threadSignalNoLock();
213 int AudioPlayer::fastBackward(){
214 int rt=setRequestedState(S_BACK);
215 threadSignalNoLock();
218 int AudioPlayer::jumpToPercent(double percent){
220 ULONG fsec=demuxer->getSecondsFromLen(lenInBytes);
221 ULONG npos=streampos;
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);
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);
232 if (npos > lenInBytes) npos=lenInBytes-1;
233 requestedStreampos=npos;
234 requestState=S_POSITION;
237 //no need to wait here...
241 int AudioPlayer::skipForward(int seconds) {
243 ULONG curr=demuxer->getSecondsFromLen(streampos);
244 ULONG dest=demuxer->positionFromSeconds(curr+(UINT)seconds);
246 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
247 requestedStreampos=dest;
249 requestState=S_POSITION;
254 int AudioPlayer::skipBackward(int seconds) {
256 ULONG curr=demuxer->getSecondsFromLen(streampos);
257 if (curr > (UINT)seconds) {
258 ULONG dest=demuxer->positionFromSeconds(curr-(UINT)seconds);
260 logger->log("AudioPlayer",Log::DEBUG,"new pos %ld skip %ds",dest,seconds);
261 requestedStreampos=dest;
262 requestState=S_POSITION;
272 // ----------------------------------- Internal functions
275 void AudioPlayer::sendFrontendMessage(ULONG para)
277 logger->log("AudioPlayer", Log::DEBUG, "sending frontend message %ld",para);
278 Message* m = new Message();
283 m->message = Message::PLAYER_EVENT;
285 Command::getInstance()->postMessageFromOuterSpace(m);
288 void AudioPlayer::handleVDRerror(){
289 if (!vdr->isConnected())
291 logger->log("AudioPlayer", Log::ERR, "disconnect");
292 sendFrontendMessage(CONNECTION_LOST);
297 //called within the thread!
298 int AudioPlayer::openFile() {
302 fn=new char[strlen(filename)+1];
309 lenInBytes=vdr->loadImage(fn,0,0);
310 Log::getInstance()->log("Audioplayer", Log::DEBUG, "request file rt=%d file=%s",lenInBytes,fn);
312 if (lenInBytes <= 0) {
316 UCHAR *idbuf=vdr->getImageBlock(0,demuxer->headerBytes(),&rsize);
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);
324 int hdrpos=demuxer->checkStart(idbuf,rsize);
329 if (idbuf) free(idbuf);
331 if (demuxer->getId3Tag() == NULL) {
332 //OK - look at the end
333 idbuf=vdr->getImageBlock(lenInBytes-demuxer->footerBytes(),demuxer->footerBytes(),&rsize);
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);
341 hdrpos=demuxer->checkID3(idbuf,rsize);
344 Log::getInstance()->log("VAudioplayer", Log::DEBUG, "no ID3 in footer for file %s",fn);
350 //method called by the playing thread to handle
351 //"commands" by the frontend
352 UCHAR AudioPlayer::checkState()
355 UCHAR rstate=requestState;
357 int rseq=requestedSequence;
359 int fseq=playSequence;
361 //flag to decide which message to send
366 logger->log("AudioPlayer", Log::DEBUG, "Switch state from %u to %u", cstate, rstate);
370 if (cstate != S_PLAY && cstate != S_FF) rstate=cstate; //ignore request
373 demuxer->setSkipFactor(0);
378 case S_PLAY: // to S_PLAY
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);
387 currentPlaySequence=fseq;
389 if (cstate != S_DONE) audio->mute();
396 if (cstate != S_DONE) {
397 //flush only if we are not coming from stream end
400 if (threadBuffer) free(threadBuffer);
402 controlFeeder(FEEDER_STOP);
404 controlFeeder(FEEDER_START);
406 audio->systemMuteOff();
407 audio->setStreamType(Audio::MP3);
413 else if (cstate == S_PAUSE){
418 else if (cstate == S_FF || S_BACK) {
426 Timers::getInstance()->setTimerD(this,1,4);
427 //inform the frontend
430 if (cstate != S_PLAY && cstate != S_PAUSE && cstate != S_FF) {
434 if (skipfactor == 0) skipfactor=2;
435 else skipfactor=skipfactor<<1;
436 if (skipfactor > 16 ) skipfactor=2;
437 demuxer->setSkipFactor(skipfactor);
439 if (cstate == S_PAUSE) {
445 if (cstate != S_PLAY && cstate != S_PAUSE) {
451 controlFeeder(FEEDER_STOP);
455 if (threadBuffer) free(threadBuffer);
457 streampos=requestedStreampos;
458 bytesWritten=streampos;
460 audio->setStreamType(Audio::MP3);
461 controlFeeder(FEEDER_START);
467 default: // to S_STOP
472 controlFeeder(FEEDER_STOP);
476 if (threadBuffer) free(threadBuffer);
478 logger->log("AudioPlayer", Log::DEBUG, "stop handled fseq: %d startseq %d completed", playSequence, currentPlaySequence);
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);
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
495 //rstate could be different but no new request - so return cstate
502 // ----------------------------------- Feed thread
504 void AudioPlayer::waitTimed(int ms) {
507 gettimeofday(&ct,NULL);
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);
517 void AudioPlayer::threadMethod()
519 logger->log("AudioPlayer", Log::DEBUG, "player thread started");
524 UCHAR cstate=checkState();
528 if (cstate != S_PLAY && cstate != S_FF && cstate != S_BACK) {
534 if (thisWrite == thisRead) {
535 //TODO: use normal blocks...
538 threadBuffer = vdr->getImageBlock(streampos, BUFLEN , &thisRead);
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);
547 //logger->log("AudioPlayer", Log::DEBUG, "read %ld bytes at pos %ld",thisRead,streampos);
554 memset(&p,sizeof(p),0);
559 audio->PrepareMediaSample(pl,0);
561 UINT rt=audio->DeliverMediaSample(threadBuffer,&bytesWritten);
562 ULONG written=thisRead;
564 written=bytesWritten;
566 ULONG written= demuxer->put(threadBuffer + thisWrite, thisRead - thisWrite);
568 bytesWritten+=written;
569 if (thisWrite < thisRead) {
571 // demuxer is full and can't take anymore
576 //logger->log("AudioPlayer", Log::DEBUG, "block written %d", thisWrite);
585 logger->log("AudioPlayer", Log::DEBUG, "finished");
590 int AudioPlayer::waitForSequence(int timeout, int seq) {
591 time_t starttime=time(NULL)+timeout;
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;
602 int AudioPlayer::getSequence() {
612 void AudioPlayer::threadPostStopCleanup()
616 delete(threadBuffer);
622 void AudioPlayer::call(void *) {
623 threadSignalNoLock();
626 void AudioPlayer::timercall(int ref) {
628 logger->log("AudioPlayer", Log::DEBUG, "stream end - informing frontend");
629 sendFrontendMessage(STREAM_END);
633 //--------------------------- info functions -------------------
635 char * AudioPlayer::getTitle() {
636 logger->log("AudioPlayer", Log::DEBUG, "getTitle");
638 const id3_tag * tag=demuxer->getId3Tag();
639 const char * title=NULL;
644 if (title && strlen(title) != 0) {
645 rt=new char[strlen(title)+1];
649 //let the frontend fill in something
654 char * AudioPlayer::getID3Info() {
655 logger->log("AudioPlayer", Log::DEBUG, "getID3Info");
658 const id3_tag * tag=demuxer->getId3Tag();
660 if (tag) taglen=tag->stringlen(false);
662 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
666 char bitrateType='C';
667 if (info && info->avrBitrate != info->bitRate) bitrateType='V';
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,
674 else if (tag && info){
676 snprintf(rt,len-1,"%s\n"
677 "%s: %s/L%d %cBR,SR=%dk,%s\n",
678 tag->toString(tmp,taglen,false),
680 info->mpegVersion,info->mpegLayer,bitrateType,info->sampleRate/1000,
683 else if (tag && !info){
685 snprintf(rt,len-1,"%s\n",
686 tag->toString(tmp,taglen,false));
691 logger->log("AudioPlayer", Log::DEBUG, "getID3Info returns %s",rt);
695 ULONG AudioPlayer::getCurrentTimes(){
699 rt=demuxer->getSecondsFromLen(bytesWritten);
702 rt= bytesWritten/DEFAULT_BITRATE;
709 ULONG AudioPlayer::getSonglen(){
712 const DemuxerAudio::vbrInfo * vbr=demuxer->getVBRINfo();
713 if (vbr) rt=vbr->fileSeconds;
715 if (lenInBytes != 0) {
716 rt=demuxer->getSecondsFromLen(lenInBytes);
719 rt= lenInBytes/DEFAULT_BITRATE;
727 int AudioPlayer::getCurrentBitrate(){
728 int rt=DEFAULT_BITRATE;
730 const DemuxerAudio::mpegInfo *info=demuxer->getMpegInfo();
731 if (info) rt=info->bitRate;