msgbartop
Various ramblings-on, mostly about Red5
msgbarbottom

25 Feb 15 Release of Actionscript for my mobile broadcaster

Today I decided to release the AIR / Actionscript source for my Google Play app for broadcasting to Flash media servers; you can find it on github https://github.com/mondain/BroadcasterFreeAS

Enjoy

Tags: , , , ,

28 Jan 09 RTMPT and Red5

By default or so I’ve been told, the Flash Player will try various ports when attempting to connect to a resource. In Red5, RTMP is supported out-of-the-box on the default RTMP port of 1935 and HTTP is setup on 5080. A “special” server is started on 8088 as well to handle RTMPT only requests, but this requires that you set your request url as “rtmpt://myserver:8088/myapp/” which can be confusing and completely ignores the Flash Player port probing. So I offer this solution, allowing you to setup HTTP on port 80 and RTMPT on port 80 as well. Since Red5 includes a servlet container (Tomcat by default), you have a full-fledged HTTP server and servlet engine built-in; allowing a servlet to answer the RTMPT requests.
The first file we need to modify is the server properties file located in the conf directory:
red5/conf/red5.properties

  • Locate the http.port key and change it to 80 instead of 5080
  • Do not change the rtmpt.port entry, it should be 8088
  • Save and close the file

The last file to modify will be your web application configuration or “web.xml” file. The web application configuration file will be located here: red5/webapps/myapp/WEB-INF/web.xml if your application name is “myapp”. Add these entries:

    
   	<servlet>
		<servlet-name>rtmpt</servlet-name>
		<servlet-class>org.red5.server.net.rtmpt.RTMPTServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
    
	<servlet-mapping>
		<servlet-name>rtmpt</servlet-name>
		<url-pattern>/fcs/*</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>rtmpt</servlet-name>
		<url-pattern>/open/*</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>rtmpt</servlet-name>
		<url-pattern>/close/*</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>rtmpt</servlet-name>
		<url-pattern>/send/*</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>rtmpt</servlet-name>
		<url-pattern>/idle/*</url-pattern>
	</servlet-mapping>

Informational links about FlashPlayer and ports:
HTTP Tunneling protocols

The Trouble with Proxy Servers

Tags: , , , , , , ,

23 Jan 09 The dreaded 2044 error

For those of us who have encountered this error, we can understand each others pain. I searched all around and never found a solution to my particular situation. I found Renaun’s post helpful but it didn’t resolve my issue, as well as these other posts:

http://renaun.com/blog/2007/07/21/226/

http://www.lonhosford.com/lonblog/2008/03/13/flex-liveconnection-and-legacy-flash-swfs/

http://blog.kazumakzak.com/2008/11/26/flex-actionscript-project-sandbox-error-error-2044/

So here is how this all came about – I had built an AIR application using FlexBuilder, which created a LocalConnection to listen for events from a Native (C++) Windows application. The error would occur when the native application was executed prior to starting the AIR application. I tried everything to catch the error and prevent the dialog from appearing; in FlexBuilder this was especially annoying because the dialog would popup behind the IDE before the application window was visible and prevent it from becomming visble until the dialog was closed. I tried creating the LocalConnection on the following events of WindowedApplication:

initialize

addedToStage

applicationComplete

windowComplete

None of which worked, this is also the order in which these event fire by-the-way. So as a last resort, I tried the “preloader” option and BINGO! The preloader runs just before the application so it is able to catch the events comming from the native application, since it would appear that Flash starts listening too early (in my case). Now on to the code…

Add the preloader attribute to the top of your application mxml

preloader="org.gregoire.Preloader" 

Preloader.as

package org.gregoire {

	import org.gregoire.event.*;
	import org.gregoire.net.*;

	import mx.preloaders.DownloadProgressBar;	

	public class Preloader extends DownloadProgressBar {   

		private var localCon:CustomLocalConnection;
		private var srcWidth:int;
		private var srcHeight:int;		

		public function Preloader() {
			super();
			trace("Preload");
			try {
				//create local connection to provide capture source dimensions
				localCon = new CustomLocalConnection("_myBrowser");
				//setup event listeners for changes on the capture source
				localCon.addEventListener(SourceEvent.CHANGED, sourceEventHandler);
			} catch(e:Error) {
				trace("Error with (preloader) LC: " + e);
			}
		}

		private function sourceEventHandler(event:SourceEvent):void {
			trace("Preloader Source change event: " + event);
			srcWidth = event.getWidth();
			srcHeight = event.getHeight();
		}		

		public function hasDimensions():Boolean {
			return (srcWidth > 0 && srcHeight > 0);
		}

		public function getSourceWidth():int {
			return srcWidth;
		}

		public function getSourceHeight():int {
			return srcHeight;
		}

		public function unregister():void {
			localCon.removeEventListener(SourceEvent.CHANGED, sourceEventHandler);
			localCon.close();
			localCon = null;
		}

	}

}

CustomLocalConnection.as

package org.gregoire.net {

    import flash.net.LocalConnection;
    import flash.events.StatusEvent;
    import flash.events.SecurityErrorEvent;
    import org.gregoire.event.SourceEvent;

    public class CustomLocalConnection extends LocalConnection {

        public function CustomLocalConnection(connectionName:String) {
            try {
            	super();
                addEventListener(StatusEvent.STATUS, onStatus);
                addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);

                allowDomain("*");
				client = this;
                connect(connectionName);

            } catch (error:ArgumentError) {
                // server already created/connected
            }
        }

        public function onSourceSelect(sourceName:String):void {
            trace("onSourceSelect called: " + sourceName);
            var evt:SourceEvent = new SourceEvent();
            evt.setSourceName(sourceName);
            dispatchEvent(evt);
        }

        public function onSize(dimension:String):void {
            trace("onSize called: " + dimension);
            //split the dimension string into width and height
            var arr:Array = dimension.split("|", 2);
            if (arr.length >= 2) {
	            var evt:SourceEvent = new SourceEvent();
            	evt.setWidth(parseInt(arr[0]));
            	evt.setHeight(parseInt(arr[1]));
            	dispatchEvent(evt);
            } else {
            	trace("Dimension could not be properly parsed");
            }

        }

		private function onStatus(event:StatusEvent):void {
			trace("LC event: " + event);
			switch (event.level) {
               case "status":
                   trace("LocalConnection.send() succeeded");
                   break;
               case "error":
                   trace("LocalConnection.send() failed");
                   break;
        	}
		}

		private function onSecurityError(e:Error):void {
			trace("LC error: " + e);
		}		

    }
}

SourceEvent.as

package org.gregoire.event {

	import flash.events.Event;

	public class SourceEvent extends Event {

		public static const CHANGED:String = "sourceChanged";

		private var sourceName:String;
		private var width:int;
		private var height:int;

		public function SourceEvent() {
			super(CHANGED);
		}

        public function getSourceName():String {
        	return sourceName;
        }

        public function setSourceName(sourceName:String):void {
        	this.sourceName = sourceName;
        }

        public function getWidth():int {
        	return width;
        }

        public function setWidth(width:int):void {
        	this.width = width;
        }

        public function getHeight():int {
        	return height;
        }

        public function setHeight(height:int):void {
        	this.height = height;
        }

        // Override the inherited clone() method.
        override public function clone():Event {
            return new SourceEvent();
        }

		override public function toString():String{
			return "[SourceEvent] sourceName="+sourceName+",width="+width+",height="+height;
		}

	}
}

I cannot release more than that at this time, but I will try to provide more later if possible. This information should be enough to get you past the 2044 error.

Tags: , , , ,


Fatal error: Call to undefined function akismet_counter() in C:\xampp\htdocs\paulgregoireblog\wp-content\themes\googlechrome\footer.php on line 9