NetConnect fails silently in Flash when called from SilverLight - silverlight

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?

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.

Related

Get file size of an URL without download

To get the file size of an URL without download, I wrote:
public static long getFileSizeWithoutDownload(String url) {
ConnectionRequest cr = new GZConnectionRequest();
cr.setUrl(url);
cr.setPost(false);
NetworkManager.getInstance().addProgressListener((NetworkEvent evt) -> {
if (cr == evt.getConnectionRequest() && evt.getLength() > 0) {
cr.kill();
}
});
NetworkManager.getInstance().addToQueueAndWait(cr);
return cr.getContentLength();
}
It seems to work on Simulator, Android and iOS with a testing URL of my Spring Boot server.
Anyway, I consider this code as a workaround, as I couldn't find an API that directly gives me the file size without starting the download first. Starting the download and then killing it works, but maybe there may be a better way to get the same result. By the way, the condition && evt.getLength() > 0 may never be satisfied in some cases (depending on the headers received), so it would be better to read only the headers, in which "Content-Length" may be present or absent.
So, my question is if, with Codename One, there is a way to download only the response headers, without starting the download. Thank you.
Using the HTTP head request should give you the content length header that you can then use to get the size of the file without triggering a download. Your code might not follow through on the download but it does physically happen so a head request would be superior.
Unfortunately while there's a nice wrapper to head in Rest. This wrapper isn't very useful since there's no API to query response headers. That would make sense as an enhancement. You would need to derive ConnectionRequest and read the server response headers to get the content length.
Thank you Shai, your answer https://stackoverflow.com/a/62124902/1277576 led me in the right direction. cr.setHttpMethod("HEAD"); simplifies the code and prevents the download from starting:
public static long getFileSizeWithoutDownload(String url) {
ConnectionRequest cr = new GZConnectionRequest();
cr.setUrl(url);
cr.setHttpMethod("HEAD");
cr.setPost(false);
NetworkManager.getInstance().addToQueueAndWait(cr);
return cr.getContentLength();
}
However, as you wrote, I can override ConnectionRequest for a more precise control of the headers. This other method performs the same function as the previous one, but it also guarantees me that the server supports partial downloads. In fact, if the server does not support partial downloads, the information about the content length would be useless for my purposes:
/**
* Returns -2 if the server doesn't accept partial downloads, -1 if the
* content length is unknow, a value greater than 0 if the Content-Length is
* known
*
* #param url
* #return must be interpreted as a boolean value: if greater than zero than
* partial downloads are supported (the returned value is the Content-Length),
* otherwise they are not supported.
*/
public static long getFileSizeWithoutDownload(String url) {
// documentation about the headers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
Wrapper<Long> result = new Wrapper<>(0l);
ConnectionRequest cr = new GZConnectionRequest() {
#Override
protected void readHeaders(Object connection) throws IOException {
String acceptRanges = getHeader(connection, "Accept-Ranges");
if (acceptRanges == null || !acceptRanges.equals("bytes")) {
Log.p("The partial downloads of " + url + " are not supported.", Log.WARNING);
result.set(-2l);
} else {
String contentLength = getHeader(connection, "Content-Length");
if (contentLength != null) {
result.set(Long.parseLong(contentLength));
} else {
Log.p("The Content-Length of " + url + " is unknown.", Log.WARNING);
result.set(-1l);
}
}
}
};
cr.setUrl(url);
cr.setHttpMethod("HEAD");
cr.setPost(false);
NetworkManager.getInstance().addToQueueAndWait(cr);
return result.get();
}
The readHeaders and getHeader methods are implementation dependent. I have verified that they work as desired on Simulator, Android and iOS.
Lastly, the Wrapper class is so implemented:
/**
* Generic object wrapper, as workaround for the issue "Local variables
* referenced from a lambda expression must be final or effectively final".
*/
public class Wrapper<T> {
private T object;
public Wrapper(T obj) {
this.object = obj;
}
public T get() {
return object;
}
public void set(T obj) {
this.object = obj;
}
}
I hope this detailed answer will help those who need to read HTTP headers with Codename One.

how do i convert these c# winform codes to be compatible on c# wpf?

