Class: HDHomeRun::Tuner
Overview
HDHomeRun tuner wrapper.
Basic usage:
# Get a tuner instance for the first tuner on the network.
tuner = HDHomeRun::Tuner.new(:id => "FFFFFFFF", :tuner => 0)
# Set the channel and program
tuner.channel = 20
tuner.program = 3
# Open a file to write the video stream to
File.open("capture.ts", "w") do |output|
puts "Capturing (^C to stop):"
# Read the video stream from the tuner
tuner.capture do |video_data|
# write the video data to the output file
output.write(video_data)
# Display some sort of feedback to show we're capturing.
STDOUT.write(video_data.size > 0 ? "." : "?")
STDOUT.flush
end
end
Constant Summary
Constants included from FFI::HDHomeRun
FFI::HDHomeRun::DEVICE_ID_WILDCARD, FFI::HDHomeRun::DEVICE_TYPE_TUNER, FFI::HDHomeRun::VIDEO_DATA_BUFFER_SIZE_1S
Instance Attribute Summary collapse
-
#tuner ⇒ Object
readonly
Returns the value of attribute tuner.
Attributes inherited from Device
Instance Method Summary collapse
-
#capture(p = {}, &block) ⇒ Object
Capture video data from the tuner.
-
#initialize(p = {}) ⇒ Tuner
constructor
Initialize new hdhomerun tuner.
-
#key=(key) ⇒ Object
Specify the key to use when communicating with this tuner.
-
#lock(k = nil) ⇒ Object
Lock the tuner.
-
#lock_owner ⇒ Object
Return the ip address that holds the lock on the tuner.
-
#locked? ⇒ Boolean
check to see if the tuner is locked.
-
#stats ⇒ Object
Get the capture statistics for the tuner.
- #to_s ⇒ Object
-
#unlock(force = false) ⇒ Object
Unlock the tuner.
Methods inherited from Device
#get, #set, #tuner_count, #tuners
Constructor Details
#initialize(p = {}) ⇒ Tuner
Initialize new hdhomerun tuner
Arguments:
- :id
-
HDHomeRun id (default: “FFFFFFFF”)
- :tuner
-
Tuner number (default: “/tuner0”)
- :key
-
lockkey for tuner, see lock (default: nil)
Create a tuner instance for the first tuner on any HDHomeRun box on the network:
tuner => HDHomeRun::Tuner.new
Create a tuner instance for the second tuner on the HDHomeRun box with id FE92EBD0
tuner = HDHomeRun::Tuner.new(:id => "FE92EBD0", :tuner => 1)
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/ffi-hdhomerun.rb', line 239 def initialize(p={}) super(p) @tuner = p[:tuner] || 0 @tuner = "/tuner%d" % @tuner if @tuner.is_a? Fixnum self.key = p[:key] if p[:key] # Verify the format of the tuner argument raise InvalidTunerError, "invalid tuner: %s" % @tuner \ if set_tuner_from_str(@hd, @tuner) <= 0 # Final check to see if the tuner exists on our device. begin get_tuner("status") rescue UnknownVariableError => e raise InvalidTunerError, "invalid tuner: %s, %s" % [@tuner, e] end end |
Instance Attribute Details
#tuner ⇒ Object (readonly)
Returns the value of attribute tuner.
222 223 224 |
# File 'lib/ffi-hdhomerun.rb', line 222 def tuner @tuner end |
Instance Method Details
#capture(p = {}, &block) ⇒ Object
Capture video data from the tuner.
As data is received from the tuner, that data will be yielded to the block provided. If no data has been received from the tuner in over a second, capture will yield a string of length zero to the block.
If the block returns [false], the tuner will stop capturing and return.
Capture from the tuner, but abort if we see no data:
tuner.capture do |buf|
break false if buf.empty?
end
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/ffi-hdhomerun.rb', line 298 def capture(p={}, &block) raise ArgumentError, "no block" unless block_given? raise RuntimeError, "unable to start stream" \ if stream_start(@hd) <= 0 max_delay = (p[:delay] || 0.064).to_f last_yield = 0 begin len_ptr = FFI::MemoryPointer.new :ulong while true do start = Time.now.to_f data = stream_recv(@hd, VIDEO_DATA_BUFFER_SIZE_1S, len_ptr) if !data.null? or start - last_yield > 1.0 last_yield = start len = len_ptr.read_ulong buf = data.read_string(len) if len > 0 buf ||= "" yield(buf) or break end delay = max_delay - (Time.now.to_f - start) sleep delay if delay > 0 end ensure stream_stop(@hd) end end |
#key=(key) ⇒ Object
Specify the key to use when communicating with this tuner.
418 419 420 |
# File 'lib/ffi-hdhomerun.rb', line 418 def key=(key) lockkey_use_value(@hd, key.to_i) end |
#lock(k = nil) ⇒ Object
Lock the tuner. Optionally a key can be provided to allow locking across non-persistent connections.
- :k:
-
optional key for non-persistent connections
Examples:
Locking with a persistent connection:
t = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
t.lock # => true
t.channel = 3 # => 3
# Create a second instance of the tuner and try to change
# the channel.
t2 = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
t2.channel = 4 # => TunerLockedError exception
# first tuner instance releases lock
t.unlock # => true
# Now second tuner can make changes.
t2.channel = 4 # => 4
Locking across non-persistent connections:
# Grab a tuner and lock it.
t = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
t.lock 0xFFFF # => true
t.channel = 3 # => 3
t = nil # => nil
# Create a new instance referencing the same tuner, cannot
# set tuner variables without setting the key first.
t2 = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
t2.channel = 4 # => TunerLockedError exception
t2.key = 0xFFFF # => true
t2.channel = 4 # => 4
t2 = nil # => nil
# tuner key can be passed in instansiation arguments.
t3 = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0, :key => 0xFFFF)
t3.channel = 5 # => 5
# Invalid keys (or expired keys) result in a LockExpiredError
t3.key = 0x1234 # => true
t3.channel = 6 # => LockExpiredError exception
t3 = nil # => nil
376 377 378 379 380 381 382 383 |
# File 'lib/ffi-hdhomerun.rb', line 376 def lock(k = nil) # If no key was provided, generate a random key for this # session. k ||= rand(0xFFFFFFFF) set_tuner("lockkey", k) self.key = k true end |
#lock_owner ⇒ Object
Return the ip address that holds the lock on the tuner
428 429 430 |
# File 'lib/ffi-hdhomerun.rb', line 428 def lock_owner get_tuner("lockkey") end |
#locked? ⇒ Boolean
check to see if the tuner is locked
423 424 425 |
# File 'lib/ffi-hdhomerun.rb', line 423 def locked? get_tuner("lockkey") != "none" end |
#stats ⇒ Object
Get the capture statistics for the tuner.
Returns: FFI::HDHomeRun::Stats
278 279 280 281 282 283 |
# File 'lib/ffi-hdhomerun.rb', line 278 def stats ptr = FFI::MemoryPointer.new Stats out = Stats.new ptr; get_video_stats(@hd, out) out end |
#to_s ⇒ Object
432 433 434 435 |
# File 'lib/ffi-hdhomerun.rb', line 432 def to_s "<%s:0x%08x @id=%08X, @tuner=%s>" % [ self.class, object_id, @id, @tuner ] end |
#unlock(force = false) ⇒ Object
Unlock the tuner. Requires you to already have the correct key set or use the [:force:] argument.
Example:
t = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
t2 = Tuner.new(:id => 0xFEFEFEFE, :tuner => 0)
# Lock the tuner and try to unlock it without the key
t.lock # => true
t2.unlock # => TunerLockedError exception
t.locked? # => true
# force the tuner to unlock
t2.unlock :force # => true
t.locked? # => false
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/ffi-hdhomerun.rb', line 401 def unlock(force=false) # FIXME uncommenting the following line causes the tests to core # dump. # return true unless locked? set_tuner("lockkey", force != false ? "force" : "none") self.key = 0 # Strange behavior here, setting the lockkey to "none" without # the correct lockkey does not generate an error. Instead the # new value is ignored by the tuner. So we have to check here # to see if the tuner is still locked here to tell if our unlock # was successful. raise TunerLockedError if locked? true end |