Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ffi-hdhomerun / lib / ffi / hdhomerun.rb
Size: Mime:
require 'ffi'
require 'ipaddr'

module FFI # :nodoc:
  module HDHomeRun
    extend FFI::Library
    ffi_lib ['hdhomerun', 'libhdhomerun.so.1']

    VIDEO_DATA_BUFFER_SIZE_1S = (20000000 / 8)
    DEVICE_TYPE_TUNER  = 0x00000001
    DEVICE_ID_WILDCARD = 0xFFFFFFFF

    attach_function :create_from_str, 
                    :hdhomerun_device_create_from_str, 
                    [:string, :pointer],
                    :pointer
  
    attach_function :get_device_id_requested,
                    :hdhomerun_device_get_device_id_requested, 
                    [:pointer],
                    :uint
  
    attach_function :validate_device_id,
                    :hdhomerun_discover_validate_device_id,
                    [:uint],
                    :int
  
    attach_function :get_model_str,
                    :hdhomerun_device_get_model_str,
                    [:pointer],
                    :string
  
    attach_function :get_var,
                    :hdhomerun_device_get_var,
                    [:pointer, :string, :pointer, :pointer],
                    :int
  
    attach_function :set_var,
                    :hdhomerun_device_set_var,
                    [:pointer, :string, :string, :pointer, :pointer],
                    :int
  
    attach_function :set_tuner_from_str, 
                    :hdhomerun_device_set_tuner_from_str, 
                    [:pointer, :string],
                    :int
  
    attach_function :stream_start,
                    :hdhomerun_device_stream_start,
                    [:pointer],
                    :int
  
    attach_function :stream_stop,
                    :hdhomerun_device_stream_stop,
                    [:pointer],
                    :void
  
    attach_function :stream_recv,
                    :hdhomerun_device_stream_recv,
                    [:pointer, :ulong, :pointer],
                    :pointer
  
    attach_function :get_video_stats,
                    :hdhomerun_device_get_video_stats, 
                    [:pointer, :pointer],
                    :void

    attach_function :discover_find_devices_custom,
                    :hdhomerun_discover_find_devices_custom,
                    [ :uint32, :uint32, :uint32, :pointer, :int ],
                    :int

    attach_function :lockkey_use_value,
                    :hdhomerun_device_tuner_lockkey_use_value,
                    [:pointer, :ulong],
                    :void
    
    attach_function :destroy,
                    :hdhomerun_device_destroy,
                    [:pointer],
                    :void
    
    attach_function :lock,
                    :hdhomerun_device_tuner_lockkey_request,
                    [:pointer, :string],
                    :int
    
    attach_function :set_tuner_target,
                    :hdhomerun_device_set_tuner_target,
                    [:pointer, :pointer],
                    :int
    
    attach_function :get_tuner_channelmap,
                    :hdhomerun_device_get_tuner_channelmap,
                    [:pointer, :pointer],
                    :int
    
    attach_function :get_channelmap_scan_group,
                    :hdhomerun_channelmap_get_channelmap_scan_group,
                    [:pointer],
                    :string
    
    attach_function :channelscan_init,
                    :hdhomerun_device_channelscan_init,
                    [:pointer, :pointer],
                    :int
    
    attach_function :channelscan_advance,
                    :hdhomerun_device_channelscan_advance,
                    [:pointer, :pointer],
                    :int
    
    attach_function :channelscan_detect,
                    :hdhomerun_device_channelscan_detect,
                    [:pointer, :pointer],
                    :int
    
    attach_function :unlock,
                    :hdhomerun_device_tuner_lockkey_release,
                    [:pointer],
                    :int
    
    attach_function :get_tuner_status,
                    :hdhomerun_device_get_tuner_status,
                    [:pointer, :pointer, :pointer],
                    :int
    
    attach_function :get_tuner_streaminfo,
                    :hdhomerun_device_get_tuner_streaminfo,
                    [:pointer, :pointer],
                    :int
    
    attach_function :get_tuner_program,
                    :hdhomerun_device_get_tuner_program,
                    [:pointer, :pointer],
                    :int
    
    attach_function :set_tuner_program,
                    :hdhomerun_device_set_tuner_program,
                    [:pointer, :string],
                    :int
    
    attach_function :channel_list_create,
                    :hdhomerun_channel_list_create,
                    [:string],
                    :pointer
    
    attach_function :channel_list_first,
                    :hdhomerun_channel_list_first,
                    [:pointer],
                    :pointer
    
    attach_function :channel_list_last,
                    :hdhomerun_channel_list_last,
                    [:pointer],
                    :pointer
    
    attach_function :channel_list_next,
                    :hdhomerun_channel_list_next,
                    [:pointer, :pointer],
                    :pointer
    
    attach_function :channel_list_prev,
                    :hdhomerun_channel_list_prev,
                    [:pointer, :pointer],
                    :pointer
    
    class ChannelEntry < FFI::Struct
      layout :next, :pointer,
             :prev, :pointer,
             :frequency, :uint32,
             :channel_number, :uint16,
             :name, [:char, 16]
      
      def to_s
        "#{frequency} #{channel_number} #{name}"
      end
      
      %w{frequency channel_number name}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end
    end
    
    class ChannelList < FFI::Struct
      layout :head, :pointer,
             :tail, :pointer
    end
    
    ##
    # HDHomeRun status for channel scan
    # 
    # Has the following fields:
    # * +channel+
    # * +modulation_type+
    # * +signal_strength+
    # * +signal_to_noise+
    # * +symbol_error_rate+
    # * +bits_per_second+
    # * +packets_per_second+
    class Status < FFI::Struct
      layout  :channel, [:char, 32],
              :modulation_type, [:char, 32],
              :signal_present, :int,
              :lock_supported, :int,
              :lock_unsupported, :int,
              :signal_strength, :uint,
              :signal_to_noise, :uint,
              :symbol_error_rate, :uint,
              :bits_per_second, :uint32,
              :packets_per_second, :uint32
      
      def to_s
        "LOCK: #{modulation_type} (ss=#{signal_strength} snq=#{signal_to_noise} seq=#{symbol_error_rate})"
      end
    
      %w{modulation_type signal_strength signal_to_noise symbol_error_rate bits_per_second packets_per_second}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end
      
      ##
      # Is there a signal present?
      def signal?
        return self[:signal_present] == 1
      end
    end
  
    class Program < FFI::Struct
      layout  :string, [:char, 64],
              :number, :uint16,
              :major, :uint16,
              :minor, :uint16,
              :type, :uint16,
              :name, [:char, 32]
      
      def to_s
        "PROGRAM #{string}"
      end
      
      %w{number major minor type}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end
      
      def string
        self[:string].to_s
      end
      
      def name
        self[:name].to_s
      end
    end

    ##
    # HDHomeRun result object.
    #
    # Contains information about a channel scan result.
    class Result < FFI::Struct
      layout  :channel_string, [:char, 64],
              :channel_map, :uint32,
              :frequency, :uint32,
              :status, HDHomeRun::Status,
              :program_count, :int,
              :programs, [HDHomeRun::Program, 64],
              :tsid_detected, :int,
              :tsid, :uint16
      
      %w{frequency program_count status}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end
      
      def to_s
        output = "SCANNING: #{self[:frequency]} (#{self[:channel_string]})"
        output += "\n#{self[:status]}"
        output += "\nTSID: #{tsid}" if tsid?
        programs.each do |program|
            output += "\n#{program.to_s}"
        end
        
        output
      end
      
      def set_channel
        @channel_string = self[:channel_string]
        
        (@broadcast_standard, @channel) = @channel_string.to_s.split ':'
      end
      
      def channel
        set_channel() if @channel_string.nil?
        
        @channel
      end
        
      def standard
        set_channel() if @channel_string.nil?
        
        @broadcast_standard
      end
      
      def programs
        if @progs.nil?
          @progs = []
        
          self[:program_count].times do |i|
            @progs << self[:programs][i]
          end
        end
        
        @progs
      end
      
      def tsid?
        self[:tsid_detected] == 1
      end
      
      def tsid
        "0x%04X" % self[:tsid]
      end
    end

    # HDHomeRun capture statistics for a given tuner
    #
    # packets:: Number of packets captured
    # network_errors:: Number of network errors
    # transport_errors:: Number of transport errors
    # sequence_errors:: Number of sequence errors
    # overflow_errors:: Number of overflow errors
    #
    class Stats < FFI::Struct
      layout :packets, :uint,
             :network_errors, :uint,
             :transport_errors, :uint,
             :sequence_errors, :uint,
             :overflow_errors, :uint

      %w{packets network_errors transport_errors 
           sequence_errors overflow_errors}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end
    end

    class Device < FFI::Struct
      layout :cs, :pointer,
             :vs, :pointer,
             :dbg, :pointer,
             :scan, :pointer,
             :multicast_ip, :uint32,
             :multicast_port, :uint16,
             :device_id, :uint,
             :lockkey, :uint32,
             :name, [:char, 32],
             :model, [:char, 32]

      members.each do |name|
        define_method name.to_s do
          send(:[], name.to_sym)
        end
      end
    end

    # Discover device structure
    #
    # Silicon dust changed this structure at some point between
    # revision 20100121 and 20110323, but the version number in the
    # library filename was not changed by package maintainers for
    # ubuntu.  As a result, there's no simple way to determine which
    # structure we should use.  To work around this, the gem will
    # assume the library has the newer structure unless the
    # FFI_HDHOMERUN_OLD_DEVICE_STRUCT environment variable has been
    # set.
    #
    class DiscoverDevice < FFI::Struct
      if ENV['FFI_HDHOMERUN_OLD_DEVICE_STRUCT']
        layout :ip_addr, :uint32,
               :device_type, :uint32,
               :device_id, :uint32
      else
        # Newer layout has support for :tuner_count
        layout :ip_addr, :uint32,
               :device_type, :uint32,
               :device_id, :uint32,
               :tuner_count, :uint8

        define_method :tuner_count do
          send(:[], :tuner_count)
        end
      end

      %w{device_type device_id}.each do |name|
        define_method name do
          send(:[], name.to_sym)
        end
      end

      def ip_addr
        IPAddr.new(self[:ip_addr], Socket::AF_INET)
      end
    end
  end
end