hi im working on a project that uses invoke and threads.. it is a simple remote desktop program with chat.. i got a sample here on the internet in c# winform, but i would like to convert it to wpf.. i have no problem in sending message to another client using the wpf program but it cannot receive ( or cannot read) the sent messages from the others.. i think it has something to do with the thread and the invoke method, i read that wpf does invoke differently and i did try the dispatcher.invoke, but it still doesnt do the trick
pls hellp
here's the code
wait = new Thread(new ThreadStart(waitForData));
wait.Start();
that snippet above is executed when a successful connection is made in tcpclient
private void waitForData()
{
try
{
NetworkStream read = tcpclnt.GetStream();
while (read.CanRead)
{
byte[] buffer = new byte[64];
read.Read(buffer, 0, buffer.Length);
s = new ASCIIEncoding().GetString(buffer);
System.Console.WriteLine("Recieved data:" + new ASCIIEncoding().GetString(buffer));
rcvMsg = new ASCIIEncoding().GetString(buffer) + "\n";
hasNewData = true;
bool f = false;
f = rcvMsg.Contains("##");
bool comand = false;
comand = rcvMsg.Contains("*+*-");
/*File receive*/
if (f)
{
string d = "##";
rcvMsg = rcvMsg.TrimStart(d.ToCharArray());
int lastLt = rcvMsg.LastIndexOf("|");
rcvMsg = rcvMsg.Substring(0, lastLt);
NetworkStream ns = tcpclnt.GetStream();
if (ns.CanWrite)
{
string dataS = "^^Y";
byte[] bf = new ASCIIEncoding().GetBytes(dataS);
ns.Write(bf, 0, bf.Length);
ns.Flush();
}
try
{
new Recieve_File().recieve_file(rcvMsg);
}
catch (Exception ec)
{
System.Console.WriteLine(ec.Message);
}
}
/*Command-shutdown/restart/logoff*/
else if (comand)
{
string com = "*+*-";
rcvMsg = rcvMsg.TrimStart(com.ToCharArray());
execute_command(rcvMsg);
}
else
{
this.Invoke(new setOutput(setOut));
Thread.Sleep(1000);
}
}
}
catch (Exception ex)
{
wait.Abort();
output.Text += "Error..... " + ex.StackTrace;
}
}
the snippet above is a code that listens if there is a message or command.. the line
this.invoke(new setoutput(setout)) is a code for appending text in the rtb
hope someone could help me thanks
You've posted a lot of code, but I'm assuming it's only the call to Control.Invoke which is causing the problem. In WPF, use Dispatcher.Invoke (or Dispatcher.BeginInvoke) instead, via the Dispatcher property on the relevant UI element.
I'd also strongly encourage you to:
Refactor your code into smaller methods
Stop catching just Exception except at the top level of any large operation (it should just be a fall-back; usually you catch specific exceptions)
Start following .NET naming conventions
Add a using directive for System so you can just write Console.WriteLine instead of System.Console.WriteLine everywhere
Use Encoding.ASCII instead of creating a new ASCIIEncoding each time you need one
Use a StreamReader to read character data from a stream, instead of reading it as binary data first and then encoding it
For either Stream or TextReader, don't ignore the return value from Read - it tells you how many bytes or characters have been read

Application Won't 'new' when called

I am calling a new xaml application with some parameter inputs using the word new, but it does not seem to be working. I am also attempting to use onclosing to set it to null. When launching it for the first time it works (everything is new), but launching it after it finished, it seems to continue its previous state (brings to finished score board). Here is the snipplet of the code . . .
quizUI = new QuizzUI.MainWindow(App.User, true);
quizUI.Closed += (o, s) =>
{
quizUI = null;
};
quizUI.LaunchQuiz(qSet);
this is hooked to a button event. does anyone know how i can absolutely new this object's state every time? the two paramters are user's info and second one is to shortcut without prompt screen/loading screen.
Here is the code for QuizzUI.MainWindow.LaunchQuizz:
public void LaunchQuiz(GameQuizzSet quiz)
{
this.Hide();
quizz = new QuizzContainer()
{
QSet = quiz,
};
if (isShortCutted)
{
bool? diag = quizz.ShowDialog();
if (diag.HasValue)
{
quizz.Close();
Close();
}
}
else
{
quizz.ShowDialog();
this.Show();
}
}
the QuizzUI.MainWindow allows the user to select their profile and which quiz to execute.

WIA silverlight Scanner integration

I am new to silverlight , and I am experimenting with wia scanner integration. I know usng WIA.CommonDialog , showacquireimage() I can retrieve an image from the scanner. I am trying to access the device directly and execute the scan command to avoid user interaction.
I am able to connect to the device. But the only command available from the scanner is synchronize. I am trying to use the ExecuteCommand on the device object, but I am not sure what command to use. Any direction will be appreciated.
using (dynamic DeviceManager1 = AutomationFactory.CreateObject("WIA.DeviceManager"))
{
var deviceInfos = DeviceManager1.DeviceInfos;
for(int i= 1;i<=deviceInfos.Count;i++)
{
//check if the device is a scanner
if (deviceInfos.Item(i).Type.ToString() == "1")
{
var IDevice = deviceInfos.Item(i).Connect();
deviceN.Text = IDevice.Properties("Name").Value.ToString();
var dv = IDevice.Commands;
for (int j = 0; j <= dv.Count; j++)
{
deviceN.Text += " " + dv.Item(i).CommandID.ToString() + " " + dv.Item(i).Description.ToString();
}
}
}
}
You don't really need to deal with the device commands to scan the document. Instead you need to use the first device item under the device object. Here is a little example which works in itself, without failure checks for easier readability.
//using WIA;
bool showProgressBar = false;
DeviceManager deviceManager = new DeviceManagerClass();
foreach(DeviceInfo info in deviceManager.DeviceInfos)
{
if(info.Type == WiaDeviceType.ScannerDeviceType)
{
Device device = info.Connect();
ImageFile imageFile = null;
Item deviceItem = null;
//Read through the list of items under the device...
foreach(Item item in device.Items)
{
//Pick the very first one!
deviceItem = item;
break;
}
if(showProgressBar == true)
{
//Scan without GUI, but display the progress bar dialog.
CommonDialogClass commonDialog = new CommonDialogClass();
imageFile = (ImageFile)commonDialog.ShowTransfer(deviceItem, FormatID.wiaFormatBMP, false);
}
else
{
//Scan without GUI, no progress bar displayed...
imageFile = (ImageFile)deviceItem.Transfer(FormatID.wiaFormatBMP);
}
imageFile.SaveFile("C:\\image.bmp");
}
}
Before scanning (but after you connected to the device item), you probably need to set various device properties to select the scanning resolution, color depth and other things if the defaults are not good enough for your needs.
Not long ago I made an easy to use class to operate WIA-compatible scanners, you can download it from this page... It's for .Net Framework 2.0, C#. Maybe it could come handy in your project, you would be done with a few lines of code including setting the basic properties. :)

