void MainLoop(void) { int commandSock = 0; int controlSock = 0; int bridgeSock = 0; int prevFPPstatus = FPPstatus; int sleepms = 50000; fd_set active_fd_set; fd_set read_fd_set; struct timeval timeout; int selectResult; LogDebug(VB_GENERAL, "MainLoop()\n"); FD_ZERO (&active_fd_set); CheckExistanceOfDirectoriesAndFiles(); piFaceSetup(200); // PiFace inputs 1-8 == wiringPi 200-207 if (getFPPmode() == BRIDGE_MODE) { bridgeSock = Bridge_Initialize(); if (bridgeSock) FD_SET (bridgeSock, &active_fd_set); } else { InitMediaOutput(); } pluginCallbackManager.init(); InitializeChannelOutputs(); sequence->SendBlankingData(); InitEffects(); InitializeChannelDataMemoryMap(); commandSock = Command_Initialize(); if (commandSock) FD_SET (commandSock, &active_fd_set); #ifdef USEHTTPAPI APIServer apiServer; apiServer.Init(); #endif controlSock = InitControlSocket(); FD_SET (controlSock, &active_fd_set); SetupGPIOInput(); if (getFPPmode() & PLAYER_MODE) { if (getFPPmode() == MASTER_MODE) InitSyncMaster(); scheduler->CheckIfShouldBePlayingNow(); if (getAlwaysTransmit()) StartChannelOutputThread(); } LogInfo(VB_GENERAL, "Starting main processing loop\n"); while (runMainFPPDLoop) { timeout.tv_sec = 0; timeout.tv_usec = sleepms; read_fd_set = active_fd_set; selectResult = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &timeout); if (selectResult < 0) { if (errno == EINTR) { // We get interrupted when media players finish continue; } else { LogErr(VB_GENERAL, "Main select() failed: %s\n", strerror(errno)); runMainFPPDLoop = 0; continue; } } if (commandSock && FD_ISSET(commandSock, &read_fd_set)) CommandProc(); if (bridgeSock && FD_ISSET(bridgeSock, &read_fd_set)) Bridge_ReceiveData(); if (controlSock && FD_ISSET(controlSock, &read_fd_set)) ProcessControlPacket(); // Check to see if we need to start up the output thread. // FIXME, possibly trigger this via a fpp command to fppd if ((!ChannelOutputThreadIsRunning()) && (getFPPmode() != BRIDGE_MODE) && ((UsingMemoryMapInput()) || (channelTester->Testing()) || (getAlwaysTransmit()))) { int E131BridgingInterval = getSettingInt("E131BridgingInterval"); if (!E131BridgingInterval) E131BridgingInterval = 50; SetChannelOutputRefreshRate(1000 / E131BridgingInterval); StartChannelOutputThread(); } if (getFPPmode() & PLAYER_MODE) { if ((FPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (FPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { if (prevFPPstatus == FPP_STATUS_IDLE) { playlist->PlayListPlayingInit(); sleepms = 10000; } // Check again here in case PlayListPlayingInit // didn't find anything and put us back to IDLE if ((FPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (FPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { playlist->PlayListPlayingProcess(); } } int reactivated = 0; if (FPPstatus == FPP_STATUS_IDLE) { if ((prevFPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (prevFPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { playlist->PlayListPlayingCleanup(); if (FPPstatus != FPP_STATUS_IDLE) reactivated = 1; else sleepms = 50000; } } if (reactivated) prevFPPstatus = FPP_STATUS_IDLE; else prevFPPstatus = FPPstatus; scheduler->ScheduleProc(); } else if (getFPPmode() == REMOTE_MODE) { if(mediaOutputStatus.status == MEDIAOUTPUTSTATUS_PLAYING) { playlist->PlaylistProcessMediaData(); } } CheckGPIOInputs(); } StopChannelOutputThread(); ShutdownControlSocket(); if (getFPPmode() == BRIDGE_MODE) Bridge_Shutdown(); LogInfo(VB_GENERAL, "Main Loop complete, shutting down.\n"); }
/* * Main loop in channel output thread */ void Player::RunChannelOutputThread(void) { static long long lastStatTime = 0; long long startTime; long long sendTime; long long readTime; int onceMore = 0; struct timespec ts; int syncFrameCounter = 0; LogDebug(VB_PLAYER | VB_CHANNELOUT, "RunChannelOutputThread() starting\n"); m_outputThreadIsRunning = 1; if ((getFPPmode() == REMOTE_MODE) && (!IsEffectRunning()) && (!UsingMemoryMapInput()) && (!channelTester->Testing()) && (!getAlwaysTransmit())) { // Sleep about 2 seconds waiting for the master int loops = 0; while ((m_masterFramesPlayed < 0) && (loops < 200)) { usleep(10000); loops++; } // Stop playback if the master hasn't sent any sync packets yet if (m_masterFramesPlayed < 0) m_runOutputThread = 0; } StartOutputThreads(); while (m_runOutputThread) { startTime = GetTime(); pthread_mutex_lock(&m_sequenceLock); int runningSequences = m_sequence.size(); if ((getFPPmode() == MASTER_MODE) && (runningSequences)) { if (syncFrameCounter & 0x10) { // Send sync every 16 frames (use 16 to make the check simpler) syncFrameCounter = 1; for (int i = 0; i < m_sequence.size(); i++) SendSeqSyncPacket( m_sequence[i]->m_seqFilename, channelOutputFrame, mediaElapsedSeconds); } else { syncFrameCounter++; } } if (m_outputFrames) { if (getFPPmode() == BRIDGE_MODE) { memcpy(m_seqData, e131Data, FPPD_MAX_CHANNELS); } else { for (int i = 0; i < m_sequence.size(); i++) m_sequence[i]->OverlayNextFrame(m_seqData); } SendChannelData(m_seqData); } sendTime = GetTime(); if ((getFPPmode() != BRIDGE_MODE) && (runningSequences)) { // Close any sequences that aren't open anymore for (int i = m_sequence.size() - 1; i >= 0; i--) { if (!m_sequence[i]->SequenceFileOpen()) { Sequence *seq = m_sequence[i]; m_sequence.erase(m_sequence.begin() + i); delete seq; } } runningSequences = m_sequence.size(); // Loop through sequences pre-reading next frame of data for (int i = 0; i < m_sequence.size(); i++) { m_sequence[i]->ReadSequenceData(); } } ProcessChannelData(); readTime = GetTime(); pthread_mutex_unlock(&m_sequenceLock); if ((runningSequences) || (IsEffectRunning()) || (UsingMemoryMapInput()) || (channelTester->Testing()) || (getAlwaysTransmit()) || (getFPPmode() == BRIDGE_MODE)) { onceMore = 1; if (startTime > (lastStatTime + 1000000)) { int sleepTime = m_lightDelay - (GetTime() - startTime); if (sleepTime < 0) sleepTime = 0; lastStatTime = startTime; LogDebug(VB_PLAYER | VB_CHANNELOUT, "Output Thread: Loop: %dus, Send: %lldus, Read: %lldus, Sleep: %dus, FrameNum: %ld\n", m_lightDelay, sendTime - startTime, readTime - sendTime, sleepTime, channelOutputFrame); } } else { m_lightDelay = m_defaultLightDelay; if (onceMore) onceMore = 0; else m_runOutputThread = 0; } // Calculate how long we need to nanosleep() ts.tv_sec = 0; ts.tv_nsec = (m_lightDelay - (GetTime() - startTime)) * 1000; nanosleep(&ts, NULL); } StopOutputThreads(); m_outputThreadIsRunning = 0; LogDebug(VB_PLAYER | VB_CHANNELOUT, "RunChannelOutputThread() completed\n"); pthread_exit(NULL); }