2 Copyright 2004-2006 Chris Tallon
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 "playerradio.h"
23 // ----------------------------------- Called from outside, one offs or info funcs
25 PlayerRadio::PlayerRadio(MessageQueue* tmessageQueue, void* tmessageReceiver, bool tIsRecording)
28 messageQueue = tmessageQueue;
29 messageReceiver = tmessageReceiver;
30 audio = Audio::getInstance();
31 logger = Log::getInstance();
32 vdr = VDR::getInstance();
42 isRecording = tIsRecording;
47 startupBlockSize = 20000;
48 preBufferSize = 20000;
50 Video::getInstance()->turnVideoOff();
53 PlayerRadio::~PlayerRadio()
55 if (initted) shutdown();
58 int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets)
60 if (initted) return 0;
62 pthread_mutex_init(&mutex, NULL);
64 mutex=CreateMutex(NULL,FALSE,NULL);
67 demuxer = new DemuxerVDR();
68 if (!demuxer) return 0;
70 if (!demuxer->init(this, audio, NULL, 0, 40000))
72 logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
80 lengthBytes = tlengthBytes;
81 lengthPackets = tlengthPackets;
83 logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
90 UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
93 logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
98 success = demuxer->findPTS(buffer, thisRead, &startPTS);
101 logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
109 if (!setLengthSeconds())
111 logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");
121 bool PlayerRadio::setLengthSeconds()
126 UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
129 logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
133 success = demuxer->findPTS(buffer, thisRead, &endPTS);
136 logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
141 if (startPTS < endPTS)
143 lengthSeconds = (endPTS - startPTS) / 90000;
147 lengthSeconds = (startPTS - endPTS) / 90000;
153 int PlayerRadio::shutdown()
155 if (!initted) return 0;
170 void PlayerRadio::setStartBytes(ULLONG startBytes)
172 streamPos = startBytes;
175 ULONG PlayerRadio::getLengthSeconds()
177 return lengthSeconds;
180 ULONG PlayerRadio::getCurrentSeconds()
182 if (startup) return 0;
184 long long currentPTS = demuxer->getAudioPTS();
185 currentPTS -= startPTS;
186 if (currentPTS < 0) currentPTS += 8589934592ULL;
187 ULONG ret = currentPTS / 90000;
191 // ----------------------------------- Externally called events
193 void PlayerRadio::play()
195 if (!initted) return;
196 if (state == S_PLAY) return;
202 void PlayerRadio::stop()
204 if (!initted) return;
205 if (state == S_STOP) return;
207 logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
212 void PlayerRadio::pause()
214 if (!initted) return;
217 if (state == S_PAUSE_P)
223 switchState(S_PAUSE_P);
229 void PlayerRadio::jumpToPercent(int percent)
232 logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
233 ULONG newPacket = percent * lengthPackets / 100;
234 switchState(S_JUMP, newPacket);
238 void PlayerRadio::skipForward(int seconds)
241 logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
242 ULONG currentSeconds = getCurrentSeconds();
243 ULONG currentPacket = demuxer->getPacketNum();
245 if (currentSeconds == 0) { unLock(); return; } // div by zero
246 if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
248 ULONG newPacket = demuxer->getPacketNum() / currentSeconds * (currentSeconds + seconds);
249 if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }
250 else switchState(S_JUMP, newPacket);
254 void PlayerRadio::skipBackward(int seconds) // FIXME why are these signed?!
257 logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
259 ULONG currentSeconds = getCurrentSeconds();
260 ULONG currentPacket = demuxer->getPacketNum();
262 if (currentSeconds == 0) { unLock(); return; } // div by zero
263 if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
266 if ((UINT)seconds > currentSeconds)
269 newPacket = demuxer->getPacketNum() / currentSeconds * (currentSeconds - seconds);
271 switchState(S_JUMP, newPacket);
275 // ----------------------------------- Implementations called events
277 void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)
279 if (!initted) return;
281 logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);
283 switch(state) // current state selector
285 case S_PLAY: // from S_PLAY -----------------------------------
289 case S_PLAY: // to S_PLAY
293 case S_PAUSE_P: // to S_PAUSE_P
299 case S_STOP: // to S_STOP
309 case S_JUMP: // to S_JUMP
311 restartAtPacket(jumpPacket);
316 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
320 case S_PLAY: // to S_PLAY
326 case S_PAUSE_P: // to S_PAUSE_P
330 case S_STOP: // to S_STOP
337 audio->systemMuteOff();
341 case S_JUMP: // to S_JUMP
345 restartAtPacket(jumpPacket);
350 case S_STOP: // from S_STOP -----------------------------------
354 case S_PLAY: // to S_PLAY
359 audio->systemMuteOff();
363 // FIXME use restartAtPacket here?
364 if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;
365 demuxer->setPacketNum(currentPacketNumber);
373 logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
377 else // do prebuffering
379 logger->log("PlayerRadio", Log::DEBUG, "Prebuffering...");
384 case S_PAUSE_P: // to S_PAUSE_P
388 case S_STOP: // to S_STOP
392 case S_JUMP: // to S_JUMP
398 // case S_JUMP cannot be selected as a start state because it auto flips to play
402 // ----------------------------------- Internal functions
404 void PlayerRadio::lock()
407 pthread_mutex_lock(&mutex);
408 logger->log("PlayerRadio", Log::DEBUG, "LOCKED");
411 WaitForSingleObject(mutex, INFINITE);
415 void PlayerRadio::unLock()
418 logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");
419 pthread_mutex_unlock(&mutex);
425 void PlayerRadio::restartAtPacket(ULONG newPacket)
431 currentPacketNumber = newPacket;
432 demuxer->setPacketNum(newPacket);
436 audio->systemMuteOff();
440 void PlayerRadio::doConnectionLost()
442 logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");
443 Message* m = new Message();
444 m->to = messageReceiver;
446 m->message = Message::PLAYER_EVENT;
447 m->parameter = PlayerRadio::CONNECTION_LOST;
448 messageQueue->postMessage(m);
451 // ----------------------------------- Callback
453 void PlayerRadio::call(void* caller)
455 threadSignalNoLock();
458 // ----------------------------------- Feed thread
460 void PlayerRadio::threadMethod()
464 if (state == S_PLAY) threadFeedPlay();
472 void PlayerRadio::threadFeedLive()
477 UINT preBufferTotal = 0;
489 askFor = startupBlockSize; // find audio streams sized block
491 askFor = blockSize; // normal
493 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
495 if (!vdr->isConnected())
501 if (!threadBuffer) break;
505 int a_stream = demuxer->scan(threadBuffer, thisRead);
506 demuxer->setAudioStream(a_stream);
507 logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
513 preBufferTotal += thisRead;
514 if (preBufferTotal >= preBufferSize)
516 logger->log("PlayerRadio", Log::DEBUG, "Got >500K, prebuffering complete");
518 preBuffering = false;
523 // unLock(); // thread will be locked by play until here
524 // FIXME - see if this can segfault because it is starting threads out of the master mutex
530 while(writeLength < thisRead)
532 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
533 writeLength += thisWrite;
537 // demuxer is full and can't take anymore
539 threadWaitForSignal();
551 logger->log("PlayerRadio", Log::DEBUG, "Live play failed to start or interrupted");
555 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
556 m->to = messageReceiver;
558 m->message = Message::PLAYER_EVENT;
559 m->parameter = PlayerRadio::STREAM_END;
560 logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
561 messageQueue->postMessage(m);
562 logger->log("PlayerRadio", Log::DEBUG, "Message posted...");
565 void PlayerRadio::threadFeedPlay()
568 UINT thisRead, writeLength, thisWrite, askFor;
569 time_t lastRescan = time(NULL);
571 feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);
572 if (!vdr->isConnected()) { doConnectionLost(); return; }
573 logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);
584 // If we havn't rescanned for a while..
585 if ((lastRescan + 60) < time(NULL))
587 lengthBytes = vdr->rescanRecording(&lengthPackets);
588 if (!vdr->isConnected()) { doConnectionLost(); return; }
589 logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
590 lastRescan = time(NULL);
592 if (!setLengthSeconds())
594 logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");
599 if (feedPosition >= lengthBytes) break; // finished playback
603 if (startupBlockSize > lengthBytes)
604 askFor = lengthBytes; // is a very small recording!
606 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
610 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
611 askFor = lengthBytes - feedPosition;
616 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
617 feedPosition += thisRead;
619 if (!vdr->isConnected())
625 if (!threadBuffer) break;
629 int a_stream = demuxer->scan(threadBuffer, thisRead);
630 demuxer->setAudioStream(a_stream);
631 logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
637 while(writeLength < thisRead)
639 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
640 writeLength += thisWrite;
644 // demuxer is full and can't take anymore
646 threadWaitForSignal();
659 logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");
664 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
665 m->to = messageReceiver;
667 m->message = Message::PLAYER_EVENT;
668 m->parameter = PlayerRadio::STOP_PLAYBACK;
669 logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
670 messageQueue->postMessage(m);
673 void PlayerRadio::threadPostStopCleanup()