/* * Trigger an event */ int TriggerEventByID(char *id) { LogDebug(VB_EVENT, "TriggerEventByID(%s)\n", id); if (getFPPmode() == MASTER_MODE) SendEventPacket(id); FPPevent *event = LoadEvent(id); if (!event) { LogWarn(VB_EVENT, "Unable to load event %s\n", id); return 0; } if (event->effect) StartEffect(event->effect, event->startChannel); if (event->script) RunEventScript(event); FreeEvent(event); return 1; }
int omxplayer_StartPlaying(const char *filename) { char fullVideoPath[2048]; LogDebug(VB_MEDIAOUT, "omxplayer_StartPlaying(%s)\n", filename); bzero(&mediaOutputStatus, sizeof(mediaOutputStatus)); if (snprintf(fullVideoPath, 2048, "%s/%s", getVideoDirectory(), filename) >= 2048) { LogErr(VB_MEDIAOUT, "Unable to play %s, full path name too long\n", filename); return 0; } if (getFPPmode() == REMOTE_MODE) CheckForHostSpecificFile(getSetting("HostName"), fullVideoPath); if (!FileExists(fullVideoPath)) { LogErr(VB_MEDIAOUT, "%s does not exist!\n", fullVideoPath); return 0; } // Create Pipes to/from omxplayer pid_t omxplayerPID = forkpty(&pipeFromOMX[0], 0, 0, 0); if (omxplayerPID == 0) // omxplayer process { ShutdownControlSocket(); seteuid(1000); // 'pi' user execl("/opt/fpp/scripts/omxplayer", "/opt/fpp/scripts/omxplayer", fullVideoPath, NULL); LogErr(VB_MEDIAOUT, "omxplayer_StartPlaying(), ERROR, we shouldn't " "be here, this means that execl() failed\n"); exit(EXIT_FAILURE); } else // Parent process { mediaOutput->childPID = omxplayerPID; } // Clear active file descriptor sets FD_ZERO (&omx_active_fd_set); // Set description for reading from omxplayer FD_SET (pipeFromOMX[0], &omx_active_fd_set); mediaOutputStatus.status = MEDIAOUTPUTSTATUS_PLAYING; omxVolumeShift = omxplayer_GetVolumeShift(getVolume()); return 1; }
void Sequence::SendBlankingData(void) { LogDebug(VB_SEQUENCE, "SendBlankingData()\n"); usleep(100000); if (getFPPmode() == MASTER_MODE) SendBlankingDataPacket(); BlankSequenceData(); ProcessSequenceData(0); SendSequenceData(); }
void Player::SendBlankingData(void) { usleep(100000); // FIXME, figure out a way to not need this delay // possibly by just starting thread up once more bzero(m_seqData, FPPD_MAX_CHANNELS); if (getFPPmode() == MASTER_MODE) SendBlankingDataPacket(); ProcessChannelData(); SendChannelData(m_seqData); }
void Sequence::CloseSequenceFile(void) { LogDebug(VB_SEQUENCE, "CloseSequenceFile() %s\n", m_seqFilename); if (getFPPmode() == MASTER_MODE) SendSeqSyncStopPacket(m_seqFilename); pthread_mutex_lock(&m_sequenceLock); if (m_seqFile) { fclose(m_seqFile); m_seqFile = NULL; } m_seqFilename[0] = '\0'; m_seqPaused = 0; if ((getFPPmode() != REMOTE_MODE) && (!IsEffectRunning()) && (FPPstatus != FPP_STATUS_PLAYLIST_PLAYING)) SendBlankingData(); pthread_mutex_unlock(&m_sequenceLock); }
/* * Initialize effects constructs */ int InitEffects(void) { std::string localFilename = getEffectDirectory(); localFilename += "/background.eseq"; if ((getFPPmode() == REMOTE_MODE) && CheckForHostSpecificFile(getSetting("HostName"), localFilename)) { localFilename = "background_"; localFilename += getSetting("HostName"); LogInfo(VB_EFFECT, "Automatically starting background effect " "sequence %s\n", localFilename.c_str()); StartEffect(localFilename.c_str(), 0, 1); } else if (FileExists(localFilename)) { LogInfo(VB_EFFECT, "Automatically starting background effect sequence " "background.eseq\n"); StartEffect("background", 0, 1); } pauseBackgroundEffects = getSettingInt("pauseBackgroundEffects"); return 1; }
/* * Calculate the new sync offset based on the current position reported * by the media player. */ void Player::CalculateNewChannelOutputDelay(float mediaPosition) { static float nextSyncCheck = 0.5; if (getFPPmode() == REMOTE_MODE) return; if ((mediaPosition <= nextSyncCheck) && (nextSyncCheck < (mediaPosition + 2.0))) return; float offsetMediaPosition = mediaPosition - m_mediaOffset; int expectedFramesSent = (int)(offsetMediaPosition * m_refreshRate); mediaElapsedSeconds = mediaPosition; LogDebug(VB_PLAYER | VB_CHANNELOUT, "Media Position: %.2f, Offset: %.3f, Frames Sent: %d, Expected: %d, Diff: %d\n", mediaPosition, m_mediaOffset, channelOutputFrame, expectedFramesSent, channelOutputFrame - expectedFramesSent); CalculateNewChannelOutputDelayForFrame(expectedFramesSent); }
void ogg123Output::ParseTimes() { static int lastRemoteSync = 0; int result; int secs; int mins; int subSecs; char tmp[3]; tmp[2]= '\0'; // Mins tmp[0] = m_ogg123_strTime[1]; tmp[1] = m_ogg123_strTime[2]; sscanf(tmp,"%d",&mins); // Secs tmp[0] = m_ogg123_strTime[4]; tmp[1] = m_ogg123_strTime[5]; sscanf(tmp,"%d",&secs); m_mediaOutputStatus->secondsElapsed = 60*mins + secs; // Subsecs tmp[0] = m_ogg123_strTime[7]; tmp[1] = m_ogg123_strTime[8]; sscanf(tmp,"%d",&m_mediaOutputStatus->subSecondsElapsed); // Mins Remaining tmp[0] = m_ogg123_strTime[11]; tmp[1] = m_ogg123_strTime[12]; sscanf(tmp,"%d",&mins); // Secs Remaining tmp[0] = m_ogg123_strTime[14]; tmp[1] = m_ogg123_strTime[15]; sscanf(tmp,"%d",&secs); m_mediaOutputStatus->secondsRemaining = 60*mins + secs; // Subsecs remaining tmp[0] = m_ogg123_strTime[17]; tmp[1] = m_ogg123_strTime[18]; sscanf(tmp,"%d",&m_mediaOutputStatus->subSecondsRemaining); // Total Mins tmp[0] = m_ogg123_strTime[24]; tmp[1] = m_ogg123_strTime[25]; sscanf(tmp,"%d",&m_mediaOutputStatus->minutesTotal); // Total Secs tmp[0] = m_ogg123_strTime[27]; tmp[1] = m_ogg123_strTime[28]; sscanf(tmp,"%d",&m_mediaOutputStatus->secondsTotal); m_mediaOutputStatus->mediaSeconds = (float)((float)m_mediaOutputStatus->secondsElapsed + ((float)m_mediaOutputStatus->subSecondsElapsed/(float)100)); if (getFPPmode() == MASTER_MODE) { if ((m_mediaOutputStatus->secondsElapsed > 0) && (lastRemoteSync != m_mediaOutputStatus->secondsElapsed)) { SendMediaSyncPacket(m_mediaFilename.c_str(), 0, m_mediaOutputStatus->mediaSeconds); lastRemoteSync = m_mediaOutputStatus->secondsElapsed; } } if ((sequence->IsSequenceRunning()) && (m_mediaOutputStatus->secondsElapsed > 0)) { LogExcess(VB_MEDIAOUT, "Elapsed: %.2d.%.2d Remaining: %.2d Total %.2d:%.2d.\n", m_mediaOutputStatus->secondsElapsed, m_mediaOutputStatus->subSecondsElapsed, m_mediaOutputStatus->secondsRemaining, m_mediaOutputStatus->minutesTotal, m_mediaOutputStatus->secondsTotal); CalculateNewChannelOutputDelay(m_mediaOutputStatus->mediaSeconds); } }
void omxplayer_ProcessPlayerData(int bytesRead) { int ticks = 0; static int lastSyncCheck = 0; static int lastRemoteSync = 0; int mins = 0; int secs = 0; int subsecs = 0; int totalCentiSecs = 0; char *ptr = NULL; if ((mediaOutputStatus.secondsTotal == 0) && (mediaOutputStatus.minutesTotal == 0) && (ptr = strstr(omxBuffer, "Duration: "))) { // Sample line format: // (whitespace)Duration: 00:00:37.91, start: 0.000000, bitrate: 2569 kb/s char *ptr2 = strchr(ptr, ','); if (ptr2) { *ptr2 = '\0'; ptr = ptr + 10; int hours = strtol(ptr, NULL, 10); ptr += 3; mediaOutputStatus.minutesTotal = strtol(ptr, NULL, 10) + (hours * 60); ptr += 3; mediaOutputStatus.secondsTotal = strtol(ptr, NULL, 10); } } // Data is line buffered so all stats lines should start with "M: " if ((!strncmp(omxBuffer, "M:", 2)) && (bytesRead > 20)) { errno = 0; ticks = strtol(&omxBuffer[2], NULL, 10); if (errno) { LogErr(VB_MEDIAOUT, "Error parsing omxplayer output.\n"); return; } } else { return; } totalCentiSecs = ticks / 10000; mins = totalCentiSecs / 6000; secs = totalCentiSecs % 6000 / 100; subsecs = totalCentiSecs % 100; mediaOutputStatus.secondsElapsed = 60 * mins + secs; mediaOutputStatus.subSecondsElapsed = subsecs; mediaOutputStatus.secondsRemaining = (mediaOutputStatus.minutesTotal * 60) + mediaOutputStatus.secondsTotal - mediaOutputStatus.secondsElapsed; // FIXME, can we get this? // mediaOutputStatus.subSecondsRemaining = subsecs; mediaOutputStatus.mediaSeconds = (float)((float)mediaOutputStatus.secondsElapsed + ((float)mediaOutputStatus.subSecondsElapsed/(float)100)); if (getFPPmode() == MASTER_MODE) { if ((mediaOutputStatus.secondsElapsed > 0) && (lastRemoteSync != mediaOutputStatus.secondsElapsed)) { SendMediaSyncPacket(mediaOutput->filename, 0, mediaOutputStatus.mediaSeconds); lastRemoteSync = mediaOutputStatus.secondsElapsed; } } if ((sequence->IsSequenceRunning()) && (mediaOutputStatus.secondsElapsed > 0) && (lastSyncCheck != mediaOutputStatus.secondsElapsed)) { LogDebug(VB_MEDIAOUT, "Elapsed: %.2d.%.2d Remaining: %.2d Total %.2d:%.2d.\n", mediaOutputStatus.secondsElapsed, mediaOutputStatus.subSecondsElapsed, mediaOutputStatus.secondsRemaining, mediaOutputStatus.minutesTotal, mediaOutputStatus.secondsTotal); CalculateNewChannelOutputDelay(mediaOutputStatus.mediaSeconds); lastSyncCheck = mediaOutputStatus.secondsElapsed; } }
void ProcessCommand(char *command) { char *s; char *s2; char *s3; char *s4; char *response2 = NULL; int i; char NextPlaylist[128] = "No playlist scheduled."; char NextScheduleStartText[64] = ""; char CommandStr[64]; LogExcess(VB_COMMAND, "CMD: %s\n", command); s = strtok(command,","); strcpy(CommandStr, s); if (!strcmp(CommandStr, "s")) { Json::Value info = player->GetCurrentPlaylistInfo(); char currentEntryType = 'u'; // Unknown const char *currentSequenceName = NULL; const char *currentMediaName = NULL; if (info["currentEntry"].isMember("sequenceName")) currentSequenceName = info["currentEntry"]["sequenceName"].asString().c_str(); if (info["currentEntry"].isMember("mediaFilename")) currentMediaName = info["currentEntry"]["mediaFilename"].asString().c_str(); if (info["currentEntry"].isMember("type")) { std::string type = info["currentEntry"]["type"].asString(); if (type == "both") currentEntryType = 'b'; else if (type == "event") currentEntryType = 'e'; else if (type == "media") currentEntryType = 'm'; else if (type == "pause") currentEntryType = 'p'; else if (type == "plugin") currentEntryType = 'P'; else if (type == "sequence") currentEntryType = 's'; } player->GetNextScheduleStartText(NextScheduleStartText); player->GetNextPlaylistText(NextPlaylist); if(FPPstatus==FPP_STATUS_IDLE) { if (getFPPmode() == REMOTE_MODE) { sprintf(response,"%d,%d,%d,%s,%s,%d,%d\n", getFPPmode(), 0, getVolume(), currentSequenceName, currentMediaName, player->GetPlaybackSecondsElapsed(), player->GetPlaybackSecondsRemaining()); } else { sprintf(response,"%d,%d,%d,%s,%s\n", getFPPmode(),0,getVolume(), NextPlaylist,NextScheduleStartText); } } else { sprintf(response,"%d,%d,%d,%s,%c,%s,%s,%d,%d,%d,%d,%s,%s,%d\n", getFPPmode(),FPPstatus,getVolume(), info["name"].asString().c_str(), currentEntryType, currentSequenceName, currentMediaName, info["currentPosition"].asInt() + 1, info["size"].asInt(), info["currentEntry"]["secondsElapsed"].asInt(), info["currentEntry"]["secondsRemaining"].asInt(), NextPlaylist,NextScheduleStartText, info["repeat"].asInt()); } } else if ((!strcmp(CommandStr, "p")) || (!strcmp(CommandStr, "P"))) { if(FPPstatus==FPP_STATUS_PLAYLIST_PLAYING || FPPstatus==FPP_STATUS_STOPPING_GRACEFULLY) { player->PlaylistStopNow(); sleep(1); } s = strtok(NULL,","); if (s) { std::string playlistName(s); int repeat = !strcmp(CommandStr, "p") ? 1 : 0; int position = 0; s = strtok(NULL,","); if (s) position = atoi(s); if (player->PlaylistStart(playlistName, position, repeat)) { sprintf(response,"%d,%d,Playlist Started,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Playlist Start Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else { sprintf(response,"%d,%d,Unknown Playlist,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "S")) { if(FPPstatus==FPP_STATUS_PLAYLIST_PLAYING) { player->PlaylistStopGracefully(); player->ReLoadCurrentScheduleInfo(); sprintf(response,"%d,%d,Playlist Stopping Gracefully,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,Not playing,,,,,,,,,,,\n",COMMAND_FAILED); } } else if (!strcmp(CommandStr, "d")) { if(FPPstatus==FPP_STATUS_PLAYLIST_PLAYING || FPPstatus==FPP_STATUS_STOPPING_GRACEFULLY) { player->PlaylistStopNow(); player->ReLoadCurrentScheduleInfo(); sprintf(response,"%d,%d,Playlist Stopping Now,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Not playing,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "R")) { if(FPPstatus==FPP_STATUS_IDLE) { player->ReLoadCurrentScheduleInfo(); } player->ReLoadNextScheduleInfo(); sprintf(response,"%d,%d,Reloading Schedule,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if (!strcmp(CommandStr, "v")) { s = strtok(NULL,","); if (s) { setVolume(atoi(s)); sprintf(response,"%d,%d,Setting Volume,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Invalid Volume,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "w")) { LogInfo(VB_SETTING, "Sending Falcon hardware config\n"); if (!DetectFalconHardware(1)) SendFPDConfig(); } else if (!strcmp(CommandStr, "r")) { WriteBytesReceivedFile(); sprintf(response,"true\n"); } else if (!strcmp(CommandStr, "q")) { // Quit/Shutdown fppd ShutdownFPPD(); } else if (!strcmp(CommandStr, "e")) { // Start an Effect s = strtok(NULL,","); s2 = strtok(NULL,","); s3 = strtok(NULL,","); if (s && s2) { i = StartEffect(s, atoi(s2), atoi(s3)); if (i >= 0) sprintf(response,"%d,%d,Starting Effect,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Invalid Effect,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else sprintf(response,"%d,%d,Invalid Effect,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "t")) { // Trigger an event s = strtok(NULL,","); pluginCallbackManager.eventCallback(s, "command"); i = TriggerEventByID(s); if (i >= 0) sprintf(response,"%d,%d,Event Triggered,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Event Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "GetTestMode")) { strcpy(response, channelTester->GetConfig().c_str()); strcat(response, "\n"); } else if (!strcmp(CommandStr, "SetTestMode")) { if (channelTester->SetupTest(std::string(s + strlen(s) + 1))) { sprintf(response, "0,%d,Test Mode Activated,,,,,,,,,\n", COMMAND_SUCCESS); } else { sprintf(response, "0,%d,Test Mode Deactivated,,,,,,,,,\n", COMMAND_SUCCESS); } } else if (!strcmp(CommandStr, "LogLevel")) { s = strtok(NULL,","); if (SetLogLevel(s)) { sprintf(response,"%d,%d,Log Level Updated,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_SUCCESS,logLevel,logMask); } else { sprintf(response,"%d,%d,Error Updating Log Level,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_FAILED,logLevel,logMask); } } else if (!strcmp(CommandStr, "LogMask")) { s = strtok(NULL,","); if ((s && SetLogMask(s)) || SetLogMask("")) { sprintf(response,"%d,%d,Log Mask Updated,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_SUCCESS,logLevel,logMask); } else { sprintf(response,"%d,%d,Error Updating Log Mask,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_FAILED,logLevel,logMask); } } else if (!strcmp(CommandStr, "SetSetting")) { char name[128]; s = strtok(NULL,","); if (s) { strcpy(name, s); s = strtok(NULL,","); if (s) parseSetting(name, s); } } else if (!strcmp(CommandStr, "StopAllEffects")) { StopAllEffects(); sprintf(response,"%d,%d,All Effects Stopped,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if (!strcmp(CommandStr, "StopEffectByName")) { s = strtok(NULL,","); if (strlen(s)) { if (StopEffect(s)) sprintf(response,"%d,%d,Stopping Effect,%s,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,s); else sprintf(response,"%d,%d,Stop Effect Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "StopEffect")) { s = strtok(NULL,","); i = atoi(s); if (StopEffect(i)) sprintf(response,"%d,%d,Stopping Effect,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Stop Effect Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "GetRunningEffects")) { sprintf(response,"%d,%d,Running Effects",getFPPmode(),COMMAND_SUCCESS); GetRunningEffects(response, &response2); } else if (!strcmp(CommandStr, "ReloadChannelRemapData")) { if ((FPPstatus==FPP_STATUS_IDLE) && (LoadChannelRemapData())) { sprintf(response,"%d,%d,Channel Remap Data Reloaded,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Failed to reload Channel Remap Data,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "GetFPPDUptime")) { sprintf(response,"%d,%d,FPPD Uptime,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS, time(NULL) - fppdStartTime); } else if (!strcmp(CommandStr, "StartSequence")) { s = strtok(NULL,","); s2 = strtok(NULL,","); if (s && s2) { i = atoi(s2); player->StartSequence(s, 0, i); sprintf(response,"%d,%d,Sequence Started,,,,,,,,,,,,\n", getFPPmode(), COMMAND_SUCCESS); } else { LogErr(VB_COMMAND, "Tried to start a sequence when a playlist or " "sequence is already running\n"); sprintf(response,"%d,%d,Sequence Failed,,,,,,,,,,,,\n", getFPPmode(), COMMAND_FAILED); } } else if (!strcmp(CommandStr, "StopSequence")) { s = strtok(NULL,","); if (s) { player->StopSequence(s); sprintf(response,"%d,%d,Sequence Stopped,,,,,,,,,,,,\n", getFPPmode(), COMMAND_SUCCESS); } else { LogDebug(VB_COMMAND, "Invalid command: %s\n", command); sprintf(response,"%d,%d,Sequence Name Missing,,,,,,,,,,,,\n", getFPPmode(), COMMAND_FAILED); } } else if (!strcmp(CommandStr, "ToggleSequencePause")) { if ((player->SequencesRunning()) && ((FPPstatus == FPP_STATUS_IDLE) || (FPPstatus != FPP_STATUS_IDLE))) { player->ToggleSequencePause(); } } else if (!strcmp(CommandStr, "SingleStepSequence")) { if ((player->SequencesRunning()) && (player->SequencesArePaused()) && ((FPPstatus == FPP_STATUS_IDLE) || ((FPPstatus != FPP_STATUS_IDLE)))) { player->SingleStepSequences(); } } else if (!strcmp(CommandStr, "SingleStepSequenceBack")) { if ((player->SequencesRunning()) && (player->SequencesArePaused()) && ((FPPstatus == FPP_STATUS_IDLE) || ((FPPstatus != FPP_STATUS_IDLE)))) { player->SingleStepSequencesBack(); } } else if (!strcmp(CommandStr, "NextPlaylistItem")) { switch (FPPstatus) { case FPP_STATUS_IDLE: sprintf(response,"%d,%d,No playlist running\n",getFPPmode(),COMMAND_FAILED); break; case FPP_STATUS_PLAYLIST_PLAYING: sprintf(response,"%d,%d,Skipping to next playlist item\n",getFPPmode(),COMMAND_SUCCESS); player->NextPlaylistItem(); break; case FPP_STATUS_STOPPING_GRACEFULLY: sprintf(response,"%d,%d,Playlist is stopping gracefully\n",getFPPmode(),COMMAND_FAILED); break; } } else if (!strcmp(CommandStr, "PrevPlaylistItem")) { switch (FPPstatus) { case FPP_STATUS_IDLE: sprintf(response,"%d,%d,No playlist running\n",getFPPmode(),COMMAND_FAILED); break; case FPP_STATUS_PLAYLIST_PLAYING: sprintf(response,"%d,%d,Skipping to previous playlist item\n",getFPPmode(),COMMAND_SUCCESS); player->PrevPlaylistItem(); break; case FPP_STATUS_STOPPING_GRACEFULLY: sprintf(response,"%d,%d,Playlist is stopping gracefully\n",getFPPmode(),COMMAND_FAILED); break; } } else if (!strcmp(CommandStr, "SetupExtGPIO")) { // Configure the given GPIO to the given mode s = strtok(NULL,","); s2 = strtok(NULL,","); if (s && s2) { if (!SetupExtGPIO(atoi(s), s2)) { sprintf(response, "%d,%d,Configuring GPIO,%d,%s,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,atoi(s),s2); } else { sprintf(response, "%d,%d,Configuring GPIO,%d,%s,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED,atoi(s),s2); } } } else if (!strcmp(CommandStr, "ExtGPIO")) { s = strtok(NULL,","); s2 = strtok(NULL,","); s3 = strtok(NULL,","); if (s && s2 && s3) { i = ExtGPIO(atoi(s), s2, atoi(s3)); if (i >= 0) { sprintf(response, "%d,%d,Setting GPIO,%d,%s,%d,%d,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,atoi(s),s2,atoi(s3),i); } else { sprintf(response, "%d,%d,Setting GPIO,%d,%s,%d,,,,,,,,\n",getFPPmode(),COMMAND_FAILED,atoi(s),s2,atoi(s3)); } } } else { sprintf(response,"Invalid command: '%s'\n", CommandStr); } if (response2) { bytes_sent = sendto(socket_fd, response2, strlen(response2), 0, (struct sockaddr *) &(client_address), sizeof(struct sockaddr_un)); LogDebug(VB_COMMAND, "%s %s", CommandStr, response2); free(response2); response2 = NULL; } else { bytes_sent = sendto(socket_fd, response, strlen(response), 0, (struct sockaddr *) &(client_address), sizeof(struct sockaddr_un)); LogDebug(VB_COMMAND, "%s %s", CommandStr, response); } }
int main(int argc, char *argv[]) { initSettings(argc, argv); initMediaDetails(); if (DirectoryExists("/home/fpp")) loadSettings("/home/fpp/media/settings"); else loadSettings("/home/pi/media/settings"); wiringPiSetupGpio(); // would prefer wiringPiSetupSys(); // Parse our arguments first, override any defaults parseArguments(argc, argv); if (loggingToFile()) logVersionInfo(); printVersionInfo(); // Start functioning if (getDaemonize()) CreateDaemon(); scheduler = new Scheduler(); playlist = new Playlist(); sequence = new Sequence(); channelTester = new ChannelTester(); #ifndef NOROOT struct sched_param param; param.sched_priority = 99; if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) { perror("sched_setscheduler"); exit(EXIT_FAILURE); } #endif MainLoop(); if (getFPPmode() != BRIDGE_MODE) { CleanupMediaOutput(); } if (getFPPmode() & PLAYER_MODE) { if (getFPPmode() == MASTER_MODE) ShutdownSync(); CloseChannelDataMemoryMap(); CloseEffects(); } CloseChannelOutputs(); delete channelTester; delete scheduler; delete playlist; delete sequence; return 0; }
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"); }
int Sequence::OpenSequenceFile(const char *filename, int startSeconds) { LogDebug(VB_SEQUENCE, "OpenSequenceFile(%s, %d)\n", filename, startSeconds); if (!filename || !filename[0]) { LogErr(VB_SEQUENCE, "Empty Sequence Filename!\n", filename); return 0; } size_t bytesRead = 0; m_seqFileSize = 0; if (IsSequenceRunning()) CloseSequenceFile(); m_seqStarting = 1; m_seqPaused = 0; m_seqDuration = 0; m_seqSecondsElapsed = 0; m_seqSecondsRemaining = 0; strcpy(m_seqFilename, filename); char tmpFilename[2048]; unsigned char tmpData[2048]; strcpy(tmpFilename,(const char *)getSequenceDirectory()); strcat(tmpFilename,"/"); strcat(tmpFilename, filename); if (getFPPmode() == REMOTE_MODE) CheckForHostSpecificFile(getSetting("HostName"), tmpFilename); if (!FileExists(tmpFilename)) { LogErr(VB_SEQUENCE, "Sequence file %s does not exist\n", tmpFilename); m_seqStarting = 0; return 0; } m_seqFile = fopen((const char *)tmpFilename, "r"); if (m_seqFile == NULL) { LogErr(VB_SEQUENCE, "Error opening sequence file: %s. fopen returned NULL\n", tmpFilename); m_seqStarting = 0; return 0; } if (getFPPmode() == MASTER_MODE) { SendSeqSyncStartPacket(filename); // Give the remotes a head start spining up so they are ready usleep(100000); } /////////////////////////////////////////////////////////////////////// // Check 4-byte File format identifier char seqFormatID[5]; strcpy(seqFormatID, " "); bytesRead = fread(seqFormatID, 1, 4, m_seqFile); seqFormatID[4] = 0; if ((bytesRead != 4) || (strcmp(seqFormatID, "PSEQ") && strcmp(seqFormatID, "FSEQ"))) { LogErr(VB_SEQUENCE, "Error opening sequence file: %s. Incorrect File Format header: '%s', bytesRead: %d\n", filename, seqFormatID, bytesRead); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } /////////////////////////////////////////////////////////////////////// // Get Channel Data Offset bytesRead = fread(tmpData, 1, 2, m_seqFile); if (bytesRead != 2) { LogErr(VB_SEQUENCE, "Sequence file %s too short, unable to read channel data offset value\n", filename); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } m_seqChanDataOffset = tmpData[0] + (tmpData[1] << 8); /////////////////////////////////////////////////////////////////////// // Now that we know the header size, read the whole header in one shot fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, m_seqChanDataOffset, m_seqFile); if (bytesRead != m_seqChanDataOffset) { LogErr(VB_SEQUENCE, "Sequence file %s too short, unable to read fixed header size value\n", filename); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } m_seqVersionMinor = tmpData[6]; m_seqVersionMajor = tmpData[7]; m_seqVersion = (m_seqVersionMajor * 256) + m_seqVersionMinor; m_seqFixedHeaderSize = (tmpData[8]) + (tmpData[9] << 8); m_seqStepSize = (tmpData[10]) + (tmpData[11] << 8) + (tmpData[12] << 16) + (tmpData[13] << 24); m_seqNumPeriods = (tmpData[14]) + (tmpData[15] << 8) + (tmpData[16] << 16) + (tmpData[17] << 24); m_seqStepTime = (tmpData[18]) + (tmpData[19] << 8); m_seqNumUniverses = (tmpData[20]) + (tmpData[21] << 8); m_seqUniverseSize = (tmpData[22]) + (tmpData[23] << 8); m_seqGamma = tmpData[24]; m_seqColorEncoding = tmpData[25]; // End of v1.0 fields if (m_seqVersion > 0x0100) { } m_seqRefreshRate = 1000 / m_seqStepTime; fseek(m_seqFile, 0L, SEEK_END); m_seqFileSize = ftell(m_seqFile); m_seqDuration = (int)((float)(m_seqFileSize - m_seqChanDataOffset) / ((float)m_seqStepSize * (float)m_seqRefreshRate)); m_seqSecondsRemaining = m_seqDuration; fseek(m_seqFile, m_seqChanDataOffset, SEEK_SET); m_seqFilePosition = m_seqChanDataOffset; LogDebug(VB_SEQUENCE, "Sequence File Information\n"); LogDebug(VB_SEQUENCE, "seqFilename : %s\n", m_seqFilename); LogDebug(VB_SEQUENCE, "seqVersion : %d.%d\n", m_seqVersionMajor, m_seqVersionMinor); LogDebug(VB_SEQUENCE, "seqFormatID : %s\n", seqFormatID); LogDebug(VB_SEQUENCE, "seqChanDataOffset : %d\n", m_seqChanDataOffset); LogDebug(VB_SEQUENCE, "seqFixedHeaderSize : %d\n", m_seqFixedHeaderSize); LogDebug(VB_SEQUENCE, "seqStepSize : %d\n", m_seqStepSize); LogDebug(VB_SEQUENCE, "seqNumPeriods : %d\n", m_seqNumPeriods); LogDebug(VB_SEQUENCE, "seqStepTime : %dms\n", m_seqStepTime); LogDebug(VB_SEQUENCE, "seqNumUniverses : %d *\n", m_seqNumUniverses); LogDebug(VB_SEQUENCE, "seqUniverseSize : %d *\n", m_seqUniverseSize); LogDebug(VB_SEQUENCE, "seqGamma : %d *\n", m_seqGamma); LogDebug(VB_SEQUENCE, "seqColorEncoding : %d *\n", m_seqColorEncoding); LogDebug(VB_SEQUENCE, "seqRefreshRate : %d\n", m_seqRefreshRate); LogDebug(VB_SEQUENCE, "seqFileSize : %lu\n", m_seqFileSize); LogDebug(VB_SEQUENCE, "seqDuration : %d\n", m_seqDuration); LogDebug(VB_SEQUENCE, "'*' denotes field is currently ignored by FPP\n"); m_seqPaused = 0; m_seqSingleStep = 0; m_seqSingleStepBack = 0; int frameNumber = 0; if (startSeconds) { int frameNumber = startSeconds * m_seqRefreshRate; int newPos = m_seqChanDataOffset + (frameNumber * m_seqStepSize); LogDebug(VB_SEQUENCE, "Seeking to byte %d in %s\n", newPos, m_seqFilename); fseek(m_seqFile, newPos, SEEK_SET); } ReadSequenceData(); SetChannelOutputFrameNumber(frameNumber); SetChannelOutputRefreshRate(m_seqRefreshRate); StartChannelOutputThread(); m_seqStarting = 0; return m_seqFileSize; }
int InitializeChannelOutputs(void) { Json::Value root; Json::Reader reader; int i = 0; channelOutputFrame = 0; for (i = 0; i < FPPD_MAX_CHANNEL_OUTPUTS; i++) { bzero(&channelOutputs[i], sizeof(channelOutputs[i])); } // Reset index so we can start populating the outputs array i = 0; if (FPDOutput.isConfigured()) { channelOutputs[i].startChannel = getSettingInt("FPDStartChannelOffset"); channelOutputs[i].outputOld = &FPDOutput; if (FPDOutput.open("", &channelOutputs[i].privData)) { channelOutputs[i].channelCount = channelOutputs[i].outputOld->maxChannels(channelOutputs[i].privData); i++; } else { LogErr(VB_CHANNELOUT, "ERROR Opening FPD Channel Output\n"); } } if (((getFPPmode() != BRIDGE_MODE) || (getSettingInt("E131Bridging"))) && (E131Output.isConfigured())) { channelOutputs[i].startChannel = 0; channelOutputs[i].outputOld = &E131Output; if (E131Output.open("", &channelOutputs[i].privData)) { channelOutputs[i].channelCount = channelOutputs[i].outputOld->maxChannels(channelOutputs[i].privData); i++; } else { LogErr(VB_CHANNELOUT, "ERROR Opening E1.31 Channel Output\n"); } } FILE *fp; char filename[1024]; char buf[2048]; // Parse the channeloutputs.json config file strcpy(filename, getMediaDirectory()); strcat(filename, "/config/channeloutputs.json"); LogDebug(VB_CHANNELOUT, "Loading %s\n", filename); if (FileExists(filename)) { std::ifstream t(filename); std::stringstream buffer; buffer << t.rdbuf(); std::string config = buffer.str(); bool success = reader.parse(buffer.str(), root); if (!success) { LogErr(VB_CHANNELOUT, "Error parsing %s\n", filename); return 0; } const Json::Value outputs = root["channelOutputs"]; std::string type; int start = 0; int count = 0; for (int c = 0; c < outputs.size(); c++) { type = outputs[c]["type"].asString(); if (!outputs[c]["enabled"].asInt()) { LogDebug(VB_CHANNELOUT, "Skipping Disabled Channel Output: %s\n", type.c_str()); continue; } start = outputs[c]["startChannel"].asInt(); count = outputs[c]["channelCount"].asInt(); // internally we start channel counts at zero start -= 1; channelOutputs[i].startChannel = start; channelOutputs[i].channelCount = count; if (type == "LEDPanelMatrix") { #if defined(PLATFORM_PI) || defined(PLATFORM_ODROID) if (outputs[c]["subType"] == "RGBMatrix") channelOutputs[i].output = new RGBMatrixOutput(start, count); else { LogErr(VB_CHANNELOUT, "%s subType not valid on Pi\n", outputs[c]["subType"].asString().c_str()); continue; } #endif #ifdef PLATFORM_BBB if (outputs[c]["subType"] == "LEDscapeMatrix") channelOutputs[i].output = new LEDscapeMatrixOutput(start, count); else { LogErr(VB_CHANNELOUT, "%s subType not valid on BBB\n", outputs[c]["subType"].asString().c_str()); continue; } } else if (type == "BBB48String") { channelOutputs[i].output = new BBB48StringOutput(start, count); } else if (type == "BBBSerial") { channelOutputs[i].output = new BBBSerialOutput(start, count); #endif #ifdef USEOLA } else if (type == "OLA") { channelOutputs[i].output = new OLAOutput(start, count); #endif } else if (type == "USBRelay") { channelOutputs[i].output = new USBRelayOutput(start, count); #if defined(PLATFORM_PI) } else if (type == "Hill320") { channelOutputs[i].output = new Hill320Output(start, count); #endif #ifdef USE_X11Matrix } else if (type == "X11Matrix") { channelOutputs[i].output = new X11MatrixOutput(start, count); #endif } else { LogErr(VB_CHANNELOUT, "Unknown Channel Output type: %s\n", type.c_str()); continue; } if (channelOutputs[i].output->Init(outputs[c])) { i++; } else { LogErr(VB_CHANNELOUT, "ERROR Opening %s Channel Output\n", type.c_str()); } } } // Parse the channeloutputs config file strcpy(filename, getMediaDirectory()); strcat(filename, "/channeloutputs"); if (FileExists(filename)) { LogDebug(VB_CHANNELOUT, "Loading %s\n", filename); fp = fopen(filename, "r"); if (fp == NULL) { LogErr(VB_CHANNELOUT, "Could not open Channel Outputs config file %s: %s\n", filename, strerror(errno)); channelOutputCount = 0; return 0; } while(fgets(buf, 2048, fp) != NULL) { int enabled = 0; char type[32]; int start = 0; int count = 0; char deviceConfig[160]; if (buf[0] == '#') // Allow # comments for testing continue; int fields = sscanf(buf, "%d,%[^,],%d,%d,%s", &enabled, type, &start, &count, deviceConfig); if (fields != 5) { LogErr(VB_CHANNELOUT, "Invalid line in channeloutputs config file: %s\n", buf); continue; } if (!enabled) { LogDebug(VB_CHANNELOUT, "Skipping disabled channel output: %s", buf); continue; } if (count > (FPPD_MAX_CHANNELS - start)) { LogWarn(VB_CHANNELOUT, "Channel Output config, start (%d) + count (%d) exceeds max (%d) channel\n", start, count, FPPD_MAX_CHANNELS); count = FPPD_MAX_CHANNELS - start; LogWarn(VB_CHANNELOUT, "Count suppressed to %d for config line: %s\n", count, buf); } if (strlen(deviceConfig)) strcat(deviceConfig, ";"); strcat(deviceConfig, "type="); strcat(deviceConfig, type); LogDebug(VB_CHANNELOUT, "ChannelOutput: %d %s %d %d %s\n", enabled, type, start, count, deviceConfig); // internally we start channel counts at zero start -= 1; channelOutputs[i].startChannel = start; channelOutputs[i].channelCount = count; if ((!strcmp(type, "Pixelnet-Lynx")) || (!strcmp(type, "Pixelnet-Open"))) { channelOutputs[i].output = new USBPixelnetOutput(start, count); } else if ((!strcmp(type, "DMX-Pro")) || (!strcmp(type, "DMX-Open"))) { channelOutputs[i].output = new USBDMXOutput(start, count); } else if ((!strcmp(type, "VirtualMatrix")) || (!strcmp(type, "FBMatrix"))) { channelOutputs[i].output = new FBMatrixOutput(start, count); } else if (!strcmp(type, "GPIO")) { channelOutputs[i].output = new GPIOOutput(start, count); } else if (!strcmp(type, "GenericSerial")) { channelOutputs[i].output = new GenericSerialOutput(start, count); } else if (!strcmp(type, "LOR")) { channelOutputs[i].outputOld = &LOROutput; } else if (!strcmp(type, "Renard")) { channelOutputs[i].outputOld = &USBRenardOutput; #ifdef PLATFORM_PI } else if (!strcmp(type, "RPIWS281X")) { channelOutputs[i].output = new RPIWS281xOutput(start, count); #endif } else if (!strcmp(type, "SPI-WS2801")) { channelOutputs[i].output = new SPIws2801Output(start, count); } else if (!strcmp(type, "SPI-nRF24L01")) { channelOutputs[i].outputOld = &SPInRF24L01Output; } else if (!strcmp(type, "Triks-C")) { channelOutputs[i].outputOld = &TriksCOutput; } else if (!strcmp(type, "GPIO-595")) { channelOutputs[i].output = new GPIO595Output(start, count); } else if (!strcmp(type, "Debug")) { channelOutputs[i].output = new DebugOutput(start, count); } else { LogErr(VB_CHANNELOUT, "Unknown Channel Output type: %s\n", type); continue; } if ((channelOutputs[i].outputOld) && (channelOutputs[i].outputOld->open(deviceConfig, &channelOutputs[i].privData))) { if (channelOutputs[i].channelCount > channelOutputs[i].outputOld->maxChannels(channelOutputs[i].privData)) { LogWarn(VB_CHANNELOUT, "Channel Output config, count (%d) exceeds max (%d) channel for configured output\n", channelOutputs[i].channelCount, channelOutputs[i].outputOld->maxChannels(channelOutputs[i].privData)); channelOutputs[i].channelCount = channelOutputs[i].outputOld->maxChannels(channelOutputs[i].privData); LogWarn(VB_CHANNELOUT, "Count suppressed to %d for config: %s\n", channelOutputs[i].channelCount, buf); } i++; } else if ((channelOutputs[i].output) && (channelOutputs[i].output->Init(deviceConfig))) { i++; } else { LogErr(VB_CHANNELOUT, "ERROR Opening %s Channel Output\n", type); } } } channelOutputCount = i; LogDebug(VB_CHANNELOUT, "%d Channel Outputs configured\n", channelOutputCount); LoadChannelRemapData(); return 1; }
char *ProcessCommand(char *command, char *response) { char *s; char *s2; char *s3; char *s4; char *response2 = NULL; int i; char NextPlaylist[128] = "No playlist scheduled."; char NextScheduleStartText[64] = ""; char CommandStr[64]; LogExcess(VB_COMMAND, "CMD: %s\n", command); s = strtok(command,","); strcpy(CommandStr, s); if (!strcmp(CommandStr, "s")) { scheduler->GetNextScheduleStartText(NextScheduleStartText); scheduler->GetNextPlaylistText(NextPlaylist); if(FPPstatus==FPP_STATUS_IDLE) { if (getFPPmode() == REMOTE_MODE) { int secsElapsed = 0; int secsRemaining = 0; char seqFilename[1024]; char mediaFilename[1024]; if (sequence->IsSequenceRunning()) { strcpy(seqFilename, sequence->m_seqFilename); secsElapsed = sequence->m_seqSecondsElapsed; secsRemaining = sequence->m_seqSecondsRemaining; } else { strcpy(seqFilename, ""); } if (mediaOutput) { strcpy(mediaFilename, mediaOutput->m_mediaFilename.c_str()); secsElapsed = mediaOutputStatus.secondsElapsed; secsRemaining = mediaOutputStatus.secondsRemaining; } else { strcpy(mediaFilename, ""); } sprintf(response,"%d,%d,%d,%s,%s,%d,%d\n", getFPPmode(), 0, getVolume(), seqFilename, mediaFilename, secsElapsed, secsRemaining); } else if (sequence->IsSequenceRunning()) { sprintf(response,"%d,%d,%d,,,%s,,0,0,%d,%d,%s,%s,0\n", getFPPmode(), 1, getVolume(), sequence->m_seqFilename, sequence->m_seqSecondsElapsed, sequence->m_seqSecondsRemaining, NextPlaylist, NextScheduleStartText); } else { sprintf(response,"%d,%d,%d,%s,%s\n",getFPPmode(),0,getVolume(),NextPlaylist,NextScheduleStartText); } } else { Json::Value pl = playlist->GetInfo(); if (pl["currentEntry"].isMember("dynamic")) pl["currentEntry"] = pl["currentEntry"]["dynamic"]; if ((pl["currentEntry"]["type"] == "both") || (pl["currentEntry"]["type"] == "media")) { //printf(" %s\n", pl.toStyledString().c_str()); sprintf(response,"%d,%d,%d,%s,%s,%s,%s,%d,%d,%d,%d,%s,%s,%d\n", getFPPmode(), FPPstatus, getVolume(), pl["name"].asString().c_str(), pl["currentEntry"]["type"].asString().c_str(), pl["currentEntry"]["type"].asString() == "both" ? pl["currentEntry"]["sequence"]["sequenceName"].asString().c_str() : "", pl["currentEntry"]["type"].asString() == "both" ? pl["currentEntry"]["media"]["mediaFilename"].asString().c_str() : pl["currentEntry"]["mediaFilename"].asString().c_str() , // pl["currentEntry"]["entryID"].asInt() + 1, playlist->GetPosition(), pl["size"].asInt(), pl["currentEntry"]["type"].asString() == "both" ? pl["currentEntry"]["media"]["secondsElapsed"].asInt() : pl["currentEntry"]["secondsElapsed"].asInt(), pl["currentEntry"]["type"].asString() == "both" ? pl["currentEntry"]["media"]["secondsRemaining"].asInt() : pl["currentEntry"]["secondsRemaining"].asInt(), NextPlaylist, NextScheduleStartText, pl["repeat"].asInt()); } else if (pl["currentEntry"]["type"] == "sequence") { sprintf(response,"%d,%d,%d,%s,%s,%s,%s,%d,%d,%d,%d,%s,%s,%d\n", getFPPmode(), FPPstatus, getVolume(), pl["name"].asString().c_str(), pl["currentEntry"]["type"].asString().c_str(), pl["currentEntry"]["sequenceName"].asString().c_str(), "", // pl["currentEntry"]["entryID"].asInt() + 1, playlist->GetPosition(), pl["size"].asInt(), sequence->m_seqSecondsElapsed, sequence->m_seqSecondsRemaining, NextPlaylist, NextScheduleStartText, pl["repeat"].asInt()); } else { sprintf(response,"%d,%d,%d,%s,%s,%s,%s,%d,%d,%d,%d,%s,%s,%d\n", getFPPmode(), FPPstatus, getVolume(), pl["name"].asString().c_str(), pl["currentEntry"]["type"].asString().c_str(), "", "", // pl["currentEntry"]["entryID"].asInt() + 1, playlist->GetPosition(), pl["size"].asInt(), pl["currentEntry"]["type"].asString() == "pause" ? pl["currentEntry"]["duration"].asInt() - pl["currentEntry"]["remaining"].asInt() : 0, pl["currentEntry"]["type"].asString() == "pause" ? pl["currentEntry"]["remaining"].asInt() : 0, NextPlaylist, NextScheduleStartText, pl["repeat"].asInt()); } } } else if ((!strcmp(CommandStr, "P")) || (!strcmp(CommandStr, "p"))) { s = strtok(NULL,","); s2 = strtok(NULL,","); int entry = 0; if (s2 && s2[0]) entry = atoi(s2); if (s) { int repeat = strcmp(CommandStr, "p") ? 0 : 1; int scheduledRepeat = 0; std::string playlistName = scheduler->GetPlaylistThatShouldBePlaying(scheduledRepeat); if ((playlistName == s) && (repeat == scheduledRepeat)) { // Use CheckIfShouldBePlayingNow() so the scheduler knows when // to stop the playlist scheduler->CheckIfShouldBePlayingNow(1); sprintf(response,"%d,%d,Playlist Started,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if (playlist->Play(s, entry, repeat, 0)) { FPPstatus = FPP_STATUS_PLAYLIST_PLAYING; sprintf(response,"%d,%d,Playlist Started,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Error Starting Playlist,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else { sprintf(response,"%d,%d,Unknown Playlist,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if ((!strcmp(CommandStr, "S")) || (!strcmp(CommandStr, "StopGracefully"))) { if (FPPstatus==FPP_STATUS_PLAYLIST_PLAYING) { playlist->StopGracefully(1); scheduler->ReLoadCurrentScheduleInfo(); sprintf(response,"%d,%d,Playlist Stopping Gracefully,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,Not playing,,,,,,,,,,,\n",COMMAND_FAILED); } } else if ((!strcmp(CommandStr, "d")) || (!strcmp(CommandStr, "StopNow"))) { if (FPPstatus==FPP_STATUS_PLAYLIST_PLAYING || FPPstatus==FPP_STATUS_STOPPING_GRACEFULLY) { playlist->StopNow(1); scheduler->ReLoadCurrentScheduleInfo(); sprintf(response,"%d,%d,Playlist Stopping Now,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if ((FPPstatus == FPP_STATUS_IDLE) && (sequence->IsSequenceRunning())) { sequence->CloseSequenceFile(); sprintf(response,"%d,%d,Sequence Stopping Now,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Not playing,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "R")) { scheduler->ReLoadNextScheduleInfo(); if (FPPstatus==FPP_STATUS_IDLE) { scheduler->ReLoadCurrentScheduleInfo(); scheduler->CheckIfShouldBePlayingNow(); } sprintf(response,"%d,%d,Reloading Schedule,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if (!strcmp(CommandStr, "v")) { s = strtok(NULL,","); if (s) { setVolume(atoi(s)); sprintf(response,"%d,%d,Setting Volume,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else { sprintf(response,"%d,%d,Invalid Volume,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "q")) { // Quit/Shutdown fppd if ((FPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (FPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { playlist->StopNow(1); sleep(2); } ShutdownFPPD(); sleep(1); } else if (!strcmp(CommandStr, "e")) { // Start an Effect s = strtok(NULL,","); s2 = strtok(NULL,","); s3 = strtok(NULL,","); if (s && s2) { i = StartEffect(s, atoi(s2), atoi(s3)); if (i >= 0) sprintf(response,"%d,%d,Starting Effect,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Invalid Effect,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else sprintf(response,"%d,%d,Invalid Effect,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "t")) { // Trigger an event s = strtok(NULL,","); pluginCallbackManager.eventCallback(s, "command"); i = TriggerEventByID(s); if (i >= 0) sprintf(response,"%d,%d,Event Triggered,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Event Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "GetTestMode")) { strcpy(response, channelTester->GetConfig().c_str()); strcat(response, "\n"); } else if (!strcmp(CommandStr, "SetTestMode")) { if (channelTester->SetupTest(std::string(s + strlen(s) + 1))) { sprintf(response, "0,%d,Test Mode Activated,,,,,,,,,\n", COMMAND_SUCCESS); } else { sprintf(response, "0,%d,Test Mode Deactivated,,,,,,,,,\n", COMMAND_SUCCESS); } } else if (!strcmp(CommandStr, "LogLevel")) { s = strtok(NULL,","); if (SetLogLevel(s)) { sprintf(response,"%d,%d,Log Level Updated,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_SUCCESS,logLevel,logMask); } else { sprintf(response,"%d,%d,Error Updating Log Level,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_FAILED,logLevel,logMask); } } else if (!strcmp(CommandStr, "LogMask")) { s = strtok(NULL,","); if ((s && SetLogMask(s)) || SetLogMask("")) { sprintf(response,"%d,%d,Log Mask Updated,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_SUCCESS,logLevel,logMask); } else { sprintf(response,"%d,%d,Error Updating Log Mask,%d,%d,,,,,,,,,\n", getFPPmode(),COMMAND_FAILED,logLevel,logMask); } } else if (!strcmp(CommandStr, "SetSetting")) { char name[128]; s = strtok(NULL,","); if (s) { strcpy(name, s); s = strtok(NULL,","); if (s) parseSetting(name, s); } } else if (!strcmp(CommandStr, "StopAllEffects")) { StopAllEffects(); sprintf(response,"%d,%d,All Effects Stopped,,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS); } else if (!strcmp(CommandStr, "StopEffectByName")) { s = strtok(NULL,","); if (strlen(s)) { if (StopEffect(s)) sprintf(response,"%d,%d,Stopping Effect,%s,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,s); else sprintf(response,"%d,%d,Stop Effect Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } } else if (!strcmp(CommandStr, "StopEffect")) { s = strtok(NULL,","); i = atoi(s); if (StopEffect(i)) sprintf(response,"%d,%d,Stopping Effect,%d,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,i); else sprintf(response,"%d,%d,Stop Effect Failed,,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED); } else if (!strcmp(CommandStr, "GetRunningEffects")) { sprintf(response,"%d,%d,Running Effects",getFPPmode(),COMMAND_SUCCESS); GetRunningEffects(response, &response2); } else if (!strcmp(CommandStr, "GetFPPDUptime")) { sprintf(response,"%d,%d,FPPD Uptime,%ld,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS, time(NULL) - fppdStartTime); } else if (!strcmp(CommandStr, "StartSequence")) { if ((FPPstatus == FPP_STATUS_IDLE) && (!sequence->IsSequenceRunning())) { s = strtok(NULL,","); s2 = strtok(NULL,","); if (s && s2) { i = atoi(s2); sequence->OpenSequenceFile(s, 0, i); } else { LogDebug(VB_COMMAND, "Invalid command: %s\n", command); } } else { LogErr(VB_COMMAND, "Tried to start a sequence when a playlist or " "sequence is already running\n"); } } else if (!strcmp(CommandStr, "StopSequence")) { if ((FPPstatus == FPP_STATUS_IDLE) && (sequence->IsSequenceRunning())) { sequence->CloseSequenceFile(); } else { LogDebug(VB_COMMAND, "Tried to stop a sequence when no sequence is running\n"); } } else if (!strcmp(CommandStr, "ToggleSequencePause")) { if ((sequence->IsSequenceRunning()) && ((FPPstatus == FPP_STATUS_IDLE) || ((FPPstatus != FPP_STATUS_IDLE) && (playlist->GetInfo()["currentEntry"]["type"] == "sequence")))) { sequence->ToggleSequencePause(); } } else if (!strcmp(CommandStr, "SingleStepSequence")) { if ((sequence->IsSequenceRunning()) && (sequence->SequenceIsPaused()) && ((FPPstatus == FPP_STATUS_IDLE) || ((FPPstatus != FPP_STATUS_IDLE) && (playlist->GetInfo()["currentEntry"]["type"] == "sequence")))) { sequence->SingleStepSequence(); } } else if (!strcmp(CommandStr, "SingleStepSequenceBack")) { if ((sequence->IsSequenceRunning()) && (sequence->SequenceIsPaused()) && ((FPPstatus == FPP_STATUS_IDLE) || ((FPPstatus != FPP_STATUS_IDLE) && (playlist->GetInfo()["currentEntry"]["type"] == "sequence")))) { sequence->SingleStepSequenceBack(); } } else if (!strcmp(CommandStr, "NextPlaylistItem")) { switch (FPPstatus) { case FPP_STATUS_IDLE: sprintf(response,"%d,%d,No playlist running\n",getFPPmode(),COMMAND_FAILED); break; case FPP_STATUS_PLAYLIST_PLAYING: sprintf(response,"%d,%d,Skipping to next playlist item\n",getFPPmode(),COMMAND_SUCCESS); playlist->NextItem(); break; case FPP_STATUS_STOPPING_GRACEFULLY: sprintf(response,"%d,%d,Playlist is stopping gracefully\n",getFPPmode(),COMMAND_FAILED); break; } } else if (!strcmp(CommandStr, "PrevPlaylistItem")) { switch (FPPstatus) { case FPP_STATUS_IDLE: sprintf(response,"%d,%d,No playlist running\n",getFPPmode(),COMMAND_FAILED); break; case FPP_STATUS_PLAYLIST_PLAYING: sprintf(response,"%d,%d,Skipping to previous playlist item\n",getFPPmode(),COMMAND_SUCCESS); playlist->PrevItem(); break; case FPP_STATUS_STOPPING_GRACEFULLY: sprintf(response,"%d,%d,Playlist is stopping gracefully\n",getFPPmode(),COMMAND_FAILED); break; } } else if (!strcmp(CommandStr, "SetupExtGPIO")) { // Configure the given GPIO to the given mode s = strtok(NULL,","); s2 = strtok(NULL,","); if (s && s2) { if (!SetupExtGPIO(atoi(s), s2)) { sprintf(response, "%d,%d,Configuring GPIO,%d,%s,,,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,atoi(s),s2); } else { sprintf(response, "%d,%d,Configuring GPIO,%d,%s,,,,,,,,,\n",getFPPmode(),COMMAND_FAILED,atoi(s),s2); } } } else if (!strcmp(CommandStr, "ExtGPIO")) { s = strtok(NULL,","); s2 = strtok(NULL,","); s3 = strtok(NULL,","); if (s && s2 && s3) { i = ExtGPIO(atoi(s), s2, atoi(s3)); if (i >= 0) { sprintf(response, "%d,%d,Setting GPIO,%d,%s,%d,%d,,,,,,,\n",getFPPmode(),COMMAND_SUCCESS,atoi(s),s2,atoi(s3),i); } else { sprintf(response, "%d,%d,Setting GPIO,%d,%s,%d,,,,,,,,\n",getFPPmode(),COMMAND_FAILED,atoi(s),s2,atoi(s3)); } } } else { sprintf(response,"Invalid command: '%s'\n", CommandStr); } return response2; }
/* * Start a new effect offset at the specified channel number */ int StartEffect(const std::string &effectName, int startChannel, int loop) { int effectID = -1; int frameTime = 50; LogInfo(VB_EFFECT, "Starting effect %s at channel %d\n", effectName.c_str(), startChannel); std::unique_lock<std::mutex> lock(effectsLock); if (effectCount >= MAX_EFFECTS) { LogErr(VB_EFFECT, "Unable to start effect %s, maximum number of effects already running\n", effectName.c_str()); return effectID; } std::string filename = getEffectDirectory(); filename += "/"; filename += effectName; filename += ".eseq"; FSEQFile *fseq = FSEQFile::openFSEQFile(filename); if (!fseq) { LogErr(VB_EFFECT, "Unable to open effect: %s\n", filename.c_str()); return effectID; } V2FSEQFile *v2fseq = dynamic_cast<V2FSEQFile*>(fseq); if (!v2fseq) { delete fseq; LogErr(VB_EFFECT, "Effect file not a correct eseq file: %s\n", filename.c_str()); return effectID; } if (v2fseq->m_sparseRanges.size() == 0){ LogErr(VB_EFFECT, "eseq file must have at least one model range."); delete fseq; return effectID; } if (startChannel != 0) { // This will need to change if/when we support multiple models per file v2fseq->m_sparseRanges[0].first = startChannel - 1; } frameTime = v2fseq->getStepTime(); effectID = GetNextEffectID(); if (effectID < 0) { LogErr(VB_EFFECT, "Unable to start effect %s, unable to determine next effect ID\n", effectName.c_str()); delete fseq; return effectID; } effects[effectID] = new FPPeffect; effects[effectID]->name = effectName; effects[effectID]->fp = v2fseq; effects[effectID]->loop = loop; effects[effectID]->background = 0; if (effectName == "background") { effects[effectID]->background = 1; } else if ((getFPPmode() == REMOTE_MODE) && (effectName.find("background_") == 0)) { std::string localFilename = "background_"; localFilename += getSetting("HostName"); if (localFilename == effectName) { effects[effectID]->background = 1; } } effectCount++; int tmpec = effectCount; lock.unlock(); StartChannelOutputThread(); if (!sequence->IsSequenceRunning() && tmpec == 1) { //first effect running, no sequence running, set the refresh rate //to the rate of the effect SetChannelOutputRefreshRate(1000 / frameTime); } return effectID; }
/* * Kick off the channel output thread */ int Player::StartChannelOutputThread(void) { LogDebug(VB_PLAYER | VB_CHANNELOUT, "StartChannelOutputThread()\n"); if (!ChannelOutputThreadIsRunning()) { // Give a little time in case we were shutting down usleep(200000); if (ChannelOutputThreadIsRunning()) { LogDebug(VB_PLAYER | VB_CHANNELOUT, "Channel Output thread is already running\n"); return 1; } } int mediaOffsetInt = getSettingInt("mediaOffset"); if (mediaOffsetInt) m_mediaOffset = (float)mediaOffsetInt * 0.001; else m_mediaOffset = 0.0; LogDebug(VB_PLAYER | VB_MEDIAOUT, "Using mediaOffset of %.3f\n", m_mediaOffset); int E131BridgingInterval = getSettingInt("E131BridgingInterval"); if ((getFPPmode() == BRIDGE_MODE) && (E131BridgingInterval)) m_defaultLightDelay = E131BridgingInterval * 1000; else m_defaultLightDelay = 1000000 / m_refreshRate; m_lightDelay = m_defaultLightDelay; m_runOutputThread = 1; int result = pthread_create(&m_outputThreadID, NULL, &ChannelOutputThread, this); if (result) { char msg[256]; m_runOutputThread = 0; switch (result) { case EAGAIN: strcpy(msg, "Insufficient Resources"); break; case EINVAL: strcpy(msg, "Invalid settings"); break; case EPERM : strcpy(msg, "Invalid Permissions"); break; } LogErr(VB_PLAYER | VB_CHANNELOUT, "ERROR creating channel output thread: %s\n", msg ); return 0; } else { pthread_detach(m_outputThreadID); } // Wait for thread to start while (!ChannelOutputThreadIsRunning()) usleep(10000); return 1; }
/* * 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); }