private void CallAddNewRecording(RecorderCallbackProxy callbackProxy, DateTime actualStartTimeUtc) { WriteLog("RecordingThread [{0}]: Calling AddNewRecording()", _recordingProgram.CreateProgramTitle()); try { callbackProxy.AddNewRecording(_recordingProgram, actualStartTimeUtc, this.RecordingFileName).Wait(); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
private void CallStartRecordingFailed(RecorderCallbackProxy callbackProxy, string reason) { WriteLog("RecordingThread [{0}]: Calling StartRecordingFailed(Reason=\"{1}\")", _recordingProgram.CreateProgramTitle(), reason); try { callbackProxy.StartRecordingFailed(_channelAllocation, _recordingProgram, reason).Wait(); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
protected override bool OnStopRecording(RecorderCallbackProxy proxy, bool abort) { if (_tve3User != null) { if (StopMediaPortalRecording(_tve3User)) { _tve3User = null; return(true); } } return(false); }
protected override bool OnPrepareRecording(RecorderCallbackProxy proxy, ref string errorMessage) { DeleteAllMediaPortalSchedules(); string userName = String.Format(CultureInfo.InvariantCulture, "ArgusTV{0}", Thread.CurrentThread.ManagedThreadId); _tve3User = new User(userName, true, _recordOnCard.IdCard); _tve3User.IdChannel = _channel.IdChannel; _tve3User.SubChannel = -1; bool argusIsRecordingOnCard; return(EnsureCardFree(true, ref errorMessage, out argusIsRecordingOnCard)); }
private void CallEndRecording(RecorderCallbackProxy callbackProxy, DateTime actualStartTimeUtc, DateTime actualStopTimeUtc) { bool isPartial = (actualStartTimeUtc > _recordingProgram.StartTimeUtc.AddSeconds(30)) || (actualStopTimeUtc < _recordingProgram.StopTimeUtc.AddSeconds(-30)); WriteLog("RecordingThread [{0}]: Calling EndRecording(IsPartial={1})", _recordingProgram.CreateProgramTitle(), isPartial); try { callbackProxy.EndRecording(this.RecordingFileName, actualStopTimeUtc, isPartial, !_usedSuggestedBaseFileName).Wait(); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
abstract protected bool OnPrepareRecording(RecorderCallbackProxy callbackProxy, ref string errorMessage);
protected override string OnStartRecording(RecorderCallbackProxy proxy, ref string errorMessage) { string baseFileName = _suggestedBaseFileName; if (String.IsNullOrEmpty(baseFileName)) { baseFileName = FileUtility.BuildRecordingBaseFileName(null, this.RecordingProgram); } else { this.UsedSuggestedBaseFileName = true; } string fileName = Path.Combine(_recordOnCard.RecordingFolder, baseFileName); string extension = (_recordOnCard.RecordingFormat == 0) ? ".ts" : ".mpg"; _tve3RecordingFileName = FileUtility.GetFreeFileName(fileName, extension); string tve3RecordingDirectory = Path.GetDirectoryName(_tve3RecordingFileName); if (!Directory.Exists(tve3RecordingDirectory)) { Directory.CreateDirectory(tve3RecordingDirectory); } string uncRecordingFolder = Common.ShareExplorer.GetUncPathForLocalPath(tve3RecordingDirectory); if (String.IsNullOrEmpty(uncRecordingFolder)) { errorMessage = "Failed to convert '" + Path.GetDirectoryName(_tve3RecordingFileName) + "' to UNC path, please add required share"; return(null); } bool argusIsRecordingOnCard; if (!EnsureCardFree(false, ref errorMessage, out argusIsRecordingOnCard)) { if (!WaitCardFree(argusIsRecordingOnCard, ref errorMessage)) { return(null); } } IChannel tuningChannel = Utility.FindTuningChannelOnCard(_channel, _recordOnCard.IdCard); if (tuningChannel == null) { errorMessage = "Failed to find tuning details for channel " + _channel.DisplayName; return(null); } // Make sure only one thread can tune and start a recording at the same time. lock (_startRecordingLock) { if (TvServerPlugin.TvController_Tune(ref _tve3User, tuningChannel, _channel.IdChannel) != TvResult.Succeeded) { errorMessage = "Failed to tune to channel " + _channel.DisplayName; return(null); } if (TvServerPlugin.TvController_StartRecording(ref _tve3User, ref _tve3RecordingFileName) != TvResult.Succeeded) { errorMessage = "TV Server failed to start recording on channel " + _channel.DisplayName; return(null); } } return(Path.Combine(uncRecordingFolder, Path.GetFileName(_tve3RecordingFileName))); }
abstract protected bool OnStopRecording(RecorderCallbackProxy callbackProxy, bool abort);
protected override void Run() { var callbackProxy = new RecorderCallbackProxy(_schedulerBaseUrl); try { SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_AWAYMODE_REQUIRED); if (this.StopTimeUtc <= DateTime.UtcNow || _startTimeUtc >= this.StopTimeUtc) { CallStartRecordingFailed(callbackProxy, String.Format(CultureInfo.InvariantCulture, "Recording of {0} at {1} for {2} has invalid timing parameters.", _channelAllocation.ChannelName, _startTimeUtc.ToLocalTime().ToShortTimeString(), this.StopTimeUtc.Subtract(_startTimeUtc))); return; } if (_waitForThreadToComplete != null) { _waitForThreadToComplete.Join(); } bool aborted = false; _usedSuggestedBaseFileName = !_okToRenameRecordedFiles; // First of all make sure the recorder is tuned to the correct channel. string errorMessage = null; if (!OnPrepareRecording(callbackProxy, ref errorMessage)) { CallStartRecordingFailed(callbackProxy, errorMessage); OnError(); aborted = true; } DateTime actualStartTimeUtc = DateTime.MaxValue; if (!aborted) { // Now wait for the actual start-time try { TimeSpan delay = _startTimeUtc.AddSeconds(-1) - DateTime.UtcNow; if (delay.TotalMilliseconds > 0) { aborted = this.StopThreadEvent.WaitOne((int)delay.TotalMilliseconds, false); } if (!aborted) { errorMessage = null; this.RecordingFileName = OnStartRecording(callbackProxy, ref errorMessage); if (String.IsNullOrEmpty(this.RecordingFileName)) { CallStartRecordingFailed(callbackProxy, errorMessage); OnError(); aborted = true; } else { this.ActualRecordingFileName = ShareExplorer.TryConvertUncToLocal(this.RecordingFileName); actualStartTimeUtc = DateTime.UtcNow; CallAddNewRecording(callbackProxy, actualStartTimeUtc); } } } catch (Exception e) { CallStartRecordingFailed(callbackProxy, e.Message); OnError(); aborted = true; } } if (!aborted) { TimeSpan?checkerInterval = this.FileSizeCheckerInterval; if (!checkerInterval.HasValue) { checkerInterval = TimeSpan.MaxValue; } _fileSizeChecker = new FileSizeChecker(this.ActualRecordingFileName, checkerInterval.Value); while (!aborted && DateTime.UtcNow < this.StopTimeUtc) { TimeSpan interval = this.CheckRecordingActiveInterval; TimeSpan timeToEnd = this.StopTimeUtc.AddMilliseconds(1) - DateTime.UtcNow; if (timeToEnd < interval) { interval = timeToEnd; } aborted = this.StopThreadEvent.WaitOne(interval, false); } if (aborted) { WriteLog(TraceEventType.Warning, "RecordingThread [{0}]: Aborted", _recordingProgram.CreateProgramTitle()); } if (!OnStopRecording(callbackProxy, aborted)) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: Failed to stop recording", _recordingProgram.CreateProgramTitle()); try { callbackProxy.LogMessage(this.RecorderId, LogSeverity.Error, "Failed to stop recording " + _recordingProgram.CreateProgramTitle()); } catch { } } CallEndRecording(callbackProxy, actualStartTimeUtc, DateTime.UtcNow); } } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); try { callbackProxy.LogMessage(this.RecorderId, LogSeverity.Error, "Exception: " + ex.Message); } catch { } OnError(); } finally { SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); } OnThreadEnding(); }
abstract protected string OnStartRecording(RecorderCallbackProxy callbackProxy, ref string errorMessage);
protected override void Run() { var callbackProxy = new RecorderCallbackProxy(_schedulerBaseUrl); try { SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_AWAYMODE_REQUIRED); if (this.StopTimeUtc <= DateTime.UtcNow || _startTimeUtc >= this.StopTimeUtc) { CallStartRecordingFailed(callbackProxy, String.Format(CultureInfo.InvariantCulture, "Recording of {0} at {1} for {2} has invalid timing parameters.", _channelAllocation.ChannelName, _startTimeUtc.ToLocalTime().ToShortTimeString(), this.StopTimeUtc.Subtract(_startTimeUtc))); return; } if (_waitForThreadToComplete != null) { _waitForThreadToComplete.Join(); } bool aborted = false; _usedSuggestedBaseFileName = !_okToRenameRecordedFiles; // First of all make sure the recorder is tuned to the correct channel. string errorMessage = null; if (!OnPrepareRecording(callbackProxy, ref errorMessage)) { CallStartRecordingFailed(callbackProxy, errorMessage); OnError(); aborted = true; } DateTime actualStartTimeUtc = DateTime.MaxValue; if (!aborted) { // Now wait for the actual start-time try { TimeSpan delay = _startTimeUtc.AddSeconds(-1) - DateTime.UtcNow; if (delay.TotalMilliseconds > 0) { aborted = this.StopThreadEvent.WaitOne((int)delay.TotalMilliseconds, false); } if (!aborted) { errorMessage = null; this.RecordingFileName = OnStartRecording(callbackProxy, ref errorMessage); if (String.IsNullOrEmpty(this.RecordingFileName)) { CallStartRecordingFailed(callbackProxy, errorMessage); OnError(); aborted = true; } else { this.ActualRecordingFileName = ShareExplorer.TryConvertUncToLocal(this.RecordingFileName); actualStartTimeUtc = DateTime.UtcNow; CallAddNewRecording(callbackProxy, actualStartTimeUtc); } } } catch (Exception e) { CallStartRecordingFailed(callbackProxy, e.Message); OnError(); aborted = true; } } if (!aborted) { TimeSpan? checkerInterval = this.FileSizeCheckerInterval; if (!checkerInterval.HasValue) { checkerInterval = TimeSpan.MaxValue; } _fileSizeChecker = new FileSizeChecker(this.ActualRecordingFileName, checkerInterval.Value); while (!aborted && DateTime.UtcNow < this.StopTimeUtc) { TimeSpan interval = this.CheckRecordingActiveInterval; TimeSpan timeToEnd = this.StopTimeUtc.AddMilliseconds(1) - DateTime.UtcNow; if (timeToEnd < interval) { interval = timeToEnd; } aborted = this.StopThreadEvent.WaitOne(interval, false); } if (aborted) { WriteLog(TraceEventType.Warning, "RecordingThread [{0}]: Aborted", _recordingProgram.CreateProgramTitle()); } if (!OnStopRecording(callbackProxy, aborted)) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: Failed to stop recording", _recordingProgram.CreateProgramTitle()); try { callbackProxy.LogMessage(this.RecorderId, LogSeverity.Error, "Failed to stop recording " + _recordingProgram.CreateProgramTitle()); } catch { } } CallEndRecording(callbackProxy, actualStartTimeUtc, DateTime.UtcNow); } } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); try { callbackProxy.LogMessage(this.RecorderId, LogSeverity.Error, "Exception: " + ex.Message); } catch { } OnError(); } finally { SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); } OnThreadEnding(); }