Large method causing silverlight application to go into "Not responding" state

I am working on an application that plays videos through the silverlight MediaElement object.
I have a large method which is responsible for the following
Opens a FileInfo item on the local file path of the video and strips the file name to get the first portion of the filename which we use as part of the license acquisition process
Sets the LicenseAcquirer on the MediaElement
Sets the Source property of the MediaElement
When this method is called, it actually causes the application to go into a "Not reponding" state for a couple of seconds. How do I avoid this? I have tried putting this all into a background worker but I have to invoke the UI thread for almost all of the calls and this didnt help it seemed to actually make things slower.
I have a busy box that shows while this all happens but that actually stops reporting progress in those seconds where the application is not responding. I understand why this is happening - a lot of work happening on the main UI thread, but how do I avoid this?
This is the code that is causing the trouble:
private void SetupMediaElement(String mediaElementType)
{
Messenger.Default.Send("Loading video...", "SetNowWatchingVideoBusyBoxText");
Messenger.Default.Send(true, "SetNowWatchingVideoBusyBox");
try
{
if (_mainMediaElement != null)
{
VideoItem vi = CurrentSession.NowPlayingVideoItem;
if (vi != null)
{
CurrentVideoItem = vi;
MustShowImage = true;
if (vi.ID != string.Empty)
{
String mediaId = String.Empty;
if (vi.LocalFilePath != DEMOVIDEOPATH)
{
if (vi.LocalFilePath != String.Empty)
{
var fi =
new FileInfo(vi.LocalFilePath);
if (fi.Exists)
{
mediaId = fi.Name.Substring(fi.Name.LastIndexOf('-') + 1,
(fi.Name.LastIndexOf('.') -
(fi.Name.LastIndexOf('-') + 1)));
}
}
else
{
Debug.WriteLine("localFilePath is empty");
}
Debug.WriteLine("MediaId = " + mediaId +
", SessionId = " +
CurrentSession.LoggedOnUser.SessionId +
",Ticket = " +
CurrentSession.LoggedOnUser.Ticket);
string licenseURL = GetLicenseURL(mediaId, CurrentSession.LoggedOnUser.SessionId,
CurrentSession.LoggedOnUser.Ticket);
if (licenseURL != string.Empty)
{
var la = new LicenseAcquirer
{
LicenseServerUriOverride
=
new Uri(
licenseURL)
};
la.AcquireLicenseCompleted += la_AcquireLicenseCompleted;
_mainMediaElement.LicenseAcquirer = la;
}
var fileInfo = new FileInfo(vi.LocalFilePath);
string playURL = #"file://" +
Path.Combine(CoreConfig.HOME_FULL_PATH, fileInfo.Name);
playURL = playURL.Replace("\\", #"/");
VideoURL = playURL;
}
else
{
VideoURL = vi.LocalFilePath;
Messenger.Default.Send(false, "SetNowWatchingVideoBusyBox");
}
_totalDurationSet = false;
TotalTime = FormatTextHoursMinutesSecond(_mainMediaElement.NaturalDuration.TimeSpan);
SetSliderPosition();
}
}
else
{
Messenger.Default.Send(false, "SetNowWatchingVideoBusyBox");
}
}
else
{
Messenger.Default.Send(false, "SetNowWatchingVideoBusyBox");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
VideoURL = DEMOVIDEOPATH;
Messenger.Default.Send(false, "SetNowWatchingVideoBusyBox");
}
}
Thanks
EDIT:
So it turns out that the method posted above is NOT the cause of the delay - that code executes in under a second. The problem comes in when the media element's source is set and it reads the file to the end - large files take time and this is the delay. Am opening a new question based on this.
You should do some diagnostics to determine which line(s) are truely costing all that time, its unlikely that amount of time is spread evenly across the whole function.
Place that line (or lines) in a background thread (hopefully that line doesn't need to be on the UI thread).
So it turns out that the method posted above is NOT the cause of the delay - that code executes in under a second. The problem comes in when the media element's source is set and it reads the file to the end - large files take time and this is the delay. Am opening a new question based on this.

Resources