Skip to content

Instantly share code, notes, and snippets.

@jcarbaugh
Created September 30, 2015 17:33
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jcarbaugh/e08dcfe61ece0e7eea12 to your computer and use it in GitHub Desktop.
Save jcarbaugh/e08dcfe61ece0e7eea12 to your computer and use it in GitHub Desktop.
DIAL examples
import httplib
import socket
import StringIO
# generic
SSDP_ALL = 'ssdp:all'
UPNP_ROOT = 'upnp:rootdevice'
# devices
DIAL = 'urn:dial-multiscreen-org:service:dial:1'
class SSDPResponse(object):
class _FakeSocket(StringIO.StringIO):
def makefile(self, *args, **kw):
return self
def __init__(self, response):
r = httplib.HTTPResponse(self._FakeSocket(response))
r.begin()
self._headers = r.getheaders()
self.location = r.getheader('location')
self.usn = r.getheader('usn')
self.st = r.getheader('st')
self.server = r.getheader('server')
self.cache = r.getheader('cache-control').split('=')[1]
def __repr__(self):
return '<SSDPResponse({location}, {st}, {usn})'.format(**self.__dict__)
def discover(st, timeout=2, retries=1):
group = ('239.255.255.250', 1900)
message = '\r\n'.join([
'M-SEARCH * HTTP/1.1',
'HOST: {0}:{1}'.format(*group),
'MAN: "ssdp:discover"',
'ST: {st}','MX: 3','',''])
socket.setdefaulttimeout(timeout)
responses = {}
for _ in range(retries):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto(message.format(st=st), group)
while 1:
try:
response = SSDPResponse(sock.recv(1024))
responses[response.location] = response
except socket.timeout:
break
return responses.values()
if __name__ == '__main__':
for device in discover(SSDP_ALL, timeout=5):
print "%s\n\t%s" % (device.location, device.server)
"""
DLNA_RENDERER = 'urn:schemas-upnp-org:device:MediaRenderer:1'
DLNA_SERVER = 'urn:schemas-upnp-org:device:MediaServer:1'
GATEWAY = 'urn:schemas-upnp-org:device:InternetGatewayDevice:1'
PANASONIC_VIERA = 'urn:panasonic-com:device:p00RemoteController:1'
ROKU = 'roku:ecp'
SONOS = 'urn:schemas-upnp-org:device:ZonePlayer:1'
SONY_NEX = 'urn:schemas-sony-com:service:ScalarWebAPI:1'
WAN_IP = 'urn:schemas-upnp-org:service:WANIPConnection:1'
WAN_PPP = 'urn:schemas-upnp-org:service:WANPPPConnection:1'
"""

Things you don't want to have to know just to watch Hot Rod

Hot Rod

From your phone or tablet to your TV

  • AirPlay
  • Chromecast + related technologies

Discovery with SSDP

Simple Service Discovery Protocol (SSDP) is used to discover services advertised by devices on your network.

  • Yell "who's out there?!"
  • Listen for responses

Launching apps and playing media with DIAL

Discovery And Launch (DIAL) is a simple protocol that 2nd screen devices can use to launch apps on 1st screen devices. Developed by Netflix and YouTube.

  • Find device's DIAL endpoint
  • Use it

Name registry

Incredibly high-tech, Google Spreadsheet powered name registry.

DIAL Protocol

Overview of the DIAL protocol.

UPnP > DIAL > Chromecast

  1. Send multicast M-SEARCH request with a Search Target (ST) header of urn:dial-multiscreen-org:service:dial:1.
  2. Read LOCATION header of responding GET requests.
  3. GET the LOCATION header and read the APPLICATION-URL header in the response.
  4. APP-URL is /, where APP-NAME is defined in the registry.
  5. POST to APP-URL. Include supported parameters in the body of the POST, if necessary. v=eIej8JgWWJk is a good demo for YouTube.
  6. Read the LOCATION header of the POST response to get the INSTANCE-URL.
  7. DELETE to the INSTANCE-URL to stop the running app.

YouTube

  • Play a video:

      {"v": video_id}
    
  • Play a playlist:

      {"listType": "playlist", "list": playlist_id}
    
@ObjSal
Copy link

ObjSal commented Jan 2, 2017

Thanks for sharing, this was very useful!

I tried the YouTube JSON parameters as in your example and they don't work, I'm only able to get it working by sending a raw body, for example: v=DYd57rkvnpQ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment