// Tune to a channel, and get a live stream to that channel. // // Post-data is an object with: // channel - The channel to tune to. // upcomingRecordingAllocation - The allocation of the next upcoming recording, or null if there isn't one. // stream - The live stream in case of retuning an existing stream, or null for a new one. // // Returns a LiveStreamResult value to indicate success or failure. public Stream LiveTune(Stream body) { var args = Bind <TuneLiveStreamArguments>(body); var stream = args.stream; LiveStreamResult result = Service.TuneLiveStream(args.channel, args.upcomingRecordingAllocation, ref stream); return(AsJson(new { result = result, stream = stream })); }
private void ShowLiveStreamResultMessageBox(LiveStreamResult result) { if (result == LiveStreamResult.NotSupported) { MessageBox.Show(this, "No tuner was able to start the live stream.", "Information", MessageBoxButtons.OK); } else if (result == LiveStreamResult.NoFreeCardFound) { MessageBox.Show(this, "No free card was found to start the live stream.", "Information", MessageBoxButtons.OK); } else if (result == LiveStreamResult.ChannelTuneFailed) { MessageBox.Show(this, "Failed to tune to channel.", "Information", MessageBoxButtons.OK); } else { MessageBox.Show(this, "Unable to start live streaming.", "Information", MessageBoxButtons.OK); } }
private LiveStreamResult StartAndPlayNewLiveStream(Channel channel, LiveStream liveStream) { LiveStreamResult result = this.ControlAgent.TuneLiveStream(channel, ref liveStream); Log.Debug("ChannelNavigator: start a new live stream, result = {0}", result); if (result == LiveStreamResult.Succeeded) { result = PlayLiveStream(liveStream); if (result == LiveStreamResult.Succeeded) { if (_autoFullScreen) { g_Player.ShowFullScreenWindow(); } } } return(result); }
private LiveStreamResult StartAndPlayNewLiveStream(Channel channel, LiveStream liveStream) { var res = Proxies.ControlService.TuneLiveStream(channel, liveStream).Result; liveStream = res.LiveStream; LiveStreamResult result = res.LiveStreamResult; Log.Debug("ChannelNavigator: start a new live stream, result = {0}", result); if (result == LiveStreamResult.Succeeded) { result = PlayLiveStream(liveStream); if (result == LiveStreamResult.Succeeded) { if (_autoFullScreen) { g_Player.ShowFullScreenWindow(); } } } return(result); }
private LiveStreamResult PlayLiveStream(LiveStream liveStream) { Log.Debug("ChannelNavigator: PlayLiveStream()"); LiveStreamResult result = LiveStreamResult.Succeeded; string fileName; bool isRTSP; GetPlayerFileNameAndOffset(liveStream, out fileName, out isRTSP); if (liveStream != null) _isAnalog = (ControlAgent.GetLiveStreamTuningDetails(liveStream).CardType == CardType.Analog); if (!isRTSP) { for (int i = 0; i < 10; i++) { if (System.IO.File.Exists(fileName)) break; Thread.Sleep(100); Log.Info("Channelnavigator: startplay: waiting for TS file {0}", fileName); } if (!System.IO.File.Exists(fileName)) { result = LiveStreamResult.UnknownError; g_Player.Stop(); } } if (result == LiveStreamResult.Succeeded) { for (int i = 0; i < 50; i++) { if (g_Player.Play(fileName, liveStream.Channel.ChannelType == ChannelType.Television ? g_Player.MediaType.TV : g_Player.MediaType.Radio)) { double duration = g_Player.Duration; if (duration > 0.0) { result = LiveStreamResult.Succeeded; g_Player.SeekAbsolute(duration); _liveStream = liveStream; break; } else { result = LiveStreamResult.UnknownError; g_Player.Stop(); Thread.Sleep(50); Log.Debug("ChannelNavigator: PlayLiveStream_timeout = {0}", i); } } else { result = LiveStreamResult.UnknownError; break; } } } Log.Debug("ChannelNavigator: PlayLiveStream_Result = {0}", result); return result; }
private void ChannelTuneFailedNotifyUser(LiveStreamResult result, Channel channel) { string TuningResult = string.Empty; switch (result) { case LiveStreamResult.ChannelTuneFailed: TuningResult = (Utility.GetLocalizedText(TextId.ChannelTuneFailed)); break; case LiveStreamResult.NoFreeCardFound: TuningResult = (Utility.GetLocalizedText(TextId.NoFreeCardFound)); break; case LiveStreamResult.NotSupported: TuningResult = (Utility.GetLocalizedText(TextId.NotSupported)); break; case LiveStreamResult.NoRetunePossible: TuningResult = (Utility.GetLocalizedText(TextId.NoRetunePossible)); break; case LiveStreamResult.IsScrambled: TuningResult = (Utility.GetLocalizedText(TextId.IsScrambled)); break; case LiveStreamResult.UnknownError: TuningResult = (Utility.GetLocalizedText(TextId.UnknownError)); break; } if (GUIWindowManager.ActiveWindow == (int)(int)GUIWindow.Window.WINDOW_TVFULLSCREEN) { // If failed and wasPlaying TV, left screen as it is and show zaposd with error message GUIMessage msg = new GUIMessage(GUIMessage.MessageType.GUI_MSG_TV_ERROR_NOTIFY, GUIWindowManager.ActiveWindow, 0, 0, 0, 0, null); msg.SendToTargetWindow = true; msg.Object = TuningResult; // forward error info object msg.TargetWindowId = (int)(int)GUIWindow.Window.WINDOW_TVFULLSCREEN; GUIGraphicsContext.SendMessage(msg); } else { // if not fulscreen, show notify dialog with the error message string caption = string.Empty; string tvlogo = string.Empty; if (channel != null) { _navigatorChannels[_currentChannel.ChannelType].PreviousChannel = channel; _currentChannel = null; using (SchedulerServiceAgent SchedulerAgent = new SchedulerServiceAgent()) { tvlogo = Utility.GetLogoImage(channel, SchedulerAgent); } if (channel.ChannelType == ChannelType.Television) caption = GUILocalizeStrings.Get(605) + " - " + channel.DisplayName; else caption = GUILocalizeStrings.Get(665) + " - " + channel.DisplayName; } GUIDialogNotify pDlgNotify = (GUIDialogNotify)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_NOTIFY); if (pDlgNotify != null) { pDlgNotify.Reset(); pDlgNotify.ClearAll(); pDlgNotify.SetHeading(caption); if (!string.IsNullOrEmpty(TuningResult)) { pDlgNotify.SetText(TuningResult); } pDlgNotify.SetImage(tvlogo); pDlgNotify.TimeOut = 5; pDlgNotify.DoModal(GUIWindowManager.ActiveWindow); } } }
private void TuneLiveStream(Channel channel) { Log.Debug("ChannelNavigator: TuneLiveStream(), channel = {0}", channel.DisplayName); if (channel != null) { using (SchedulerServiceAgent tvSchedulerAgent = new SchedulerServiceAgent()) { LiveStream liveStream = _liveStream; CurrentAndNextProgram currentAndNext = tvSchedulerAgent.GetCurrentAndNextForChannel(channel.ChannelId, true, _liveStream);//null); _currentChannel = channel; _doingChannelChange = true; RenderBlackImage(); if (liveStream != null) { try { g_Player.PauseGraph(); g_Player.OnZapping(0x80); result = this.ControlAgent.TuneLiveStream(channel, ref liveStream); Log.Debug("ChannelNavigator: First try to re-tune the existing TV stream (staying on the same card), result = {0}", result); if (result == LiveStreamResult.Succeeded) { if (_isAnalog) g_Player.OnZapping(-1); double duration = g_Player.Duration; if (g_Player.Duration < 0.0) result = LiveStreamResult.UnknownError; else { g_Player.SeekAbsolute(duration); g_Player.ContinueGraph(); } } else if (result == LiveStreamResult.NoRetunePossible)// not mapped to card, card in use by recorder or other user ---> start new stream { // Now re-try the new channel with a new stream. Log.Debug("ChannelNavigator: Seems a re-tune has failed, stop the current stream and start a new one"); SilentlyStopLiveStream(liveStream); result = StartAndPlayNewLiveStream(channel, liveStream); } } catch { result = LiveStreamResult.UnknownError; Log.Error("ChannelNavigator: TuneLiveStream error"); } } else { result = StartAndPlayNewLiveStream(channel,liveStream); } _doingChannelChange = false; if (result == LiveStreamResult.Succeeded) { _lastChannelChangeFailed = false; StopRenderBlackImage(); } else { _lastChannelChangeFailed = true; SilentlyStopLiveStream(liveStream); ChannelTuneFailedNotifyUser(result, channel); } } } }
private LiveStreamResult StartAndPlayNewLiveStream(Channel channel,LiveStream liveStream) { LiveStreamResult result = this.ControlAgent.TuneLiveStream(channel, ref liveStream); Log.Debug("ChannelNavigator: start a new live stream, result = {0}", result); if (result == LiveStreamResult.Succeeded) { result = PlayLiveStream(liveStream); if (result == LiveStreamResult.Succeeded) { if (_autoFullScreen) g_Player.ShowFullScreenWindow(); } } return result; }
public override LiveStreamResult TuneLiveStream(Channel channel, CardChannelAllocation upcomingRecordingAllocation, ref LiveStream liveStream) { try { TvDatabase.Channel mpChannel; List <TvDatabase.Card> availableCards = GetCardsForChannel(channel, out mpChannel); // Sort the cards by priority. availableCards.Sort(delegate(TvDatabase.Card c1, TvDatabase.Card c2) { return(c1.Priority.CompareTo(c2.Priority)); }); if (liveStream != null && _liveStreamUsers.ContainsKey(liveStream.RtspUrl)) { IUser tve3User = _liveStreamUsers[liveStream.RtspUrl]; foreach (TvDatabase.Card card in availableCards) { if (card.IdCard == tve3User.CardId) { if (Utility.CardFreeOrUsingSameTransponder(card, mpChannel, tve3User)) { Log("TuneLiveTvStream(): tuning on card {0} {1}", card.IdCard, card.Name); lock (_liveStreamsLock) { _liveStreams[liveStream.RtspUrl].StreamLastAliveTimeUtc = DateTime.UtcNow; } LiveStreamResult result = StartTimeShifting(channel, card, mpChannel, ref tve3User, ref liveStream); if (result != LiveStreamResult.NoFreeCardFound) { return(result); } } } } return(LiveStreamResult.NoRetunePossible); } else { if (liveStream != null) { StopLiveStream(liveStream); liveStream = null; } List <int> inUseHybridGroups = new List <int>(); foreach (TvDatabase.Card card in availableCards) { if (!Utility.IsInSameHybridGroup(card, inUseHybridGroups) && Utility.CardFreeOrUsingSameTransponder(card, mpChannel)) { string userName = String.Format(CultureInfo.InvariantCulture, "{0}{1}", _argusLiveUserName, Guid.NewGuid()); IUser tve3User = new User(userName, true, card.IdCard); tve3User.IdChannel = mpChannel.IdChannel; tve3User.SubChannel = -1; Log("TuneLiveTvStream(): tuning on card {0} {1}", card.IdCard, card.Name); LiveStreamResult result = StartTimeShifting(channel, card, mpChannel, ref tve3User, ref liveStream); if (result != LiveStreamResult.NoFreeCardFound) { return(result); } } // For hybrid cards, keep track of the groups that are in use. inUseHybridGroups.AddRange(Utility.GetHybridGroupIds(card)); } return(LiveStreamResult.NoFreeCardFound); } } catch (Exception ex) { Log(TraceEventType.Error, ex.Message); return(LiveStreamResult.UnknownError); } }
private LiveStreamResult StartAndPlayNewLiveStream(Channel channel,LiveStream liveStream) { var res = Proxies.ControlService.TuneLiveStream(channel, liveStream).Result; liveStream = res.LiveStream; LiveStreamResult result = res.LiveStreamResult; Log.Debug("ChannelNavigator: start a new live stream, result = {0}", result); if (result == LiveStreamResult.Succeeded) { result = PlayLiveStream(liveStream); if (result == LiveStreamResult.Succeeded) { if (_autoFullScreen) g_Player.ShowFullScreenWindow(); } } return result; }
private LiveStreamResult PlayLiveStream(LiveStream liveStream) { Log.Debug("ChannelNavigator: PlayLiveStream()"); LiveStreamResult result = LiveStreamResult.Succeeded; string fileName; bool isRTSP; GetPlayerFileNameAndOffset(liveStream, out fileName, out isRTSP); if (liveStream != null) { _isAnalog = (ControlAgent.GetLiveStreamTuningDetails(liveStream).CardType == CardType.Analog); } if (!isRTSP) { for (int i = 0; i < 10; i++) { if (System.IO.File.Exists(fileName)) { break; } Thread.Sleep(100); Log.Info("Channelnavigator: startplay: waiting for TS file {0}", fileName); } if (!System.IO.File.Exists(fileName)) { result = LiveStreamResult.UnknownError; g_Player.Stop(); } } if (result == LiveStreamResult.Succeeded) { for (int i = 0; i < 50; i++) { if (g_Player.Play(fileName, liveStream.Channel.ChannelType == ChannelType.Television ? g_Player.MediaType.TV : g_Player.MediaType.Radio)) { double duration = g_Player.Duration; if (duration > 0.0) { result = LiveStreamResult.Succeeded; g_Player.SeekAbsolute(duration); _liveStream = liveStream; break; } else { result = LiveStreamResult.UnknownError; g_Player.Stop(); Thread.Sleep(50); Log.Debug("ChannelNavigator: PlayLiveStream_timeout = {0}", i); } } else { result = LiveStreamResult.UnknownError; break; } } } Log.Debug("ChannelNavigator: PlayLiveStream_Result = {0}", result); return(result); }
private void ChannelTuneFailedNotifyUser(LiveStreamResult result, Channel channel) { string TuningResult = string.Empty; switch (result) { case LiveStreamResult.ChannelTuneFailed: TuningResult = (Utility.GetLocalizedText(TextId.ChannelTuneFailed)); break; case LiveStreamResult.NoFreeCardFound: TuningResult = (Utility.GetLocalizedText(TextId.NoFreeCardFound)); break; case LiveStreamResult.NotSupported: TuningResult = (Utility.GetLocalizedText(TextId.NotSupported)); break; case LiveStreamResult.NoRetunePossible: TuningResult = (Utility.GetLocalizedText(TextId.NoRetunePossible)); break; case LiveStreamResult.IsScrambled: TuningResult = (Utility.GetLocalizedText(TextId.IsScrambled)); break; case LiveStreamResult.UnknownError: TuningResult = (Utility.GetLocalizedText(TextId.UnknownError)); break; } if (GUIWindowManager.ActiveWindow == (int)(int)GUIWindow.Window.WINDOW_TVFULLSCREEN) { // If failed and wasPlaying TV, left screen as it is and show zaposd with error message GUIMessage msg = new GUIMessage(GUIMessage.MessageType.GUI_MSG_TV_ERROR_NOTIFY, GUIWindowManager.ActiveWindow, 0, 0, 0, 0, null); msg.SendToTargetWindow = true; msg.Object = TuningResult; // forward error info object msg.TargetWindowId = (int)(int)GUIWindow.Window.WINDOW_TVFULLSCREEN; GUIGraphicsContext.SendMessage(msg); } else { // if not fulscreen, show notify dialog with the error message string caption = string.Empty; string tvlogo = string.Empty; if (channel != null) { _navigatorChannels[_currentChannel.ChannelType].PreviousChannel = channel; _currentChannel = null; using (SchedulerServiceAgent SchedulerAgent = new SchedulerServiceAgent()) { tvlogo = Utility.GetLogoImage(channel, SchedulerAgent); } if (channel.ChannelType == ChannelType.Television) { caption = GUILocalizeStrings.Get(605) + " - " + channel.DisplayName; } else { caption = GUILocalizeStrings.Get(665) + " - " + channel.DisplayName; } } GUIDialogNotify pDlgNotify = (GUIDialogNotify)GUIWindowManager.GetWindow((int)GUIWindow.Window.WINDOW_DIALOG_NOTIFY); if (pDlgNotify != null) { pDlgNotify.Reset(); pDlgNotify.ClearAll(); pDlgNotify.SetHeading(caption); if (!string.IsNullOrEmpty(TuningResult)) { pDlgNotify.SetText(TuningResult); } pDlgNotify.SetImage(tvlogo); pDlgNotify.TimeOut = 5; pDlgNotify.DoModal(GUIWindowManager.ActiveWindow); } } }
private void TuneLiveStream(Channel channel) { Log.Debug("ChannelNavigator: TuneLiveStream(), channel = {0}", channel.DisplayName); if (channel != null) { using (SchedulerServiceAgent tvSchedulerAgent = new SchedulerServiceAgent()) { LiveStream liveStream = _liveStream; CurrentAndNextProgram currentAndNext = tvSchedulerAgent.GetCurrentAndNextForChannel(channel.ChannelId, true, _liveStream);//null); _currentChannel = channel; _doingChannelChange = true; RenderBlackImage(); if (liveStream != null) { try { g_Player.PauseGraph(); g_Player.OnZapping(0x80); result = this.ControlAgent.TuneLiveStream(channel, ref liveStream); Log.Debug("ChannelNavigator: First try to re-tune the existing TV stream (staying on the same card), result = {0}", result); if (result == LiveStreamResult.Succeeded) { if (_isAnalog) { g_Player.OnZapping(-1); } double duration = g_Player.Duration; if (g_Player.Duration < 0.0) { result = LiveStreamResult.UnknownError; } else { g_Player.SeekAbsolute(duration); g_Player.ContinueGraph(); } } else if (result == LiveStreamResult.NoRetunePossible)// not mapped to card, card in use by recorder or other user ---> start new stream { // Now re-try the new channel with a new stream. Log.Debug("ChannelNavigator: Seems a re-tune has failed, stop the current stream and start a new one"); SilentlyStopLiveStream(liveStream); result = StartAndPlayNewLiveStream(channel, liveStream); } } catch { result = LiveStreamResult.UnknownError; Log.Error("ChannelNavigator: TuneLiveStream error"); } } else { result = StartAndPlayNewLiveStream(channel, liveStream); } _doingChannelChange = false; if (result == LiveStreamResult.Succeeded) { _lastChannelChangeFailed = false; StopRenderBlackImage(); } else { _lastChannelChangeFailed = true; SilentlyStopLiveStream(liveStream); ChannelTuneFailedNotifyUser(result, channel); } } } }
public RecorderModule() : base("Recorder") { this.OnError.AddItemToStartOfPipeline((context, ex) => { EventLogger.WriteEntry(ex); return(null); }); // Ping Recorder service. // // Returns the version of the API on the recorder, which should be Constants.RecorderApiVersion. Get["/Ping"] = p => { int result = -1; _staContext.Send((s) => { result = Service.Ping(); }, null); return(new { result = Constants.RecorderApiVersion }); }; // Get the server's MAC address(es). These can be stored on the client after a successful // connect and later used to re-connect with wake-on-lan. // // Returns an array containing one or more MAC addresses in HEX string format (e.g. "A1B2C3D4E5F6"). Get["/MacAddresses"] = p => { List <String> result = null; _staContext.Send((s) => { result = Service.GetMacAddresses(); }, null); return(new { result = result }); }; // Ask the recorder to initialize by registering itself over the Recorder callback's // RegisterRecorder method. // // recorderId - The unique ID of this recorder. // // Post-data is an object with: // schedulerBaseUrl - The callback URL for the Recorder to communicate with the Scheduler. Put["/Initialize/{recorderId}"] = p => { var args = this.Bind <InitializeArguments>(); _staContext.Send((s) => { Service.Initialize(p.recorderId, args.schedulerBaseUrl); }, null); return(HttpStatusCode.OK); }; // Ask the recorder to allocate a (virtual) card for a channel. The previously allocated // cards are also passed in, so the implementation must take into account that these cards // are no longer available when this call is made. Note that the implementation must *not* // worry about cards being actually free at the moment the call is made! This is purely a // theoretical calculation that is used by ARGUS TV to manage its upcoming recordings. // // channel - The channel to allocate. // alreadyAllocated - All previously allocated channels/cards. // useReversePriority - Use reverse cards priority to avoid conflicts with live streaming. // // Returns the unique card ID of the card that can record this channel, or null if no free card was found. Put["/AllocateCard"] = p => { var args = this.Bind <AllocateCardArguments>(); string result = null; _staContext.Send((s) => { result = Service.AllocateCard(args.channel, args.alreadyAllocated, args.useReversePriority); }, null); return(new { result = result }); }; // Tell the recorder to actually start a recording on the given card. The implementation // must call /NewRecording on the Recorder callback service when the recording actually // starts. If the recording can't start for some reason /Recording/StartFailed must be called. // In case the recording ends (prematurely or on time) /EndRecording must be called. // IMPORTANT: If the suggested relative path and filename was used the recorder should // return 'false' to /EndRecording's 'okToMoveFile'! // // Post-data is an object with: // schedulerBaseUrl - The callback URL for the Recorder to communicate with the Scheduler. // channelAllocation - The card allocation for the channel. // startTimeUtc - The actual time to start the recording (UTC). // stopTimeUtc - The actual time to stop the recording (UTC). // recordingProgram - The program to record. // suggestedBaseFileName - The suggested relative path and filename (without extension) of the recording file. // // Returns a boolean indicating the recording was initiated succesfully. Post["/Recording/Start"] = p => { var args = this.Bind <StartRecordingArguments>(); bool result = false; _staContext.Send((s) => { result = Service.StartRecording(args.schedulerBaseUrl, args.channelAllocation, args.startTimeUtc, args.stopTimeUtc, args.recordingProgram, args.suggestedBaseFileName); }, null); return(new { result = result }); }; // Validate a recording is still running, and update its actual stop time. // // Post-data is an object with: // channelAllocation - The card allocation for the channel. // recordingProgram - The program being recorded. // stopTimeUtc - The up-to-date stop time (UTC). // // Returns true if the recording was still running (and its stop time was succesfully updated), false if there was a problem or the recording is not running. Put["/Recording/ValidateAndUpdate"] = p => { var args = this.Bind <ValidateAndUpdateRecordingArguments>(); bool result = false; _staContext.Send((s) => { result = Service.ValidateAndUpdateRecording(args.channelAllocation, args.recordingProgram, args.stopTimeUtc); }, null); return(new { result = result }); }; // Tell the recorder to abort the recording of a program. The implementation must call // EndRecording() on the Recorder callback service. // // Post-data is an object with: // schedulerBaseUrl - The callback URL for the Recorder to communicate with the Scheduler. // recordingProgram - The program being recorded. // // Returns true if the recording was found and aborted. Put["/Recording/Abort"] = p => { var args = this.Bind <AbortRecordingArguments>(); bool result = false; _staContext.Send((s) => { result = Service.AbortRecording(args.schedulerBaseUrl, args.recordingProgram); }, null); return(new { result = result }); }; // Retrieves the recording shares of the recorder. Get["/RecordingShares"] = p => { List <string> result = null; _staContext.Send((s) => { result = Service.GetRecordingShares(); }, null); return(new { result = result }); }; // Retrieves the timeshift shares of the recorder. Get["/TimeshiftShares"] = p => { List <string> result = null; _staContext.Send((s) => { result = Service.GetTimeshiftShares(); }, null); return(new { result = result }); }; #region Live Streaming // Tune to a channel, and get a live stream to that channel. // // Post-data is an object with: // channel - The channel to tune to. // upcomingRecordingAllocation - The allocation of the next upcoming recording, or null if there isn't one. // stream - The live stream in case of retuning an existing stream, or null for a new one. // // Returns a LiveStreamResult value to indicate success or failure. Post["/Live/Tune"] = p => { var args = this.Bind <TuneLiveStreamArguments>(); var stream = args.stream; LiveStreamResult result = LiveStreamResult.UnknownError; _staContext.Send((s) => { result = Service.TuneLiveStream(args.channel, args.upcomingRecordingAllocation, ref stream); }, null); return(new { result = result, stream = stream }); }; // Tell the recorder we are still showing this stream and to keep it alive. Call this every 30 seconds or so. // // Post-data is the live stream that is stil in use. // // Returns true if the live stream is still running, false otherwise. Put["/Live/KeepAlive"] = p => { var stream = this.Bind <LiveStream>(); bool result = false; _staContext.Send((s) => { result = Service.KeepLiveStreamAlive(stream); }, null); return(new { result = result }); }; // Stop the live stream (if it is found and belongs to the recorder). // // Post-data is the live stream to stop. Put["/Live/Stop"] = p => { var stream = this.Bind <LiveStream>(); _staContext.Send((s) => { Service.StopLiveStream(stream); }, null); return(HttpStatusCode.OK); }; // Get all live streams. Get["/LiveStreams"] = p => { return(new { result = Service.GetLiveStreams() }); }; // Get the live tuning state of a number of channels. // // Post-data is an object with: // channels - The channels to get the live state from. // stream - The live stream you want to be ignored (since it's yours), or null. // // Returns an array with all the live states for the given channels. Put["/ChannelsLiveState"] = p => { var args = this.Bind <GetChannelsLiveStateArguments>(); return(new { result = Service.GetChannelsLiveState(args.channels, args.stream) }); }; // Ask the recorder for the give live stream's tuning details (if possible). // // Post-data is the active live stream. // // Returns the service tuning details, or null if none are available. Put["/Live/TuningDetails"] = p => { var stream = this.Bind <LiveStream>(); ServiceTuning result = null; _staContext.Send((s) => { result = Service.GetLiveStreamTuningDetails(stream); }, null); return(new { result = result }); }; #endregion #region Teletext // Ask the recorder whether the given liveStream has teletext. // // Post-data is the live stream. // // Returns true if teletext is present. Put["/Live/HasTeletext"] = p => { var stream = this.Bind <LiveStream>(); bool result = false; _staContext.Send((s) => { result = Service.HasTeletext(stream); }, null); return(new { result = result }); }; // Tell the recorder to start grabbing teletext for the given live stream. // // Post-data is the live stream. Put["/Live/Teletext/StartGrabbing"] = p => { var stream = this.Bind <LiveStream>(); _staContext.Send((s) => { Service.StartGrabbingTeletext(stream); }, null); return(HttpStatusCode.OK); }; // Tell the recorder to stop grabbing teletext for the given live stream. // // Post-data is the live stream. Put["/Live/Teletext/StopGrabbing"] = p => { var stream = this.Bind <LiveStream>(); _staContext.Send((s) => { Service.StopGrabbingTeletext(stream); }, null); return(HttpStatusCode.OK); }; // Tell the recorder to start grabbing teletext for the given live stream. // // Post-data is the live stream. // // Returns true if the recorder is grabbing teletext. Put["/Live/Teletext/IsGrabbing"] = p => { var stream = this.Bind <LiveStream>(); bool result = false; _staContext.Send((s) => { result = Service.IsGrabbingTeletext(stream); }, null); return(new { result = result }); }; // Request a teletext page/subpage from the recorder for the given live stream. // // pageNumber - The teletext page number. // subPageNumber - The teletext subpage number. // // Post-data is the live stream. // // Returns an object with: // result - The requested page content (base64-encoded), or null if the page was not ready yet. // subPageCount - The total number of subpages of this page. Put["/Live/Teletext/GetPage/{pageNumber}/{subPageNumber}"] = p => { var stream = this.Bind <LiveStream>(); int subPageCount = 0; byte[] result = null; _staContext.Send((s) => { result = Service.GetTeletextPageBytes(stream, p.pageNumber, p.subPageNumber, out subPageCount); }, null); return(new { result = result == null ? null : Convert.ToBase64String(result, Base64FormattingOptions.None), subPageCount = subPageCount }); }; #endregion }