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);