// Schedule Recordings /// <summary> /// Schedule a recording - this examines the request and populates Service ID, etc. /// The MCDATA.Schedule... method should never be called directly outside this method /// </summary> public static RecordingResult ScheduleRecording(RecordingRequest rr) { // Populate defaults, e.g. quality, if not set PopulateDefaultsIfUnset(ref rr); RecordingResult failedResult = new RecordingResult(); failedResult.Completed = false; if (rr.RequestType != RecordingRequestType.Manual) // manual recordings already have a service ID specified { if (rr.TVProgrammeID < 1) { failedResult.ErrorMessage = "No TV Programme ID was specified."; return(failedResult); } // Populate the Service ID if not already populated TVProgramme tvp = mcData.GetTVProgramme(rr.TVProgrammeID.ToString()); if (tvp == null) { failedResult.ErrorMessage = "No TV Programme with the specified ID could be found."; return(failedResult); } rr.ServiceID = long.Parse(tvp.ServiceID); // could fail } // Get the channel ID from the service ID TVService tvs = TVServiceWithIDOrNull(rr.ServiceID.ToString()); if (tvs == null) { failedResult.ErrorMessage = "No TV Channel with the retrieved ID could be found."; return(failedResult); } rr.MCChannelID = tvs.MCChannelID; // ************** SCHEDULE THE RECORDING ************************ RPRequest generatedRequest; RecordingResult earlyRecResult; if (!mcData.ScheduleRecording(rr, out generatedRequest, out earlyRecResult)) { // Failed already - return the early result return(earlyRecResult); } RecordingResult recResult = mcData.DetermineRecordingResultForRequest(generatedRequest); // Success? if (recResult.Success) { // Wait a moment so Scheduler can catch up and associate our request with our recordings... System.Threading.Thread.Sleep(600); // Now refresh and get the generated recordings... EPGManager.ReloadAllRecordings(); try { RPRequest req = recResult.GeneratedRecordingsBlob.RPRequests[0]; // Add recordings recResult.GeneratedRecordingsBlob.RPRecordings = req.Recordings(); // Add programs linked to these recordings foreach (RPRecording rec in recResult.GeneratedRecordingsBlob.RPRecordings) { TVProgramme tvp = rec.TVProgramme(); if (tvp != null) { recResult.GeneratedRecordingsBlob.TVProgrammes.Add(tvp); } } } catch (Exception ex) { Functions.WriteLineToLogFile("ScheduleRecording(): Error retrieving recordings:"); Functions.WriteExceptionToLogFile(ex); recResult.Success = false; recResult.ErrorMessage = "Exception occured while retrieving recordings - the recording may have been scheduled."; } } return(recResult); }
// Refresh public static bool UpdateTVChannels() { bool debug = ((Settings.Default.DebugChannels) & (Settings.Default.DebugAdvanced)); Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels() Running:"); // If we don't have any existing channels at all then get some if ((AllTVChannels == null) || (AllTVChannels.Count < 1)) { Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): No existing TV Channels, populating from cache first..."); if (!PopulateTVChannels(false)) { return(false); } Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Populated from cache: there are " + AllTVChannels.Count.ToString() + " channels."); if (AllTVChannels.Count < 1) { return(false); } } Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Backing up " + AllTVChannels.Count.ToString() + " channels."); Dictionary <string, TVService> OldTVChannelsKeyedByChannelNumberString = new Dictionary <string, TVService>(); foreach (TVService tvs in AllTVChannels.Values) { TVService copiedOldService = tvs.DeepCopy(); // Skip duplicate keys otherwise you spend 4 hours on a Sunday trying to remotely debug a native code crash if (OldTVChannelsKeyedByChannelNumberString.ContainsKey(copiedOldService.ChannelNumberString())) { Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels() Skipping service with duplicate channel num string (" + copiedOldService.ChannelNumberString() + ") Callsign is " + copiedOldService.Callsign); } else { Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels() Storing " + copiedOldService.ChannelNumberString() + " : " + copiedOldService.Callsign); OldTVChannelsKeyedByChannelNumberString.Add(copiedOldService.ChannelNumberString(), copiedOldService); } } // Re-populate AllTVChannels from MediaCenter Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Getting newest channels from 7MC..."); PopulateTVChannels(true); Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Populated from 7MC: there are " + AllTVChannels.Count.ToString() + " channels."); // Go through new channels - retrieve isFavourite information and user sort order from old channels Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Merging info from old channels into newer list."); List <string> MatchedChannelNumberStrings = new List <string>(); foreach (TVService newService in AllTVChannels.Values) { if (OldTVChannelsKeyedByChannelNumberString.ContainsKey(newService.ChannelNumberString())) { if (!MatchedChannelNumberStrings.Contains(newService.ChannelNumberString())) { TVService oldService = OldTVChannelsKeyedByChannelNumberString[newService.ChannelNumberString()]; // Merge in old user sort and isfavorite information newService.IsFavorite = oldService.IsFavorite; newService.UserSortOrder = oldService.UserSortOrder; if (newService.MCChannelID != oldService.MCChannelID) { Functions.WriteLineToLogFile("EPG: UpdateTVChannels(): INFORMATION: Service " + newService.Callsign + " changed MC-ID from " + oldService.MCChannelID.ToString() + " to " + newService.MCChannelID.ToString() + " - merging in change."); } if (newService.UniqueId != oldService.UniqueId) { Functions.WriteLineToLogFile("EPG: UpdateTVChannels(): INFORMATION: Service " + newService.Callsign + " changed Unique Service ID from " + oldService.UniqueId + " to " + newService.UniqueId + " - merging in change."); } MatchedChannelNumberStrings.Add(newService.ChannelNumberString()); } } else { Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): NEW channel " + newService.Callsign + " was found. (Chan number " + newService.ChannelNumberString() + ")"); } } Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Merge complete."); // Save it Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): Saving."); SaveChannelsToLocal(); Functions.WriteLineToLogFileIfSetting(debug, "EPG: UpdateTVChannels(): DONE."); return(true); }
public MediaStreamingResult StartStreamer(MediaStreamingRequest request, string HostName, bool dontstart, out bool alreadyexists) { int newStreamerID = newUniqueID(request, false, dontstart); // Universal workaround: can be removed once new iOS app introduced that sets the Client Device to 'iphone3g' // (desirable to remove it since this will also affect silverlive streaming) if (string.IsNullOrEmpty(request.ClientID)) { request.ClientID = "ios"; request.ClientDevice = "iphone3g"; } try { // Legacy clients (e.g. iOS client) don't have any custom parameters - set them now based on 'Quality' if (!request.UseCustomParameters) // if there are no custom parameters { // Create/update video encoding parameters (also transfers Aspect Ratio into child 'encoding parameters' object) MediaStreamingRequest.AddVideoEncodingParametersUsingiOSQuality(ref request); } /* ************************************************************ * // Override any video encoding parameters from server settings ************************************************************ */ // 1. Audio Volume if (Settings.Default.StreamingVolumePercent != 100) { request.CustomParameters.AudioVolumePercent = Convert.ToInt32(Settings.Default.StreamingVolumePercent); } // 2. Custom FFMPEG template if ((Settings.Default.UseCustomFFMpegTemplate) & (!string.IsNullOrWhiteSpace(Settings.Default.CustomFFMpegTemplate))) { request.CustomParameters.CustomFFMpegTemplate = Settings.Default.CustomFFMpegTemplate.Trim(); } // 3. iPhone 3G requires profile constraints if (request.ClientDevice.ToLowerInvariant() == "iphone3g") { request.CustomParameters.X264Level = 30; request.CustomParameters.X264Profile = "baseline"; } // 4. Deinterlace obvious WMC video if ( (request.InputFile.ToUpper().EndsWith("WTV")) || (request.InputFile.ToUpper().EndsWith("DVR-MS")) ) { request.CustomParameters.DeInterlace = true; } // for liveTV resolve AV sync issue: //LiveTVHelpers lth = new LiveTVHelpers(); //request.CustomParameters.AVSyncDifference = lth.GetMediaSyncDifference(Functions.ToolkitFolder, Functions.StreamBaseFolder, request.InputFile); //for LiveTV // Create the streamer MediaStreamer mediaStreamer = new MediaStreamer(newStreamerID, request, Functions.ToolkitFolder, Settings.Default.MediaStreamerSecondsToKeepAlive, Settings.Default.DebugAdvancedStreaming); mediaStreamer.DebugMessage += new EventHandler <WasFatAttitude.GenericEventArgs <string> >(mediaStreamer_DebugMessage); mediaStreamer.DebugMessage2 += new EventHandler <WasFatAttitude.GenericEventArgs <string> >(mediaStreamer_DebugMessage2); mediaStreamer.DebugMessage3 += new EventHandler <WasFatAttitude.GenericEventArgs <string> >(mediaStreamer_DebugMessage3); mediaStreamer.DebugMessage4 += new EventHandler <WasFatAttitude.GenericEventArgs <string> >(mediaStreamer_DebugMessage4); mediaStreamer.AutoDied += new EventHandler(mediaStreamer_AutoDied); MediaStreamingResult result = new MediaStreamingResult(); try { AddNewStreamer(mediaStreamer); Functions.WriteLineToLogFile("MediaStreamer: mediaStreamer object created."); alreadyexists = false; // Try streaming result = mediaStreamer.Configure(); // this does actually begin transcoding } catch (Exception e) { //apparently key already existed alreadyexists = true; } if (request.NewLiveTV) { result.LiveStreamingIndexPath = "/httplivestream/" + newStreamerID.ToString() + "/livetv.m3u8"; } else if (request.UseNewerFFMPEG) { result.LiveStreamingIndexPath = "/httplivestream/" + newStreamerID.ToString() + "/index2.m3u8"; } else { result.LiveStreamingIndexPath = "/httplivestream/" + newStreamerID.ToString() + "/index.m3u8"; } // Add streamer ID to result result.StreamerID = newStreamerID; // Return return(result); } catch (Exception e) { Functions.WriteLineToLogFile("Exception setting up mediaStreaming object:"); Functions.WriteExceptionToLogFile(e); alreadyexists = false; return(new MediaStreamingResult(MediaStreamingResultCodes.NamedError, e.Message)); } }
public void CleanUp() { Functions.WriteLineToLogFile("StreamingManager: Cleaning Up."); StopAllStreamers(); }
void prober_DebugMessage(object sender, WasFatAttitude.GenericEventArgs <string> e) { Functions.WriteLineToLogFileIfSetting(Settings.Default.DebugStreaming, e.Value); }
public int newUniqueID(MediaStreamingRequest request, bool getIDOnly) { int newId = IdsAndInputFilesContains(request.InputFile + request.UniekClientID); if (request.KeepSameIDForSameInputFile && newId != 0) // != 0 means found as existing id that can be resumed { var ms = GetStreamerByID(newId); if (ms != null && !getIDOnly) { //mediaStreamers.Remove(newId); Functions.WriteLineToLogFile("Streamer newId=" + newId + " about to stop (in background), mediaStreamers.ContainsKey(newId) : " + mediaStreamers.ContainsKey(newId)); StopStreamer(newId, 2); Functions.WriteLineToLogFile("Streamer newId=" + newId + " stopped (in background), mediaStreamers.ContainsKey(newId) : " + mediaStreamers.ContainsKey(newId)); } if (!getIDOnly) { DeleteStreamingFiles(newId); //begin anew, s.t. if new quality, this will be used. } //bump up the id in the database db.Delete("IDANDINPUTFILE", String.Format("STREAMID = {0}", "" + newId)); var item = new Dictionary <string, string>(); item.Add("STREAMID", "" + newId); string i = request.InputFile.Replace("'", "''"); string u = request.UniekClientID.Replace("'", "''"); item.Add("INPUTFILE", i + u); db.Insert("IDANDINPUTFILE", item); return(newId); } //clean up if database is large const int maxFileToRememberResume = 1000; int count = 0; Int32.TryParse(db.ExecuteScalar("select COUNT(*) from IDANDINPUTFILE where STREAMID IS NOT NULL;"), out count); if (count > maxFileToRememberResume) { try { DataTable tabel; String query = "select STREAMID, INPUTFILE from IDANDINPUTFILE;"; tabel = db.GetDataTable(query); // The results can be directly applied to a DataGridView control // recipeDataGrid.DataSource = tabel; // Or looped through for some other reason var i = 0; foreach (DataRow r in tabel.Rows) { if (i < count / 2) { db.ExecuteNonQuery("delete from IDANDINPUTFILE where STREAMID=" + r["STREAMID"] + ";"); } else { } i++; } } catch (Exception fail) { String error = "The following error has occurred in cleaning up database : " + db.ToString() + "\n"; error += fail.Message; if (Settings.Default.DebugStreaming) { Functions.WriteLineToLogFile("StreamingManager: " + error); } } } do { var r = new Random(); //newId = (getIDOnly ? r.Next(100000, 999999) : r.Next(10000, 99999)); newId = r.Next(10000, 99999); } while (mediaStreamers.ContainsKey(newId) || !IdsAndInputFilesContains(newId).Equals("")); if (IdsAndInputFilesContains(request.InputFile + request.UniekClientID) == 0 && !request.InputFile.Contains("RMCLiveTV")) //live tv gets a new iD all the time anyway, due to randowm nr in inputfile string { var item = new Dictionary <string, string>(); item.Add("STREAMID", "" + newId); string i = request.InputFile.Replace("'", "''"); string u = request.UniekClientID.Replace("'", "''"); item.Add("INPUTFILE", i + u); db.Insert("IDANDINPUTFILE", item); // db.CommitTransaction(); } return(newId); }