• Flingo enables a website to discover a device in the user's network and bidirectionally communicate arbitrary messages with that device.
  • Flingo works from any major browser and most javascript/wifi-enabled mobile devices including your iPad, Android and Blackberry.
  • Flingo works by utilizing standard web protocols and universally supported browser mechanisms.
  • Flingo connects with any TV that runs a Flingo-enabled application. It's already in millions of living rooms!
  • Flingo requires modifications to the web page, not the user's computer. No applications, plugins, or bookmarklets are required for sites that embed fling links in their web pages.
  • Flingo does not require usernames, passwords, or user configuration.

Contents:

  1. Fling from almost anywhere
  2. Fling to almost anywhere
  3. Fling on almost any network
  4. Fling for free
  5. Fling from a wiki, blog, forum, ...
  6. Fling to friends via email or twitter
  7. Fling to visitors of your youtube page
  8. How it works
  9. Fling from desktop apps
  10. Applications, devices, services, and agents
  11. Security model
  12. Calling a service
  13. Testing without a TV
  14. Fling from a Flash video player
  15. API reference
  1. Fling from almost anywhere

    Flingo relies only on HTML and javascript or Adobe Flash / Flash Lite. To fling a video from a web page requires only a single line of HTML that can be generated from our embed code generator . As long as a device renders HTML and speaks HTTP, a user can fling from it.

  2. Fling to almost anywhere

    Because Flingo relies only on HTTP and JSON, it can be used by any TV application that can generate HTTP requests and parse JSON results. Thus, Flingo can be used by almost any TV application including those written in HTML + javascript, Adobe Flash, Adobe Flex, or Adobe Flash Lite AND even when those TV applications are constrained to a security sandbox as rigid as a web browser's.

  3. Fling on almost any network

    If a user can browse the web from a network, the user can fling to enabled devices on that network. Flingo does not use broadcast or multicast as does UPnP, Bonjour or DLNA, because these are not available from within a web page. Flingo does not use UDP or non-HTTP TCP to talk to Flingo infrastructure, because if it did, there would be some network with a firewall that would block it. So far Flingo has worked on every NATted network we have tried that allows open access to the web.

  4. Fling for free

    Flingo is free for any web site or application for commercial or non-commercial use. We also provide development-only open source GPL-licensed Flingo desktop application hosted by github that demonstrates use of the Flingo API. If for some reason you need a less strict license for the Flingo application then contact editor at flingo.org.

  5. Fling from a wiki, blog, or forum,...

    For example, to fling Big Buck Bunny using nothing more than a hyperlink, click http://flingo.tv/fling/a?purl=http://flingo.org/index.html

    With wikis, blogs, and CMS-managed web pages, bloggers or visitors are often allowed to put hyperlinks on the page. If a blogger or visitor can insert a hyperlink, the blogger or visitor can post a fling of a video web page with URL u provided u points at a web page served by a supported site. The flinging blogger or visitor prepends the fling URL to page URL u as follows:

        http://flingo.tv/fling/a?purl=u
    

    With some systems, the blogger or visitor may be able to create a hyperlinked image that flings. For example, with wikipedia, you can insert a fling button on any wiki page using the following markup:

        [[File:FlingoLogo.png|64px|link=http://flingo.tv/fling/a?purl=u|alt=fling]]
    

    You can see an example of this on the flingo wikipedia page.

  6. Fling to friends via email or twitter

    You can send a fling in an email or tweet in the same manner as you would post a fling to a blog or wiki--- by prepending the fling URL to any URL u pointing at a web page residing on a supported site.

    Since many email programs recognize URLs embedded in the text of an email, the receiver may be able to simply click on the hyperlink in the email and the referenced video is flung to devices in the receiver's private network.

    For example, Alice likes a video foo.mp4 embedded in page with url http://example.com/foo.html. Alice sends Bob an email containing the link

        http://flingo.tv/fling/a?purl=http://example.com/foo.html
    

    Bob opens the email while at home. He clicks on the link which flings foo.mp4 to his connected TV.

    The same link above can as easily be tweeted, and Flingo does not interfere with shortening by services such as t.co, bit.ly, or TinyURL.com.

  7. Fling to visitors of your youtube page

    You can enable visitors to fling your videos from your youtube page by including the URL

        http://flingo.tv/fling/a
    

    in the description section for the video to be flingo-enabled. When a visitor clicks on this link in your video's description, the video is flung to connected TVs in the visitor's network.

    You can see an example of this on the flingotv youtube page.

  8. How it works

    Flingo-enabled devices such as connected TVs and blu-ray players announce to flingo.tv by sending an HTTP request. A Flingo-enabled web site later discovers Flingo-enabled devices by sending an HTTP request to flingo.tv using cross-site scripting. flingo.tv then returns a list of all Flingo-enabled devices sitting behind the same public IP as the browser.

    Most homes have a NAT sitting in between the home network and the Internet, and as such returning a list of all devices behind the same IP address is often exactly equivalent to returning a list of all devices in the user's home network. This may not work as well for corporate environments where the number of devices behind a public IP may be quite large, but we'll address that issue at a different time.

    In the most constrained scenario, communications with the Flingo-enabled device are forwarded through a relay using HTTP requests with JSON bodies. If a Flingo-enabled device is not powered, messages are queued in the relay until the device is powered. While a Flingo-enabled application is running the device HTTP long polls the relay allowing messages to be immediately forwarded.

    So far we have discussed using Flingo to tell a TV to play or queue a video. However, Flingo can be used to communicate arbitrary messages so long as the Flingo-enabled application in the receiving device is written to understand them. As such Flingo can be used to remote control TV applications, manage the user's queue, or do whatever interesting thing someone in the Flingo community can imagine.

    Flingo relies on central infrastructure to act as a rendezvous point and message relay between the web browser and devices in the browser's network because using a mutually-reachable third party is the ONLY way that a web site can reliably discover and communicate with devices within the same network when constrained to the limitations imposed by a modern web browser. Web browsers do not today provide web pages with access to Bonjour/MDNS, UPnP, or other protocols that require data-link layer broadcast or network-layer multicast. Even if browsers did, they would not handle the case when TVs are unpowered.

  9. Fling from desktop applications

    Although Flingo works from within the constraints imposed by sandboxes both in the web browser and the TV, it is still quite useful to applications sitting outside a sandbox.

    For example, given a streaming video player application on the TV that is sandboxed such that it can only request HTTP, a desktop application running on a laptop could still fling a video from its file system to the TV so long as the laptop serves that video using HTTP. Imagine integrating Flingo into a downloader application, when the video completes downloading, the downloader automatically flings the video to the TV.

    We have provided a development open-source GPL'd Flingo desktop application that flings video files to a TV from a computer's file system. We hope the community helps expand this application or uses it as an example to integrate Flingo into existing applications.

  10. Applications, devices, services, and agents

    An application running inside a web browser or browser-like sandbox is called a sandboxed application.

    A device announces network services to Flingo's discovery service. The discovery service runs on flingo.tv, and all communications with flingo.tv use the Flingo API. A sandbox-reachable service is any service that can be discovered and communicated with from within a sandboxed application. A single device or any application on that device may run many such services.

    When a sandbox-reachable service is itself constrained to a browser or browser-like security sandbox, it is called a sandboxed service. Many TV and set-top box manufacturers insist on running TV applications (a.k.a., widgets) inside a sandbox to reduce the likelihood of an application "crashing" the device or subverting the device's behavior in unintended ways.

    When a sandbox-reachable service is sandboxed or is forced to be implemented in Adobe Flash, Adobe Flash Lite, or Javascript + HTML, the service cannot listen on a socket and thus can only service requests by using a third party that acts as a relay. This is one reason Flingo provides a relay service. Other reasons being that a relay enables queueing messages even while a device is turned off, or is within a separate private IP address space behind the same NAT.

    When a service is not constrained to a sandbox, it presumably can know its own IP address(es) and can bind to a socket to service requests. Because we assume network services run behind a NAT, the IP address(es) of the device on which a service runs are private addresses and are not visible to the public Internet. However, because the service knows its own private IP address(es), it can announce this information to the Flingo discovery service. When a sandoxed application later performs a discovery request, the discovery service response includes the private addresses for each discovered sandbox-reachable service. A web page can then use cross-site scripting to open a connection directly to the discovered service. We call this a local fling. Thus when a service is not sandboxed, it is unnecessary for messages to pass through a relay. Avoiding the relay has at least two advantages:

    1. connections that traverse a local network experience low latency and are thus more suitable for interactive applications like TV remote controls, and
    2. local network connections improve privacy-- if a message does not pass through central infrastructure, central infrastructure never has the opportunity to read the message's contents.

    Realizing that most TV manufacturers are unwilling to completely unsandbox applications running on the TV, we isolated the subset of functionality specific to Flingo into an executable that runs outside the sandbox and can be shared by all of the sandbox-reachable services on that TV. We call this executable the Flingo agent. A service S can operate fine without an agent, but then S cannot receive local flings and cannot distinguish whether services in the same network run on the same network node as S.

    To mimimize porting issues, the agent is written using only standard unix libraries. To avoid relying on platform-specific mechanisms for extending the sandbox, the agent communicates with local sandbox reachable services using sockets. The agent binds to the loopback interface and listens on a well-known port. To our surprise, not all unix-based, Internet-connected devices offer a loopback interface by default. Enabling it is generally a one-line change in a boot script, but it is usually something only the device manufacturer can do. Using an interface other than the loopback interface is not possible since sandboxed services do not know the IP addresses of the network interfaces on the device on which they run.

    On startup, a sandboxed service need only announce to the agent's well-known port to discover whether an agent is available. If the connection is refused or the service returns something other than a valid JSON dict containing an announce response then the sandboxed service reverts to announcing to the Flingo discovery service running on flingo.tv.

  11. Security Model

    Because Flingo has so few contraints, we should take a moment to explain its security model.

    A sandboxed application sends a discovery request to the Flingo discovery service. When Flingo receives a discovery request, it returns a list of sandbox-reachable services containing only those services that share the same IP address with the sender IP address of the discovery request. This prevents arbitrary hosts on the Internet from discovering services in a user's private network.

    Other than the website performing the query, only an attacker capable of intercepting communications traversing the public Internet can see the response to a discovery request. An attacker so empowered is in a position to do far more damage than playing a video on your TV; therefore, we assume that protecting from attackers that do not have access to packets traversing the public Internet is sufficient.

    By default, Flingo considers web sites as untrustworthy and only allows them to perform a small set of operations. To prevent web sites from sending arbitrary messages to a user's devices, web sites are never given complete information. They can be told that a sandbox reachable service exists and told its name, thumbnail, description or an locally-unique ephemeral device ID but the actual communication with the sandbox reachable service is achieved using a web page, iframe or SWF loaded from flingo.tv. Such web page, iframe or SWF is called a trusted intermediary.

    All major browsers send a "referer [sic]" header that contains the URI of the web page or iframe originating a request. The Flingo discovery service running on flingo.tv relies on the presence of the referer header to ensure that messages either originate or pass through a web page, iframe or SWF served by flingo.tv. Since all messages from a browser either originate or pass through something served by flingo.tv, flingo.tv can impose policy. For example, to fling a video flingo.tv presents a fling button that the user must press before a "fling" call is made. This serves to minimize spam from random web sites a user visits.

    When a referer URI is not present, the Flingo discovery service assumes that the request comes from a desktop application or a bookmarklet. Because desktop applications require user installation and often have direct access to the user's local network, we assume that applications are more trusted than web sites. We thus provide applications with access to a far wider range of APIs than we provide to websites. Although perhaps not as justified, we provide the same leniency for bookmarklets as we do applications.

    Browser referer header behavior is not as consistent for Adobe Flash, and for that we use different mechanisms.

    The API defines several access specifiers: public, private, and restricted. A public function is one that can be called by anyone from anywhere. Example calls include announce and discover. Private calls affect the state of one or more sandbox-reachable services that MUST reside within the private network of the caller. Restricted calls additionally cannot be performed from a browser by any site other than flingo.tv or a site with a white-listed domain. The whitelist is set by the user. flingo.tv will soon release policy mechanisms to allow users to expose restricted calls to web sites beyond flingo.tv. Anyone else is permitted to make restricted calls including unsandboxed services, desktop applications, and bookmarklets. Entities permitted to perform restricted calls are said to have unrestricted access.

    The discover call is actually both public and restricted in the sense that anyone can call discover, but only an entity with unrestricted access is allowed to see a sandbox reachable service's globally unique id (a.k.a., guid). A service's guid is a global address in that the relay uses the guid to route messages. If a web site does not know a service's guid then it has no means to address messages to that service. Furthermore, messages enqueued for services not behind the same public IP as the sender are dropped.

  12. Calling a service

    Flingo provides a remote procedure call primitive. The intended purpose of this building block is to enable remote controls or more detailed manipulation of services than should be allowed from a web site without a trusted intermediary. As such these calls can only be made directly from parties with unrestricted access such as applications and bookmarklets or from SWFs, web pages, or iframes loaded from flingo.tv.

    The primitive is designed to meet the following criteria:

    1. The primitive enables procedure calls to services that may themselves be sandboxed.
    2. The primitive is generic where possible: it allows communication of arbitrary opaque short messages from a caller to a callee and back.
    3. The primitive works with existing RPC specifications that operate over HTTP, e.g., JSON-RPC, XML-RPC.
    4. The primitive separates payload from envelope where possible: routing information to a specific service is included in HTTP headers or URI query strings so that routing is handled without imposing constraints on the contents of the request body.
    5. The primitive resists cross-site scripting attacks.

    The call primitive enables communication to sandboxed services by relying on the flingo relay service or an agent to forward calls and return results.

    The call primitive achieves genericity by forwarding arbitrary HTTP request bodies through the relay and/or agent to the service and preserving the content type and content length headers. The payload can obey the JSON-RPC specification, XML-RPC specification, or any other communication specification that HTTP POSTs a single message and expects a single message as the HTTP response body.

    The primitive separates payload from envelope by communicating the guid and optionally the service name in the URI query string of the call made to the relay or agent. The relay or agent (except when using the as2 workaround) places the service name and message id in experimental HTTP headers in the response to the corresponding longpoll call.

    And to resist cross-site scripting attacks, the relay and agents only accept calls from parties with unrestricted access, i.e., those that transmit HTTP requests lacking referer headers.

    We demonstrate a call to a mythical function foo below:

  13. Testing without a TV

    If you do not have a TV that runs a Flingo-enabled application, you can create a virtual TV inside a web page by going to here. You can fling to this TV as if it were a real TV. Note that this virtual TV is intended for demo and development purposes only. If you have more than one window open on the same computer with a virtual TV running in it, they will share the same service guid and thus will interfere with each other.

  14. Fling from a Flash video player

    To make it easier for Adobe Flash or Flex developers to put Fling functionality into their applications (e.g., Flash video players), we have also released a SWF that can be embedded into any Flash application. Load the SWF from http://flingo.tv/swf/flingButton.swf and call the set_media function to tell it the details of the media to be flung.

    The SWF does not expose a fling function, the user has to click on the SWF in order for any content to be flung to the TV. As with an iframe, a SWF encapsulating a button served from trusted infrastructure is a measure to avoid website's sending unsolicited flings to a user's network services.

    By embedding a fling SWF inside a site's flash player, the call to set_media and all of its arguments are compiled inside the site's flash player rather than exposed on the web page as would occur using the http://flingo.tv/fling/a method.

    By embedding a fling SWF inside a site's flash player, we also allow that site to update its deployed base of embed players to support flingo without requiring modification to the HTML of the web pages that have already embedded the player.

    • set_media
      • set_media(metainfo_dict:Object)
      • access: public
      • set_media takes a flash.utils.Dictionary with the following key-value pairs: url, deobfuscator, context, title, description, and image.

        Note that the url parameter and <deobfuscator, context&rt; pair are mutually excusive, they cannot all be set. All parameters are string values, and have the same meanings as the arguments to the fling call: they are used to make the http://flingo.tv/fling/fling API call when the user clicks on the button.

    The following example illustrates embedding a fling button in an Adobe Flex SWF:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
        ...
        <mx:Script>
            <![CDATA[
                protected function completeHandler(event:Event):void
                {
                    var mediaDict:Dictionary = new Dictionary();
                    mediaDict.publisher_name = "Example";
                    mediaDict.title = "Foo: the Movie";
                    mediaDict.description = "The best movie ever.";
                    mediaDict.image = "http://example.com/foo.jpg";
                    
                    (flingButton.content as Object).set_media(mediaDict);
                }
            ]]>
        </mx:Script>
        
        <mx:SWFLoader id="flingButton" 
            source="http://flingo.tv/swf/flingButton.swf"
            complete="completeHandler(event)"/>
        
    </mx:Canvas>
    
  15. API Reference

    All functions are implemented using HTTP. All functions excepting call and longpoll return JSON-encoded responses. call and longpoll are used to pass opaque messages that may be JSON-encoded. Arguments are passed as URL query string key-value pairs or passed using a POST of a JSON dict where each key corresponds to an argument. In the documention brackets denote optional arguments.

    Use HTTP POST to makes calls that modify state such as announce. Calls that retrieve state use HTTP GET. The anchor function a loads a web page that then performs a fling. The call to a itself does not modify state and thus is called using HTTP GET.

    In this API reference the word GET precedes the name of each function that SHOULD be called using GET and similarly for POST for functions that SHOULD be called using POST. To ease testing, some functions support both GET and POST. In the documention brackets denote optional arguments.

    API-level errors are reported using HTTP status code 200 with a JSON dict containing an error code and error message. For example,

    {
        "error" : {
            "code" : 8003,
            "message" : "Unknown model id." 
        }
    }
    

    The structure is similar to that used by JSON-RPC, but the similarity is arbitrary. Originally we attempted to use 4xx HTTP status codes for API-level errors as this would be more in keeping with modern web service APIs, but many embedded and non-embedded platforms do not propagate HTTP status codes to Flash AS2 and AS3 SWFs. Given that many high volume platforms provide limited or no HTML support, we developed user interfaces using Flash Lite. We may introduce a new version of the flingo APIs when this problem is less prevalent. For HTTP-protocol-level errors, HTTP status codes are still used.

    Currently the following application-level error codes are defined:

    FAILURE8002
    KEY_ERROR8003
    VALUE_ERROR8004
    ILLEGAL_REFERER609
    SERVICE_INACCESSIBLE611
    EXPIRED_GUID612

    FAILURE denotes an API-level error not captured by other error codes. KEY_ERROR refers to a lookup on a key that does not exist. VALUE_ERROR refers to an argument that is invalid. ILLEGAL_REFERER occurs when a call is refused because the domain originating the call is not whitelisted and the call has restricted access. SERVICE_INACCESSIBLE occurs when a passed guid corresponds to a service that either does not exist or the service exists but the call has private access and the service is not in the same private network as the caller. EXPIRED_GUID occurs when a call is made with an expired ephemeral guid. Non-whitelisted domains are provided only short-lived device guids.

    Because many calls have more RPC-like semantics and/or have results that are dependent on the client's public IP, API results cannot be cached. By its nature this API is not REST-ful. That the API uses 200 status codes to report errors simply moves it one step further from REST. To avoid caching, every response contains a Cache-Control header with value no-cache.

    Public functions may be called using cross-site scripting using the script tag, a.k.a., JSONP. For example,

    <script type="text/javascript">
    function cb(d) { ... }
    </script>
    ...
    <script id="external_script" type="text/javascript"></script>
    <script type="text/javascript">
        document.getElementById(
            "external_script").src = "http://flingo.tv/fling/discover?callback=cb";
    </script>
    

    Using jQuery the above becomes

    <script type="text/javascript">
      function cb(d) { ... }
      function doit() {
        $.ajax( { url : url, dataType : "jsonp", success : cb,
                  error : cb, timeout : 5000 } );
      };
      $(document).ready(doit);
    </script>
    
    • GET a
      • http://flingo.tv/fling/a[?purl=P&url=U&description=D&title=T&image=I]
      • access: private
      • a refers to the HTML anchor tag, which in HTML is used to create hyperlinks. Place a hyperlink of the form

        <a href="http://flingo.tv/fling/a">...</a>
        

        or

        <a href="http://flingo.tv/fling/a?url=U&title=T&image=I">...</a>
        

        on any web page. In the first form, the page url is inferred from the referer header and the metadata content url, title, and image are inferred sometimes via a site-specific API or by scraping the HTML. The first form is an example of Zero-Argument Fling (ZAF). The first form only works for ZAF-supported web sites such as youtube.com. In the second form, explicit arguments are provided for the URL of the actual video, the video's title, and the escaped URI of an image used as cover art and thumbnail. The second form works with any website.

        The anchor a function can be placed in blogs, wikis, email, tweets and youtube descriptions hyperlink. Often times (e.g., with youtube) no markup is necessary to delimit a hyperlink and thus the anchor function can appear in the text simply as

        http://flingo.tv/fling/a
        

        For example, placing the above link in the description of a youtube video fling-enables the youtube video. Clicking on the link opens an HTML form to confirm the fling. The form is served form flingo.tv and serves as a trusted intermediary that thwarts web sites spamming flingo-enabled devices.

        When a hyperlink does not appear in a web page, there is no referer URI. Thus to tweet or email a fling, the sender must include the url or purl arguments in the anchor a call, where the url references the actual video and purl references the web page containing the video. purl without url can only be passed for ZAF-supported web sites. If the purl is provided, the anchor call attempts to infer the URL of the actual video and infer the video's metadata from the purl. If both purl and url are provided then url is taken to mean the URL of the actual video and purl is used only to infer any metadata that is not provided by other parameters to the anchor call.

    • POST announce
      • http://flingo.tv/fling/announce
        {
          "guid" : "G",
          "name" : "N",
          "service" : "S",
          "description" : "D",
          "make" : "K",
          "model" : "M",
          "model_id" : "I",
          "private_ip" : ["IP1",..,"IPn"],
          "dev_name" : "DN",
          "dev_description" : "DD",
          "version" : "SV",
          "capability" : ["C1",..,"Ck"]
        }
        

        All arguments are optional except guid.

      • access: public
      • Announces the existence of a sandbox-reachable service with globally unique id G, service name S, and human-readable name N (e.g., Foo Video Player). If no service name is provided then the service announces as the default service for handling flings for the provided guid.

        The globally unique id is a string that MUST be sufficiently random to guarantee global uniqueness with high probabilty. For example, currently deployed devices randomly generate a 40-byte hex string. When possible all services on a given device should use the same guid as this is used to identify services that share a device. However, when services are sandboxed and there is no agent, services have no way of determining whether they run on the same device. In such a case the service should generate a random id on first startup and save that state, e.g., as a cookie or shared object.

        Services on the same device announce separately.

        When a service or its agent announces, it may include the IP address-port pairs on which it listens using the private_ip IP1..n parameter. Each ip address-port pair is represented as IP and port substrings separated by a colon, e.g.,

        http://flingo.tv/fling/announce?...&private_ip=192.168.1.12:11997
          &private_ip=10.0.1.1:11997&...
        

        means the service or its agent listens on port 11997 on two network interfaces with IP addresses 192.168.1.12 and 10.0.1.1 respectively.

        When an agent announces or when a service knows the model of the device on which it runs, it may specify a make K (e.g., Vizio), human-readable model name M (e.g., Vizio 42" LCD SV422XVT) and/or model id I (e.g., sv422xvt). It may also provide a human-readable name for the device DN and a human-readable description for the device DD.

        When multiple services announce on the same device, device-specific arguments device name, device description, make, model, and model id are taken from the most recent announce with a given guid that contained the respective argument. If a device-specific argument is omitted from an announce then its prior value if any is retained. All other fields are specific to each service.

        The version SV is a service-specific version number. It is not a Flingo API or protocol version number.

        The capability C array specifies capabilities beyond the functionality expected for the service with given service name SN. As of now there is only one capability defined: play_now. play_now indicates that a particular flingo service has the ability to preempt video including potentially broadcast television to play or otherwise render the flung media.

        Returns a dict containing the caller's public IP and the announce interval in seconds. The caller is expected to announce periodically within the given interval. The caller MAY announce more frequently and SHOULD randomize the interval.

        {
          "yourip": "208.90.212.135", 
          "interval": 900
        }
        
    • POST call
      • http://flingo.tv/fling/call?guid=G[&service=S&ttl=T&as2_workaround=A]
      • access: restricted
      • Tells relay to forward the HTTP posted request body to the service with provided guid G and service name S then wait and forward any response from the service back to the caller. To the relay, the posted request body is opaque.

        Because the request body is opaque, this will work with any standard JSON-RPC or XML-RPC library provided the receiving service understands JSON-RPC or XML-RPC request bodies.

        If no service name is provided then the message goes to the default service for handling fling calls. If the server is not available or does not reply within ttl seconds then a Service Unavailable (503) HTTP status code is returned.

        To use the call primitive with an agent, replace domain name flingo.tv with the private IP address of the network interface on which the agent runs. When direct calls fail, the caller should fall back to using the relay service on flingo.tv.

        The as2_workaround parameter is necessary when calling from Adobe ActionScript 2, because AS2 does not allow POSTing arbitrary message bodies. Both AS2 XML and LoadVars objects add additional encoding to the HTTP POSTed message body. The as2_workaround assumes the application uses AS2 LoadVars to post a message body. Since LoadVars sends key-value pairs assigned to a LoadVars object, we assume the intended message body is assigned to a payload key as in the following example:

        lv.payload = "{ \"method\":\"echo\", \"params\":[\"foo\"], \"id\":0 }";
        lv.sendAndLoad(url, result_lv)
        

        When the receiving service calls longpoll, the longpoll returns

        { "method" : "echo", "params" : [ "foo" ], "id" : 0 }
        
    • POST clear
      • http://flingo.tv/fling/clear
      • access: restricted
      • Removes all services on this private network from the flingo.tv's discovery service. A subsequent call to discover will return zero services. This function is restricted so that web sites cannot remove state for the services in your private network. clear is intended only for development and testing. For example, if you create many devices using the demo and testing page.

    • GET discover
      • http://flingo.tv/fling/discover[?service=S][&callback=C]
      • access: public / restricted
      • Returns a JSON dict containing a list of sandbox reachable services behind the same IP address as the caller. Only returns service guids to callers with unrestricted access. If service S is specified, the results are limited to those devices offering service S and just the S service for each such device.

        For example, a device announces a default fling service,

          http://flingo.tv/fling/announce?
          guid=c22b5f9178342609428d6f51b2c5af4c0bde6a42
          &dev_name=couch&model_id=vizio_sv422xvt
          &version=1.0.13&description=Default+service
          &make=vizio&model=Vizio+SV422XVT
          &dev_description=42\"+LCD+flat+panel+VIA+connected+TV
        

        At some later time, an application calls discover to discover services in the network.

          http://flingo.tv/fling/discover
        
        The call to discover returns with a JSON dict containing a list of devices and the service they offer. In this case, only the single announced service offered by a Vizio VIA connected TV's Web Videos application appears in the response:
          {
            "yourip": "68.126.150.54", 
            "interval": 900, 
            "devices": [
              {
                "description": "42\" LCD flat panel VIA connected TV", 
                "model_id": "vizio_sv422xvt", 
                "external_ip": "68.126.150.54", 
                "make": "vizio", 
                "t": 1308386059, 
                "services": [
                  {
                    "description": "Default service for playing flung media.", 
                    "version": "1.0.13", 
                    "name": "flingo", 
                    "service": "flingo", 
                    "capability": ["play_now"],
                    "private_ip": []
                  }
                ], 
                "model": "Vizio SV422XVT", 
                "guid": "c22b5f9178342609428d6f51b2c5af4c0bde6a42", 
                "name": "couch"
              }
            ]
          }
        

        If a service knows about the device on which it runs, guid is the device's globally unique id, name is a human-readable name for the device, and model_id is the model of the device on which the service is running. If device information is not known, guid becomes the service's globally unique id, and name becomes a human-readable name for the service. model_id should be omitted if the model of the device is not known.

        In a response to a call from an entity with restricted access the result appears as:

          {
            "yourip": "68.126.150.54", 
            "interval": 900, 
            "devices": [
              {
                "description": "42\" LCD flat panel VIA connected TV", 
                "model_id": "vizio_sv422xvt", 
                "external_ip": "68.126.150.54", 
                "make": "vizio", 
                "t": 1308386059, 
                "services": [
                  {
                    "description": "Default service for playing flung media.", 
                    "version": "1.0.13", 
                    "name": "flingo", 
                    "service": "flingo", 
                    "capability": ["play_now"],
                    "private_ip": []
                  }
                ], 
                "model": "Vizio SV422XVT", 
                "name": "couch"
              }
            ]
          }
        

        The optional callback parameter specifies the name of a Javascript function that is called and passed the result. This allows the discover call to be placed inside a SCRIPT tag. For example,

        <script type="text/javascript">
        function cb(d) {
            var services = d["services"];
            var slen = services.length;
            var s, len;
            if ( slen > 0 ) {
                alert( "Found services!" );
            }
        } 
        </script>
        ...
        <script id="external_script" type="text/javascript"></script>
        <script type="text/javascript">
            document.getElementById(
                "external_script").src = "http://flingo.tv/fling/discover?callback=cb";
        </script>
        

        discover deprecates lookup. lookup has two versions with the format of the result differing depending on a fling version argument fver. People often omitted the fver argument resulting in confusion. We retain the lookup call only for backwards compatability.

    • POST fling
      • http://flingo.tv/fling/fling
        {
          "url" : "U",          
          "deobfuscator" : "D", 
          "context" : "C",  
          "purl" : "P",
          "guid" : "G",
          "title" : "T",
          "description" : "D",
          "image" : "I",
          "play_now" : "P",
          "front" : "F"
        }
        

        [U | D and C | P][G][T][I][P][F] meaning all arguments are optional excepting there must be enough information to idenitfy the content in U, D and C, or P.

      • access: restricted
      • Flings a resource with URL U to sandbox reachable services in the caller's private network. When only the URL is provided, the fling goes to the default service for handling flings on ALL sandbox reachable services in the private network.

        If the receiving service is a video playing application (e.g., Vizio's Web Videos) then the URL must be the URL of the actual video.

        If page URL P is provided and the domain in the page URL refers to a web site supported by zero-argument fling then all metadata that is not explicitly provided is inferred.

        To send to a specific sandbox-reachable service within the private network, the caller provides the service's guid G as obtained from a call to discover.

        The caller may provide additional metadata such as the title and description of the content and the URL of an image to be treated as cover art. If omitted the receiving service MAY assume a default title, image, and description. The receiving sandbox-reachable service MAY also use external services to obtain metadata. The time it takes to search and download from external services may perceptibly increase the time it takes for a fling to complete, and the resulting metadata is not guaranteed to be accurate.

        "Play now" P is a boolean taking on values true or 1 for true and false or 0 for false. When omitted, play_now defaults to false. When true, the service receiving the URL MAY preempt any resource currently being handled. The play_now key-value pair is advisory. It may not apply to all services and may be ignored as per user policy. When flinging a video to a video service that provides a queue, true means "play now" and false means "enqueue."

        The front F parameter determines whether the flung item is pushed to the front or the back of the queue. It defaults to false meaning the item is by default pushed to the back of the queue. F only applies to services that implement a queue. Like play_now P, F is advisory and may be ignored as per user policy.

        The deobfuscator D is the URL of a SWF that is executed in the sandbox-reachable service, e.g., a television, each time the resource is played or otherwise rendered to derive the URL of the resource from the opaque context C. Either the deobfuscator and associated context OR the url MUST be provided, but not both. The specifics of how to write a deobfuscator SWF will be provided soon.

        fling is restricted since it requires access to service guids for many operations. The fling function is intended for use by desktop applications and bookmarklets. To fling from a web site see the anchor (a.k.a., a) call.

    • GET longpoll
      • http://flingo.tv/fling/longpoll?guid=G[&wait=W&as2_workaround=A]
      • access: restricted
      • Waits for a message if one has not arrived. When one or more is available, this pops the first queued and returns it. The returned response body is the request body in a prior POST to call.

        The destination service for the message is specified in the X-Service header in the response headers. The message ID is specified in the X-Message-Id header.

        In AS2, LoadVars and XML provide no access to response headers so an AS2 caller cannot get X-Message-Id or X-Service headers. In order to allow the longpoll caller to correlate a response to the message returned from longpoll, we provide a way to pass id and content type. To handle this, we introduce as2_workaround which returns the call request body and content type headers as JSON of the form:

        { "content_type" : C, "payload" : P, "id" : id, ... }
        

        When using the as2_workaround, the payload can be anything encodable as a JSON string and decoded into the desired content_type. For example, given

                   
        {
          "content_type" : "application/json-rpc", 
          "payload" : 
              "{\"method\":\"echo\",\"params\":[\"foo\"],\"id\":0}",
          "message_id" : "123123123123123123",
          ...
        }
        

        In ActionScript 2, the payload decodes as

        {method:"echo",params:["foo"],id:0}
        

        When a fling arrives, longpoll returns with an "update" call. For example,

                            
        $ curl "http://flingo.tv/fling/longpoll?guid=G"
        

        blocks until a fling or other call arrives. In another window we fling

        $ curl "http://flingo.tv/fling/fling" -H "Content-Type: application/json" 
        -d '{"title":"Cool Flick", "description":"Coolest flick ever.", 
             "url":"http://example.com/foobar.mp4", 
             "purl":"http://example.com/foobar.html", "guid":"G"}'
        

        Then the longpoll returns:

        $ curl "http://flingo.tv/fling/longpoll?guid=G"
        {"params": null, "method": "update", "id": 0}
        

        When an update message arrives, the caller can call queue to obtain the updated queue.

    • POST move_queue
      • http://flingo.tv/fling/move_queue
      • access: restricted
      • {
            "guid" : "G",
            "link_id": "L",
            "index" : I
        }
        

        Moves the item with given link_id L to index I. Returns true on success. Returns false if the passed link_id is not found in the queue or the passed index is larger than the length of the queue. In the either case the state of the queue is unchanged. This function otherwise returns an error code.

        This function is idempotent.

        For example, the following moves the item with given link_id to index 2.

        {
            "guid" : "afdcbf95d224b78145bd55ea4dc6021401ba867b",
            "link_id": "4f832c487726fd58440693b3",
            "index" : 2
        }
        
    • GET obfuscate
      • http://flingo.tv/fling/obfuscate?url=U
      • access: restricted
      • Returns an encrypted version of URL U that can be passed to fling as the URL to the content. All URLs beginning with “o:” are assumed to be obfuscated. obfuscate cannot be called from a web page. To obfuscate URLs on a web page x, the content provider should call obfuscate for each url to be obfuscated y on x prior to serving x, and replace each y with the corresponding obfuscate return result. The obfuscated URLs do not expire and thus can be placed in static web pages. Even though obfuscated URLs do not expire, this says nothing about the long-term availability of the referenced resource.

        As an example of the obfuscate call, when passed

        http://example.com/blah/foo.mp4
        

        obfuscate returns an HTTP response containing the JSON string

        "o:0zSgUP59MqtQ=oAE9LSS8EXZY66gKGBAG+/G8YF3BAIE9uD3ns2Szsw=="
        

        The encryption method uses a random initialization vector so each time you call obfuscate with the same URL, it will generate different ciphertext; however, they will all decrypt to the same URL.

    • GET queue
      • http://flingo.tv/fling/queue?guid=G[&index=I&howmany=H]
      • access: restricted
      • This retrieves items from the queue with indices in the range [I, I+H). If I+H exceeds the number of items then all items starting from and including the item at index I until the end of the queue are returned. For example, if you fling a video Cool Flick sending the following POST to URL:

        http://flingo.tv/fling/fling

        {
          "title":"Cool Flick",
          "description":"Coolest flick ever.", 
          "url":"http://example.com/foobar.mp4", 
          "purl":"http://example.com/foobar.html", 
          "guid":"G"
        }
        

        And then call queue as follows:

        $ curl "http://flingo.tv/fling/queue?guid=G&index=0&howmany=10"
        {
          "count": 1,
          "items": [
            {
              "description": "Coolest flick ever.",
              "title": "Cool Flick",
              "link_id": "4ff359ce4c90d1960b057319",
              "encodings": [
                {
                  "delivery_type": "PROGRESSIVE",
                  "url": "http://example.com/foobar.mp4",
                  "is_default": true,
                  "is_ephemeral": false,
                  "bitrate": ""
                }
              ],
              "seekable": true,
              "thumbnail": "http://flingo.tv/static/images/content/ec/ec2d3612-c54f-11e1-ae4e-047d7b3abf7b/small.jpg",
              "page_url": "http://example.com/foobar.html"
            }
          ]
        }
        

        The returned dict contains two keys:

        • count: number of pieces of content in the queue. This may be more than the number of items returned. Pass arguments index and howmany to specify a range of items to load.
        • items: array of dicts where each dict contains metadata for a piece content.

        The metadata for each piece of content is represented as a dict that contain any of the following keys:

        • description: description of the video.
        • encodings: array of encoding dicts where each dict represents a single encoding of the content. (see below).
        • link_id: a unique identifier for this item in the queue. The same piece of content may appear multiple times in the queue, but each instance of that item will have its own unique link_id.
        • page_url: it is the same as purl which refers to the URL of the web page containing the video.
        • thumbnail: is a link to a thumbnail image.
        • title: title of the video

        Each encoding dict specifies at least enough information resolve to a single URL. When the URL to the content is provided, the URL appears in an encoding dict as the value to the url key. Other keys include:

        • delivery_type: takes on values in [PROGRESSIVE, RTMP, RMPTE, DYNAMIC_RTMP, DYNAMIC_RTMPE, DYNAMIC_RTMPS].
        • is_default: whether to use this encoding in favor of other encodings when all else is equal. This could be for any number of reasons including infrastructural reasons or encoding parameters.
        • is_ephemeral: whether this URL is short-lived. One should not expect this URL to work more than tens of minutes after it has been returned in this call.
        • bitrate: bitrate of the encoding.
        • deobfuscator_url: URL to a piece of code, e.g., a SWF that maps from a deobfuscator_context onto a list of encodings. If you want more information on deobfuscators then please contact editor@flingo.tv.
        • deobfuscator_context: An opaque string, often the page URL, that is passed to the deobfuscator.
    • POST remove_queue
      • http://flingo.tv/fling/remove_queue
      • {
            "guid" : "G",
            "link_id": "L",
        }
        
      • access: restricted
      • Removes the item with given link_id L from the queue. This function returns true on success. It returns false if the link_id could not be found in the queue. It otherwise returns an error code.

        This function is idempotent.

        For example, the following removes from the queue the item with link_id 4f832c487726fd58440693b3:

        $ curl "http://flingo.tv/fling/remove_queue" 
        -H "Content-Type: application/json" 
        -d '{"guid" : "afdcbf95d224b78145bd55ea4dc6021401ba867b", 
        "link_id": "4f832c487726fd58440693b3"}'
        
    • POST set_result
      • http://flingo.tv/fling/set_result?guid=G&message_id=I&service=S[&as2_workaround=A]
      • access: restricted
      • A service calls set_result to return a result from a call forwarded via the relay service on flingo.tv. set_result is sent as an HTTP POST and the result is the posted request body. The result is opaque to flingo and can thus be a JSON-RPC result, an XML-RPC result, or any other short message. The passed message id I must match the message id that accompanied the call returned from longpoll. The id is independent of anything that might appear in the posted request body, since the body is opaque. In other words the message id is independent of any JSON-RPC id. S is the name of the service that handled the call.

        See call for a description of as2_workaround.