/// <summary>
    /// Build the graph.
    /// </summary>
    public override void BuildGraph()
    {
      try
      {
        if (_graphState != GraphState.Idle)
        {
          Log.Log.Info("DRI CC: device already initialised");
          return;
        }

        bool useKeepAlive = !_isCetonDevice;
        Log.Log.Info("DRI CC: connect to device, keep-alive = {0}", useKeepAlive);
        _deviceConnection = _controlPoint.Connect(_descriptor.RootDescriptor, _descriptor.DeviceUUID, ResolveDataType, useKeepAlive);

        // services
        Log.Log.Debug("DRI CC: setup services");
        _tunerService = new TunerService(_deviceConnection.Device);
        _fdcService = new FdcService(_deviceConnection.Device);
        _auxService = new AuxService(_deviceConnection.Device);
        _encoderService = new EncoderService(_deviceConnection.Device);
        _casService = new CasService(_deviceConnection.Device);
        _muxService = new MuxService(_deviceConnection.Device);
        _securityService = new SecurityService(_deviceConnection.Device);
        _diagService = new DiagService(_deviceConnection.Device);
        _avTransportService = new AvTransportService(_deviceConnection.Device);
        _connectionManagerService = new ConnectionManagerService(_deviceConnection.Device);

        Log.Log.Debug("DRI CC: subscribe services");
        _stateVariableDelegate = new StateVariableChangedDlgt(OnStateVariableChanged);
        _tunerService.SubscribeStateVariables(_stateVariableDelegate);
        _auxService.SubscribeStateVariables(_stateVariableDelegate);
        _encoderService.SubscribeStateVariables(_stateVariableDelegate);
        _casService.SubscribeStateVariables(_stateVariableDelegate);
        _securityService.SubscribeStateVariables(_stateVariableDelegate);
        _avTransportService.SubscribeStateVariables(_stateVariableDelegate);
        _connectionManagerService.SubscribeStateVariables(_stateVariableDelegate);

        // Give time for the device to notify us about initial state variable values.
        // Attempting to continue with other actions now can overload the puny device
        // processors.
        Thread.Sleep(2000);

        int rcsId = -1;
        _connectionManagerService.PrepareForConnection(string.Empty, string.Empty, -1, UpnpConnectionDirection.Output, out _connectionId, out _avTransportId, out rcsId);
        Log.Log.Debug("DRI CC: PrepareForConnection, connection ID = {0}, AV transport ID = {1}", _connectionId, _avTransportId);

        // Check that the device is not already in use.
        if (IsTunerInUse())
        {
          throw new TvExceptionGraphBuildingFailed("DRI CC: tuner appears to be in use");
        }

        ReadDeviceInfo();

        Log.Log.Info("DRI CC: build graph");
        _graphBuilder = (IFilterGraph2)new FilterGraph();
        _capBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        _capBuilder.SetFiltergraph(_graphBuilder);
        _rotEntry = new DsROTEntry(_graphBuilder);
        AddTsWriterFilterToGraph();
        AddStreamSourceFilter();

        // This shouldn't be required, but it enables us to reuse TvCardDvbBase
        // and use CI menus for delivering messages from the CableCARD to the
        // user.
        _conditionalAccess = new ConditionalAccess(null, null, null, this);

        _graphState = GraphState.Created;
      }
      catch (Exception)
      {
        Dispose();
        throw;
      }
    }
    public override void Dispose()
    {
      if (_eventSignalLock != null)
      {
        _eventSignalLock.Close();
        _eventSignalLock = null;
      }

      base.Dispose();

      RemoveStreamSourceFilter();
      if (_mpeg2TransportStream != null)
      {
        DsUtils.FreeAMMediaType(_mpeg2TransportStream);
        _mpeg2TransportStream = null;
      }
      if (_tunerService != null)
      {
        _tunerService.Dispose();
        _tunerService = null;
      }
      if (_fdcService != null)
      {
        _fdcService.Dispose();
        _fdcService = null;
      }
      if (_auxService != null)
      {
        _auxService.Dispose();
        _auxService = null;
      }
      if (_encoderService != null)
      {
        _encoderService.Dispose();
        _encoderService = null;
      }
      if (_casService != null)
      {
        _casService.Dispose();
        _casService = null;
      }
      if (_muxService != null)
      {
        _muxService.Dispose();
        _muxService = null;
      }
      if (_securityService != null)
      {
        _securityService.Dispose();
        _securityService = null;
      }
      if (_diagService != null)
      {
        _diagService.Dispose();
        _diagService = null;
      }
      if (_avTransportService != null)
      {
        if (_gotTunerControl && _transportState != UpnpAvTransportState.STOPPED)
        {
          _avTransportService.Stop((uint)_avTransportId);
          _transportState = UpnpAvTransportState.STOPPED;
        }
        _avTransportService.Dispose();
        _avTransportService = null;
      }
      if (_connectionManagerService != null)
      {
        _connectionManagerService.ConnectionComplete(_connectionId);
        _connectionManagerService.Dispose();
        _connectionManagerService = null;
      }

      if (_deviceConnection != null)
      {
        _deviceConnection.Disconnect();
        _deviceConnection = null;
      }
      _gotTunerControl = false;
    }