3 Replies Latest reply on Apr 29, 2011 11:05 AM by ChristopherBos

    Passing additional parameters to StreamingURLResource breaks

    aintnosleeves Level 1

      There does not appear to be a way to pass additional URL parameters to a streamingURLResource request - Either that or I'm just doing it wrong.

       

      I can connect to and stream from a public cloudfront distribution. Connecting looks like this:

       

      var source:String = rtmp://szjv9xu7bkm2jx.cloudfront.net/cfx/st/my_video_file";
      
      
      var resource:StreamingURLResource = new StreamingURLResource(source, StreamType.RECORDED, NaN, NaN, null, true);
      mediaElement = mediaFactory.createMediaElement(resource);
      mediaContainer.container.addMediaElement(mediaElement);
      
      

       

      And the resulting NetConnection call looks like this:

       

      [org.osmf.net.NetNegotiator] Attempting connection to rtmp://szjv9xu7bkm2jx.cloudfront.net/cfx/st

       

      This works just fine. However, I want to protect my content, so I've enabled private streaming, which requires signed URLs to stream content. I'm attempting to pass in the generated signed URL like so:

       

      var source:String = rtmp://szjv9xu7bkm2jx.cloudfront.net/cfx/st/my_video_file?Expires=129000000&Signature=CPXwp8HdWu4TLBTmEi2XfKqqSuYJbo6IrGnFu0eFDgkcu6~CuAJJb8eOxYC9~aPdBI3~tgzvxo3SaC1C30qfSEv8wlSpmG6EW10zLU50OI0uakRIvpoCsFRI2Gx3XSM7iOq~IABF0~SAIZ86KtuwiolFj0Rx~qlmyTKLqyD3nNI_&Key-Pair-Id=APKAI5FAYIVANJF3WD4R";
      
      var resource:StreamingURLResource = new StreamingURLResource(source, StreamType.RECORDED, NaN, NaN, null, true);
      mediaElement = mediaFactory.createMediaElement(resource);
      mediaContainer.container.addMediaElement(mediaElement);
      
      

       

       

      However, this results in the following output from NetNegotiator:

       

      [org.osmf.net.NetNegotiator] Attempting connection to rtmp://szjv9xu7bkm2jx.cloudfront.net:443/cfx/st?Expires=129000000&Signature=CPXwp8HdWu4TLBTmEi2Xf KqqSuYJbo6IrGnFu0eFDgkcu6~CuAJJb8eOxYC9~aPdBI3~tgzvxo3SaC1C30qfSEv8wlSpmG6EW10zLU50OI0uakR IvpoCsFRI2Gx3XSM7iOq~IABF0~SAIZ86KtuwiolFj0Rx~qlmyTKLqyD3nNI_&Key-Pair-Id= APKAI5FAYIVANJF3WD4R

       

      The StreamingURLResource apparently appends the additional data to the NetConnection connect call? Perhaps I'm missing something obvious here, but it seems as though the StreamingURLResource should consider anything after the application instance to be a part of the stream name, not part of the connection URL. Is there some other method for ensuring that the additional params come with the stream name and not the NetConnection?

        • 1. Re: Passing additional parameters to StreamingURLResource breaks
          aintnosleeves Level 1

          Specifically, the following code in NetConnectionFactory beginning on line 410 seems to be the culprit:

           

           

           

          
          private function buildConnectionAddress(url:String, urlIncludesFMSApplicationInstance:Boolean, portProtocol:PortProtocol):String
          {
               var fmsURL:FMSURL = new FMSURL(url, urlIncludesFMSApplicationInstance);
               var addr:String = portProtocol.protocol + "://" + fmsURL.host + ":" + portProtocol.port + "/" + fmsURL.appName + (fmsURL.useInstance ? "/" +      fmsURL.instanceName:"");
          
               // Pass along any query string params
               if (fmsURL.query != null && fmsURL.query != "")
               {
                    addr += "?" + fmsURL.query;
               }
               return addr;
          }
          
          

           

           

          I'm not sure if there are cases where this is the correct action, but I know that at least in this case it does not appear to be. However, the framework does not appear to provide a mechanism for overriding this behavior easily.

           

          There's not a lot of documentation about it, but it appears as though I could do something like this:

           

           

          var resource:StreamingURLResource = new StreamingURLResource(source, StreamType.RECORDED, NaN, NaN, null, true);
          mediaElement = new VideoElement(resource, new CloudFrontNetLoader(new CloudFrontPrivateStreamingNetFactory()))
          mediaContainer.container.addMediaElement(mediaElement);

           

           

          Idea here would be to create a CloudFrontPrivateStreamingNetFactory that overrides the function that creates netconnections, and a CloudFrontNetLoader class that also ensures that the stream URL contains the additional params. Not sure if that's the right track or not, but it looks like that's where I'm headed.

           

          Again, would appreciate any suggestions, thanks!

          • 2. Re: Passing additional parameters to StreamingURLResource breaks
            aintnosleeves Level 1

            Another update - the query params that are passed with a StreamingURLResource and appended to the NetConnection connection URL are ALSO appended to the stream name. I cannot see a case where query parameters passed into a resource should be appended to both a NetConnection URL and a NetStream URL - is there something that I am missing? The query string is added to the stream name in org.osmf.net.NetStreamUtils.as (Line 63):

             

            // Add optional query parameters to the stream name.
            if (fmsURL.query != null && fmsURL.query != "")
            {
                 streamName += "?" + fmsURL.query;
            }
            

             

            My guess is that adding the query to the NetConnection (as I've shown in an above comment) is not usually desired?

             

            At any rate, I managed to make this work by subclassing the NetConnectionFactory class. All I really wanted to do was remove the lines that append the query string to the NetConnection (415-419), but since a few things seems arbitrarily marked as private (why?), a bit more was required. Hope this helps anyone else with the same issue:

             

            package com.readyforce.net
            {
                 import org.osmf.net.NetConnectionFactory;
                 import org.osmf.net.NetConnectionFactoryBase;
                 import org.osmf.net.PortProtocol;
                 import org.osmf.net.FMSURL;
                 import org.osmf.utils.URL;
            
                 public class CloudFrontPrivateNetConnectionFactory extends NetConnectionFactory
                 {
                      public function CloudFrontPrivateNetConnectionFactory()
                      {
                           super();
                      }
                 
                      override protected function createNetConnectionURLs(url:String, urlIncludesFMSApplicationInstance:Boolean=false):Vector.<String>
                      {
                           var urls:Vector.<String> = new Vector.<String>();
                           
                           var portProtocols:Vector.<PortProtocol> = buildPortProtocolSequence(url);
                           for each (var portProtocol:PortProtocol in portProtocols)
                           {
                                urls.push(buildPrivateConnectionAddress(url, urlIncludesFMSApplicationInstance, portProtocol));
                           }
                           
                           return urls;
                      }
                      
                      private function buildPrivateConnectionAddress(url:String, urlIncludesFMSApplicationInstance:Boolean, portProtocol:PortProtocol):String
                      {
                           var fmsURL:FMSURL = new FMSURL(url, urlIncludesFMSApplicationInstance);
                           var addr:String = portProtocol.protocol + "://" + fmsURL.host + ":" + portProtocol.port + "/" + fmsURL.appName + (fmsURL.useInstance ? "/" + fmsURL.instanceName:"");
                           return addr;
                      }
                      
                      private function buildPortProtocolSequence(url:String):Vector.<PortProtocol>
                      {
                           var portProtocols:Vector.<PortProtocol> = new Vector.<PortProtocol>;
                           
                           var theURL:URL = new URL(url);
                           
                           var allowedPorts:String = (theURL.port == "") ? DEFAULT_PORTS: theURL.port;
                           var allowedProtocols:String = "";
                           switch (theURL.protocol)
                           {
                                case PROTOCOL_RTMP:
                                     allowedProtocols = DEFAULT_PROTOCOLS_FOR_RTMP;
                                     break;
                                case PROTOCOL_RTMPE:
                                     allowedProtocols = DEFAULT_PROTOCOLS_FOR_RTMPE;
                                     break;
                                case PROTOCOL_RTMPS:
                                case PROTOCOL_RTMPT:
                                case PROTOCOL_RTMPTE:
                                     allowedProtocols = theURL.protocol;
                                     break;
                           }
                           var portArray:Array = allowedPorts.split(",");
                           var protocolArray:Array = allowedProtocols.split(",");
                           for (var i:int = 0; i < protocolArray.length; i++)
                           {
                                for (var j:int = 0; j < portArray.length; j++)
                                {
                                     var attempt:PortProtocol = new PortProtocol();
                                     attempt.protocol = protocolArray[i];
                                     attempt.port = portArray[j];
                                     portProtocols.push(attempt);
                                }
                           } 
                           return portProtocols;
                      }
                      
                      
                      private static const DEFAULT_PORTS:String = "1935,443,80";
                      private static const DEFAULT_PROTOCOLS_FOR_RTMP:String = "rtmp,rtmps,rtmpt"
                      private static const DEFAULT_PROTOCOLS_FOR_RTMPE:String = "rtmpe,rtmpte";
                      
                      private static const PROTOCOL_RTMP:String = "rtmp";
                      private static const PROTOCOL_RTMPS:String = "rtmps";
                      private static const PROTOCOL_RTMPT:String = "rtmpt";
                      private static const PROTOCOL_RTMPE:String = "rtmpe";
                      private static const PROTOCOL_RTMPTE:String = "rtmpte";
                 }
            }
            
            

            • 3. Re: Passing additional parameters to StreamingURLResource breaks
              ChristopherBos

              You can also do this if you don't want to replicate the private functions

               

               

              public class SecureNetConnectionFactory extends NetConnectionFactory
                   {
              
              
               public function SecureNetConnectionFactory(shareNetConnections:Boolean=true)
               {
               super(shareNetConnections);
               }
               
               override protected function createNetConnectionURLs(url:String, urlIncludesFMSApplicationInstance:Boolean=false):Vector.<String>
               {
               url = stripQueryString(url);
               
               return super.createNetConnectionURLs(url, urlIncludesFMSApplicationInstance);
               }
               
               private function stripQueryString(url:String):String
               {
               var ret:Array = url.split("?");
               
               return ret[0];
               }
               }