From 38cada3d14771da8295db810351e2bc80b7dfd03 Mon Sep 17 00:00:00 2001 From: Aaron Gotwalt Date: Tue, 17 Mar 2015 13:38:54 -0700 Subject: [PATCH] Switch from home-grown SSDP to SSDP gem for discovery. Seems to work a lot more consistently. --- lib/sonos/discovery.rb | 53 ++++-------------------------------------- sonos.gemspec | 1 + 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/lib/sonos/discovery.rb b/lib/sonos/discovery.rb index 2135afc..d9cae58 100644 --- a/lib/sonos/discovery.rb +++ b/lib/sonos/discovery.rb @@ -1,7 +1,5 @@ -require 'socket' -require 'ipaddr' -require 'timeout' require 'sonos/topology_node' +require 'ssdp' # # Inspired by https://github.com/rahims/SoCo, https://github.com/turboladen/upnp, @@ -22,17 +20,15 @@ class Discovery attr_reader :first_device_ip attr_reader :default_ip - def initialize(timeout = DEFAULT_TIMEOUT, default_ip = nil) + def initialize(timeout = DEFAULT_TIMEOUT) @timeout = timeout - @default_ip = default_ip - initialize_socket end # Look for Sonos devices on the network and return the first IP address found # @return [String] the IP address of the first Sonos device found def discover - send_discovery_message - @first_device_ip = listen_for_responses + result = SSDP::Consumer.new.search(service: 'urn:schemas-upnp-org:device:ZonePlayer:1', first_only: true, timeout: @timeout) + @first_device_ip = result[:address] end # Find all of the Sonos devices on the network @@ -46,46 +42,5 @@ def topology TopologyNode.new(node) end end - - private - - def send_discovery_message - # Request announcements - @socket.send(search_message, 0, MULTICAST_ADDR, MULTICAST_PORT) - end - - def listen_for_responses - begin - Timeout::timeout(timeout) do - loop do - message, info = @socket.recvfrom(2048) - # return the IP address - return info[2] - end - end - rescue Timeout::Error => ex - puts 'Timed out...' - puts 'Switching to the default IP' if @default_ip - return @default_ip - end - end - - def initialize_socket - # Create a socket - @socket = UDPSocket.open - - # We're going to use IP with the multicast TTL - @socket.setsockopt(Socket::Option.new(:INET, :IPPROTO_IP, :IP_MULTICAST_TTL, 2.chr)) - end - - def search_message - [ - 'M-SEARCH * HTTP/1.1', - "HOST: #{MULTICAST_ADDR}:reservedSSDPport", - 'MAN: ssdp:discover', - "MX: #{timeout}", - "ST: urn:schemas-upnp-org:device:ZonePlayer:1" - ].join("\n") - end end end diff --git a/sonos.gemspec b/sonos.gemspec index a98d655..30ace34 100644 --- a/sonos.gemspec +++ b/sonos.gemspec @@ -23,4 +23,5 @@ Gem::Specification.new do |gem| gem.add_dependency 'nokogiri' gem.add_dependency 'thor' gem.add_dependency 'httpclient' + gem.add_dependency 'ssdp' end