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;
51 PlayerRadio::~PlayerRadio()
53 if (initted) shutdown();
56 int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets)
58 if (initted) return 0;
60 pthread_mutex_init(&mutex, NULL);
62 mutex=CreateMutex(NULL,FALSE,NULL);
65 demuxer = new DemuxerVDR();
66 if (!demuxer) return 0;
68 if (!demuxer->init(this, audio, NULL, 0, 40000))
70 logger->log("PlayerRadio", Log::ERR, "Demuxer failed to init");
78 lengthBytes = tlengthBytes;
79 lengthPackets = tlengthPackets;
81 logger->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length bytes of %llu", lengthBytes);
88 UCHAR* buffer = vdr->getBlock(0, 10000, &thisRead);
91 logger->log("PlayerRadio", Log::ERR, "Failed to get start block");
96 success = demuxer->findPTS(buffer, thisRead, &startPTS);
99 logger->log("PlayerRadio", Log::ERR, "Failed to get start PTS");
107 if (!setLengthSeconds())
109 logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds");
119 bool PlayerRadio::setLengthSeconds()
124 UCHAR* buffer = vdr->getBlock(lengthBytes - 10000, 10000, &thisRead);
127 logger->log("PlayerRadio", Log::ERR, "Failed to get end block");
131 success = demuxer->findPTS(buffer, thisRead, &endPTS);
134 logger->log("PlayerRadio", Log::ERR, "Failed to get end PTS");
139 if (startPTS < endPTS)
141 lengthSeconds = (endPTS - startPTS) / 90000;
145 lengthSeconds = (startPTS - endPTS) / 90000;
151 int PlayerRadio::shutdown()
153 if (!initted) return 0;
168 void PlayerRadio::setStartBytes(ULLONG startBytes)
170 streamPos = startBytes;
173 ULONG PlayerRadio::getLengthSeconds()
175 return lengthSeconds;
178 ULONG PlayerRadio::getCurrentSeconds()
180 if (startup) return 0;
182 long long currentPTS = demuxer->getAudioPTS();
183 currentPTS -= startPTS;
184 if (currentPTS < 0) currentPTS += 8589934592ULL;
185 ULONG ret = currentPTS / 90000;
189 // ----------------------------------- Externally called events
191 void PlayerRadio::play()
193 if (!initted) return;
194 if (state == S_PLAY) return;
200 void PlayerRadio::stop()
202 if (!initted) return;
203 if (state == S_STOP) return;
205 logger->log("PlayerRadio", Log::DEBUG, "Stop called lock");
210 void PlayerRadio::pause()
212 if (!initted) return;
215 if (state == S_PAUSE_P)
221 switchState(S_PAUSE_P);
227 void PlayerRadio::jumpToPercent(int percent)
230 logger->log("PlayerRadio", Log::DEBUG, "JUMP TO %i%%", percent);
231 ULONG newPacket = percent * lengthPackets / 100;
232 switchState(S_JUMP, newPacket);
236 void PlayerRadio::skipForward(int seconds)
239 logger->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds);
240 ULONG currentSeconds = getCurrentSeconds();
241 ULONG currentPacket = demuxer->getPacketNum();
243 if (currentSeconds == 0) { unLock(); return; } // div by zero
244 if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
246 ULONG newPacket = demuxer->getPacketNum() / currentSeconds * (currentSeconds + seconds);
247 if (newPacket > lengthPackets) { switchState(S_PLAY); unLock(); }
248 else switchState(S_JUMP, newPacket);
252 void PlayerRadio::skipBackward(int seconds) // FIXME why are these signed?!
255 logger->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds);
257 ULONG currentSeconds = getCurrentSeconds();
258 ULONG currentPacket = demuxer->getPacketNum();
260 if (currentSeconds == 0) { unLock(); return; } // div by zero
261 if (currentPacket == 0) { unLock(); return; } // Current pos from demuxer is not valid
264 if ((UINT)seconds > currentSeconds)
267 newPacket = demuxer->getPacketNum() / currentSeconds * (currentSeconds - seconds);
269 switchState(S_JUMP, newPacket);
273 // ----------------------------------- Implementations called events
275 void PlayerRadio::switchState(UCHAR toState, ULONG jumpPacket)
277 if (!initted) return;
279 logger->log("PlayerRadio", Log::DEBUG, "Switch state from %u to %u", state, toState);
281 switch(state) // current state selector
283 case S_PLAY: // from S_PLAY -----------------------------------
287 case S_PLAY: // to S_PLAY
291 case S_PAUSE_P: // to S_PAUSE_P
297 case S_STOP: // to S_STOP
307 case S_JUMP: // to S_JUMP
309 restartAtPacket(jumpPacket);
314 case S_PAUSE_P: // from S_PAUSE_P -----------------------------------
318 case S_PLAY: // to S_PLAY
324 case S_PAUSE_P: // to S_PAUSE_P
328 case S_STOP: // to S_STOP
335 audio->systemMuteOff();
339 case S_JUMP: // to S_JUMP
343 restartAtPacket(jumpPacket);
348 case S_STOP: // from S_STOP -----------------------------------
352 case S_PLAY: // to S_PLAY
357 audio->systemMuteOff();
361 // FIXME use restartAtPacket here?
362 if (currentPacketNumber > lengthPackets) currentPacketNumber = 0;
363 demuxer->setPacketNum(currentPacketNumber);
371 logger->log("PlayerRadio", Log::DEBUG, "Immediate play");
375 else // do prebuffering
377 logger->log("PlayerRadio", Log::DEBUG, "Prebuffering...");
382 case S_PAUSE_P: // to S_PAUSE_P
386 case S_STOP: // to S_STOP
390 case S_JUMP: // to S_JUMP
396 // case S_JUMP cannot be selected as a start state because it auto flips to play
400 // ----------------------------------- Internal functions
402 void PlayerRadio::lock()
405 pthread_mutex_lock(&mutex);
406 logger->log("PlayerRadio", Log::DEBUG, "LOCKED");
409 WaitForSingleObject(mutex, INFINITE);
413 void PlayerRadio::unLock()
416 logger->log("PlayerRadio", Log::DEBUG, "UNLOCKING");
417 pthread_mutex_unlock(&mutex);
423 void PlayerRadio::restartAtPacket(ULONG newPacket)
429 currentPacketNumber = newPacket;
430 demuxer->setPacketNum(newPacket);
434 audio->systemMuteOff();
438 void PlayerRadio::doConnectionLost()
440 logger->log("PlayerRadio", Log::DEBUG, "Connection lost, sending message");
441 Message* m = new Message();
442 m->to = messageReceiver;
444 m->message = Message::PLAYER_EVENT;
445 m->parameter = PlayerRadio::CONNECTION_LOST;
446 messageQueue->postMessage(m);
449 // ----------------------------------- Callback
451 void PlayerRadio::call(void* caller)
453 threadSignalNoLock();
456 // ----------------------------------- Feed thread
458 void PlayerRadio::threadMethod()
462 if (state == S_PLAY) threadFeedPlay();
470 void PlayerRadio::threadFeedLive()
475 UINT preBufferTotal = 0;
487 askFor = startupBlockSize; // find audio streams sized block
489 askFor = blockSize; // normal
491 threadBuffer = vdr->getBlock(0, askFor, &thisRead);
493 if (!vdr->isConnected())
499 if (!threadBuffer) break;
503 int a_stream = demuxer->scan(threadBuffer, thisRead);
504 demuxer->setAudioStream(a_stream);
505 logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
511 preBufferTotal += thisRead;
512 if (preBufferTotal >= preBufferSize)
514 logger->log("PlayerRadio", Log::DEBUG, "Got >500K, prebuffering complete");
516 preBuffering = false;
521 // unLock(); // thread will be locked by play until here
522 // FIXME - see if this can segfault because it is starting threads out of the master mutex
528 while(writeLength < thisRead)
530 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
531 writeLength += thisWrite;
535 // demuxer is full and can't take anymore
537 threadWaitForSignal();
549 logger->log("PlayerRadio", Log::DEBUG, "Live play failed to start or interrupted");
553 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
554 m->to = messageReceiver;
556 m->message = Message::PLAYER_EVENT;
557 m->parameter = PlayerRadio::STREAM_END;
558 logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
559 messageQueue->postMessage(m);
560 logger->log("PlayerRadio", Log::DEBUG, "Message posted...");
563 void PlayerRadio::threadFeedPlay()
566 UINT thisRead, writeLength, thisWrite, askFor;
567 time_t lastRescan = time(NULL);
569 feedPosition = vdr->positionFromFrameNumber(currentPacketNumber);
570 if (!vdr->isConnected()) { doConnectionLost(); return; }
571 logger->log("PlayerRadio", Log::DEBUG, "startFeedPlay: wantedPacket %i goto %llu", currentPacketNumber, feedPosition);
582 // If we havn't rescanned for a while..
583 if ((lastRescan + 60) < time(NULL))
585 lengthBytes = vdr->rescanRecording(&lengthPackets);
586 if (!vdr->isConnected()) { doConnectionLost(); return; }
587 logger->log("PlayerRadio", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes);
588 lastRescan = time(NULL);
590 if (!setLengthSeconds())
592 logger->log("PlayerRadio", Log::ERR, "Failed to setLengthSeconds in thread");
597 if (feedPosition >= lengthBytes) break; // finished playback
601 if (startupBlockSize > lengthBytes)
602 askFor = lengthBytes; // is a very small recording!
604 askFor = startupBlockSize; // normal, but a startup sized block to detect all the audio streams
608 if ((feedPosition + blockSize) > lengthBytes) // last block of recording
609 askFor = lengthBytes - feedPosition;
614 threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead);
615 feedPosition += thisRead;
617 if (!vdr->isConnected())
623 if (!threadBuffer) break;
627 int a_stream = demuxer->scan(threadBuffer, thisRead);
628 demuxer->setAudioStream(a_stream);
629 logger->log("PlayerRadio", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
635 while(writeLength < thisRead)
637 thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
638 writeLength += thisWrite;
642 // demuxer is full and can't take anymore
644 threadWaitForSignal();
657 logger->log("PlayerRadio", Log::DEBUG, "Recording playback ends");
662 Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex
663 m->to = messageReceiver;
665 m->message = Message::PLAYER_EVENT;
666 m->parameter = PlayerRadio::STOP_PLAYBACK;
667 logger->log("PlayerRadio", Log::DEBUG, "Posting message to %p...", messageQueue);
668 messageQueue->postMessage(m);
671 void PlayerRadio::threadPostStopCleanup()