protected override string OnStartRecording(RecorderCallbackServiceAgent callbackAgent, ref string errorMessage) { string baseFileName = _suggestedBaseFileName; if (String.IsNullOrEmpty(baseFileName)) { baseFileName = Common.Utility.BuildRecordingBaseFileName(null, this.RecordingProgram); } else { this.UsedSuggestedBaseFileName = true; } string fileName = Path.Combine(_recordOnCard.RecordingFolder, baseFileName); string extension = (_recordOnCard.RecordingFormat == 0) ? ".ts" : ".mpg"; _tve3RecordingFileName = Common.Utility.GetFreeFileName(fileName, extension, 0); 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, false, 0) != TvResult.Succeeded) { errorMessage = "TV Server failed to start recording on channel " + _channel.DisplayName; return null; } } return Path.Combine(uncRecordingFolder, Path.GetFileName(_tve3RecordingFileName)); }
protected override bool OnStopRecording(RecorderCallbackServiceAgent callbackAgent, bool abort) { if (_tve3User != null) { if (StopMediaPortalRecording(_tve3User)) { _tve3User = null; return true; } } return false; }
/// <summary> /// /// </summary> /// <returns></returns> private bool Finish() { // Check recording if (DateTime.UtcNow < m_program.StopTimeUtc) m_incomplete = true; // Release device ReleaseDevice(); // Report to scheduler using (var sink = new RecorderCallbackServiceAgent( m_schedulerHost, m_schedulerPort )) sink.EndRecording( m_recordingPath, DateTime.UtcNow, m_incomplete, true ); // Done return false; }
protected override bool OnPrepareRecording(RecorderCallbackServiceAgent callbackAgent, 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); }
/// <summary> /// Prüft die Eingangsdaten. /// </summary> /// <returns>Gesetzt, wenn weitere Aktionen notwendig sind.</returns> private bool Validate() { // Validation phase try { // Check times if (m_originalEndTime < m_startTime) throw new InvalidOperationException( "ends before start" ); // Load the device m_device = m_service.Devices[m_allocation.CardId]; if (m_device == null) throw new InvalidOperationException( "bad device name" ); // Find the possible sources m_sources = m_device.Resolve( m_allocation.ChannelName ); if (m_sources == null) throw new InvalidOperationException( "no such channel" ); // Prepare next step m_run = Start; // When we should go for it NextTime = m_startTime; // If we are overdue just start immediately return (NextTime <= DateTime.UtcNow) ? Run() : true; } catch (Exception e) { // Report to scheduler using (var sink = new RecorderCallbackServiceAgent( m_schedulerHost, m_schedulerPort )) sink.StartRecordingFailed( m_allocation, m_program, e.Message ); // No further error processing required return false; } }
/// <summary> /// Startet die Aufzeichnung, sobald dies möglich ist. /// </summary> /// <returns>Gesetzt, wenn weitere asynchrone Operationen notwendig sind.</returns> private bool Start() { // Pnly if we are not already done if (DateTime.UtcNow < CurrentEndTime) { // Try to allocate the device m_streamIdentifier = m_device.Start( m_sources, m_recordingPath ); // Not possible if (!m_streamIdentifier.HasValue) { // Fast retest NextTime = DateTime.UtcNow.AddSeconds( 1 ); // Again return true; } // Check recording if (DateTime.UtcNow > m_program.StartTimeUtc) m_incomplete = true; // Be safe try { // Report to scheduler using (var sink = new RecorderCallbackServiceAgent( m_schedulerHost, m_schedulerPort )) sink.AddNewRecording( m_program, DateTime.UtcNow, m_recordingPath ); } catch (Exception) { // Release device ReleaseDevice(); // Forward throw; } } // Prepare next step m_run = Finish; // When we should go for it NextTime = CurrentEndTime; // If we are overdue just start immediately return (NextTime <= DateTime.UtcNow) ? Run() : true; }
public virtual void Initialize(Guid recorderTunerId, string serverHostName, int tcpPort) { _recorderTunerId = recorderTunerId; using (RecorderCallbackServiceAgent agent = new RecorderCallbackServiceAgent(serverHostName, tcpPort)) { agent.RegisterRecorderTuner(this.RecorderTunerId, this.Name, Assembly.GetCallingAssembly().GetName().Version.ToString()); } }
/// <summary> /// Fordert den Dienst zur Anmeldung auf. /// </summary> /// <param name="recorderTunerId">Die eindeutige Kennung dieses Dienstes.</param> /// <param name="serverHostName">Der Name des Steuerrechners.</param> /// <param name="tcpPort">Die Adresse des Steuerdienstes.</param> public void Initialize( Guid recorderTunerId, string serverHostName, int tcpPort ) { // Remember Identifier = recorderTunerId; // Process callback using (var agent = new RecorderCallbackServiceAgent( serverHostName, tcpPort )) agent.RegisterRecorderTuner( Identifier, Name, GetType().Assembly.GetName().Version.ToString() ); }
private void CallEndRecording(RecorderCallbackServiceAgent callbackAgent, 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 { callbackAgent.EndRecording(this.RecordingFileName, actualStopTimeUtc, isPartial, !_usedSuggestedBaseFileName); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
private void CallStartRecordingFailed(RecorderCallbackServiceAgent callbackAgent, string reason) { WriteLog("RecordingThread [{0}]: Calling StartRecordingFailed(Reason=\"{1}\")", _recordingProgram.CreateProgramTitle(), reason); try { callbackAgent.StartRecordingFailed(_channelAllocation, _recordingProgram, reason); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
private void CallAddNewRecording(RecorderCallbackServiceAgent callbackAgent, DateTime actualStartTimeUtc) { WriteLog("RecordingThread [{0}]: Calling AddNewRecording()", _recordingProgram.CreateProgramTitle()); try { callbackAgent.AddNewRecording(_recordingProgram, actualStartTimeUtc, this.RecordingFileName); } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); } }
protected override void Run() { using (RecorderCallbackServiceAgent callbackAgent = new RecorderCallbackServiceAgent(_serverHostName, _serverTcpPort)) { 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(callbackAgent, 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(callbackAgent, ref errorMessage)) { CallStartRecordingFailed(callbackAgent, 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(callbackAgent, ref errorMessage); if (String.IsNullOrEmpty(this.RecordingFileName)) { CallStartRecordingFailed(callbackAgent, errorMessage); OnError(); aborted = true; } else { this.ActualRecordingFileName = ShareExplorer.TryConvertUncToLocal(this.RecordingFileName); actualStartTimeUtc = DateTime.UtcNow; CallAddNewRecording(callbackAgent, actualStartTimeUtc); } } } catch (Exception e) { CallStartRecordingFailed(callbackAgent, 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(callbackAgent, aborted)) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: Failed to stop recording", _recordingProgram.CreateProgramTitle()); try { callbackAgent.LogMessage(this.RecorderTunerId, LogSeverity.Error, "Failed to stop recording " + _recordingProgram.CreateProgramTitle()); } catch { } } CallEndRecording(callbackAgent, actualStartTimeUtc, DateTime.UtcNow); } } catch (Exception ex) { WriteLog(TraceEventType.Error, "RecordingThread [{0}]: {1}", _recordingProgram.CreateProgramTitle(), ex.Message); try { callbackAgent.LogMessage(this.RecorderTunerId, LogSeverity.Error, "Exception: " + ex.Message); } catch { } OnError(); } finally { SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); } } OnThreadEnding(); }
protected abstract bool OnStopRecording(RecorderCallbackServiceAgent callbackAgent, bool abort);
protected abstract string OnStartRecording(RecorderCallbackServiceAgent callbackAgent, ref string errorMessage);
protected abstract bool OnPrepareRecording(RecorderCallbackServiceAgent callbackAgent, ref string errorMessage);