views:

246

answers:

1

This is a complex question, because there are a lot of moving parts. My apologies in advance.

I'm trying to write a Silverlight control that hosts a Flash camera and microphone (since Silverlight doesn't support these things natively, worse luck). I've written a short little Flex application ("WLocalWebCam.swf") which handles the camera, and exposes two external methods: connect(uri:String, streamName:String), and disconnect(). I can call these successfully through JavaScript as follows (simplified to remove error handling, etc.):

function connectWebCam(webCamID, rtmpUri, streamName) {
    var flashCam = getWebCam(webCamID);
    flashCam.Connect(rtmpUri, streamName);
}

function disconnectWebCam(webCamID) {
    var flashCam = getWebCam(webCamID);
    flashCam.Disconnect();
}

function getWebCam(id) {
    return document.getElementById(id);
}

When I call these functions from another JavaScript source (e.g., a button click handler), the web cam connects correctly up to the RTMP server (I'm using Wowza). However, when I call exactly these same functions on the same page from Silverlight, the Flash camera fails to connect to the RTMP server.

/// <summary>
/// Connect() invokes the connectWebCam() JavaScript function contained in the WebCam.js file on the website.
/// The connectWebCam() method in turn calls the Connect() method on the contained Flash web cam object.
/// </summary>
public void Connect()
{
    ScriptObject connectWebCam = (ScriptObject)HtmlPage.Window.GetProperty("connectWebCam");
    connectWebCam.InvokeSelf(CameraID, RtmpUri.ToString(), CameraID);
}

However, it fails in an interesting fashion. The ActionScript connect() method gets called, it successfully calls getConnection(), but the handleNetStatus event handler method never gets called, and the Wowza server never sees an attempt to connect.

Here's the ActionScript code I'm using, this time with the debugging bits left in.

public function connect(uri:String, name:String):void
{
 rtmpUri = uri;
 streamName = name;
 logMessage("Beginning attempt to open connection; rtmpUri=" + rtmpUri + "; streamName = " + streamName);
 logMessage("Retrieving camera.");
 cam = Camera.getCamera();
 if( cam != null )
 {
  logMessage("Retrieved camera.");
  cam.setMode( 320, 240, 20 );
  cam.setQuality( 0,0 );   
 }
 else
 {
  logMessage("Unable to retrieve camera instance.");
 }

 logMessage("Retrieving microphone.");
 mic = new Microphone();
 if (mic == null)
 {
  logMessage("Unable to retrieve microphone instance.");
 }
 logMessage("Retrieving NetConnection.");
 chatNC = getConnection(); 
}

private function getConnection(): NetConnection
{
 var nc: NetConnection = new NetConnection(); 
 if (nc != null)
 {
  logMessage("Retrieved NetConnection().");
  nc.client = this;
  nc.objectEncoding = ObjectEncoding.AMF0;
  nc.addEventListener( NetStatusEvent.NET_STATUS, this.handleNetStatus );
  logMessage("Connecting to " + rtmpUri);
  nc.connect(rtmpUri); // <-- We get successfully to this point.
 }
 else
 {
  logMessage("Unable to retrieve new NetConnection()");
 }       
 return nc;
}

private function handleNetStatus( event:NetStatusEvent ):void
{
 logMessage("[SYSTEM MESSAGE] net status " + event.info.code + "  type " + event.type); // <-- We never get this far.  This bit never gets called.

 switch( event.info.code )
 {
  case "NetConnection.Connect.Success":
   publishVideoStream();
   break;
  default:
   Alert.show("Error connecting: " + event.info.code, "Error Connecting");
   break;
 }
}

This has got me seriously scratching my head.

Does anyone know why the exact same ActionScript would behave differently if called from Silverlight vs. being called from JavaScript? Any suggestions on troubleshooting it?

A: 

Sigh. Never mind. Turns out it makes a difference if you try to connect to "http://localhost/videochat" instead of "rtmp:://localhost/videochat". It all works as expected when you give it the right parameters. I must have looked at that code a hundred times before I spotted what I did wrong.

Ken Smith