GameInput.DEVICE_ADDED not triggering at application startup - actionscript-3

I'm posting this question because i'm having a little problem with the GameInput API in an adobe AIR desktop app.
I tested the API in a test app and it worked just fine. However, when i added it to my real app (a game), it doesn't trigger anymore at startup.
Everything else works, and if i disconnect/reconnect the controller, everything works fine. However, the initial trigger of the callback function isn't working anymore.
Any idea why ?
Here's what i do:
if (GameInput.isSupported) //GAMEPADS SUPPORT
{
gameInput = new GameInput();
gameInput.addEventListener(GameInputEvent.DEVICE_ADDED, controllerAdded);
gameInput.addEventListener(GameInputEvent.DEVICE_REMOVED, controllerRemoved);
gameInput.addEventListener(GameInputEvent.DEVICE_UNUSABLE, controllerProblem);
} //GAMEPAD SUPPORT
public function controllerAdded(e:GameInputEvent):void
{
var vec:Vector.<String> = new Vector.<String>();
gamepad = GameInput.getDeviceAt(0);
vec[0] = gamepad.getControlAt(0).id;
gamepad.enabled = true;
gamepad.sampleInterval = 10;
gamepad.startCachingSamples(5, vec); // numSamples = 5
for (var i:int = 0; i < gamepad.numControls; ++i)
gamepad.getControlAt(i).addEventListener(Event.CHANGE, handleChangeEvent);
}
I am guessing it could be a focus issue or something related but i really don't see why this would be happening.
My app looks like this:
Core (class called from swf and manages the whole app)
Screens (different classes that inherit movieclip but have logic inside, such as game, optionscreen, etc.)
The Gameinput api intialization is done in the core, after the instanciation of the object (using Event.ADDED_TO_STAGE).

The GameInputEvent class represents an event that is dispatched when a game input device has either been added or removed from the application platform
So if you launch the app and allready have a device, no event will be triggered which sounds like your issue. Why don't you just check devices during intialization and then work with them at that point?
if (GameInput.isSupported) //GAMEPADS SUPPORT
{
gameInput = new GameInput();
gameInput.addEventListener(GameInputEvent.DEVICE_ADDED, controllerAdded);
gameInput.addEventListener(GameInputEvent.DEVICE_REMOVED, controllerRemoved);
gameInput.addEventListener(GameInputEvent.DEVICE_UNUSABLE, controllerProblem);
if(GameInput.numDevices > 0) {
/*enter code here/*
}
}

Well it seems the GameInput API by Adobe is too unstable.
I've decided to use AirControl instead and it works much better...
I'm therefore closing this question.

Related

AS3 using Workers

IDE: FLASH CS6 Professional
SDK: AIR 18 for Android
I'm trying to use Workers for my app.
The problem is, it doesn't work that it suppose to be.
public class Main extends Sprite {
private var worker:Worker;
public function Main() {
var ba:ByteArray = this.loaderInfo.bytes;
if(Worker.current.isPrimordial){
worker = WorkerDomain.current.createWorker(ba);
worker.start();
trace("Created Main");
}else{
trace("Created Worker");
}
}
}
It should output
Created Main
Created Worker
but i'm only getting
[SWF] Test.swf - 2831 bytes after decompression
Created Main
[UnloadSWF] Test.swf
Test Movie terminated.
EDIT:
Ok i tried to publish the app and ran it. It works like it should be. But why doesn't it work when i try to ran it with Adobe Debug Launcher ?
This is what it looks like on Android Debug Launcher (ADL)
ADL
This is what it looks like when Published.
Published
EDIT 2:
Tried it with Flash Professional CC 2015. Upgraded to AIR SDK 19.0.0.213.
Still the same result. What a pain Adobe.
It should work, but Flash Pro CS6 doesn't show the worker's trace statements. Check flashlog.txt or send messages from the worker to the main SWF over a MessageChannel.
I made a lib to support use of Workers, if you want use you can check it in GitHub, it is open source project.. hope help ASWorker Link
The implementation is like this
package
{
import com.tavernari.asworker.ASWorker;
import com.tavernari.asworker.notification.NotificationCenter;
import com.tavernari.asworker.notification.NotificationCenterEvent;
import flash.display.Sprite;
public class ASWorkerDemo extends Sprite
{
private var asWorker:ASWorker;
//BOTH AREA
public function ASWorkerDemo()
{
//important know, all class start here will be replicated in all works.
asWorker = new ASWorker(this.stage, uiWorkerStartedHandler, backWorkerStartedHandler);
}
//BOTH AREA END
//UI AREA START
private function uiWorkerStartedHandler():void{
//implement all class or calls for your UI
NotificationCenter.addEventListener("FROM_BACK_EVENT_MESSAGE", onFromBackEventMessageHandler );
}
private function onFromBackEventMessageHandler(e:NotificationCenterEvent):void
{
trace(e.data);
if(e.data == "completed job"){
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("NEXT_MESSAGE") );
}
}
//UI AREA END
//BACK AREA START
private function backWorkerStartedHandler():void{
//implement all class or calls for your BACK operations
NotificationCenter.addEventListener("NEXT_MESSAGE", uiCallForNextMessageHandler );
}
private function uiCallForNextMessageHandler():void
{
for(var i:int = 0; i < 15; ++i){
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("FROM_BACK_EVENT_MESSAGE", false, i) );
}
NotificationCenter.dispatchEventBetweenWorkers( new NotificationCenterEvent("FROM_BACK_EVENT_MESSAGE", false, "completed job") );
}
// BACK AREA END
}
}
Good luck with Workers
Air 20.0.0.204 ADL is also not enjoying anything worker related (from my limited experimentation), however the desktop Flash Player seems to work just fine. This makes debugging convoluted and problematic when you are using Air specific libraries in your project and prefer not to wildcard variable types.
At the moment, workers are only supported on desktop platform. This Adobe developer's guide page specifically mentions "for desktop platforms".
Meanwhile, there is an AS3-Worker-Compat library by Jeff Ward that enables you to write code with Workers that will still work correctly in an environment that doesn't support Workers (of course, in this case your code will run in single-threaded mode).
I think many people are waiting for Adobe to implement workers for mobile, hopefully it will come in the future.

Unable to free my webcam in Actionscript 3.0

To free my webcam I'm using
onScrenVideo.attachCamera(null)
where onScreenVideo is a Video object.
However, this just doesn't seem to work. Even after this line executes, the webcam light remains ON.
I have scoured the Internet for a solution to this problem and everyone seems to be unanimous that this is the only way to turn the webcam off (for example : Close webcam usage via actionscript), however, this just doesn't seem to be working for me.
Can anyone help?
Thanks
Edit: Adding relevant code.
All the variables are declared previously. Here's the code to set up the Camera and attach it to the video.
testCurrCam = Camera.getCamera();
onScreenVideo = new Video(240, 180);
onScreenVideo.smoothing = true;
onScreenVideo.x = 0;
onScreenVideo.y = 0;
addChild(onScreenVideo);
testCurrCam.setQuality(0, 70);
testCurrCam.setMode(640, 480, 10);
onScreenVideo.attachCamera(testCurrCam);
And here's a function which is called by Javascript using ExternalInterface. The call works perfectly fine, because I've checked using an alert box after the if condition.
private function stopCam(): void {
if (contains(onScreenVideo)) {
onScreenVideo.attachCamera(null);
this.removeChild(onScreenVideo);
onScreenVideo = null;
testCurrCam = null;
} else
return;
}

How to do CreateBindingSet() on Windows Phone?

In the N+1 video #34 (Progress), there was an example of using CreateBindingSet() for the Android version, which is not typical. But the narrator also mentioned briefly that the same can be done on the Windows platform.
As much as I tried, however, I am unable to get a View's property to be bound to its ModelView on the Windows Phone. I always get a NullReferenceException.
The closest I came was the code below, including suggestions from ReSharper. Here's my FirstView.xaml.cs:
using Cirrious.MvvmCross.Binding.BindingContext;
using Whatever.ViewModels;
namespace Whatever {
// inheriting from IMvxBindingContextOwner was suggested by ReSharper also
public partial class FirstView : BaseView, IMvxBindingContextOwner {
public class MyBindableMediaElement
{
private string _theMediaSource = "whatever";
public string TheMediaSource
{
get
{
return _theMediaSource;
}
set
{
_theMediaSource = value;
}
}
}
public FirstView()
{
InitializeComponent();
_mediaElement = new MyBindableMediaElement(this.theMediaElement);
var set = this.CreateBindingSet<FirstView, FirstViewModel>();
// the corresponding view model has a .SongToPlay property with get/set defined
set.Bind(_mediaElement).For(v => v.TheMediaSource).To(vm => vm.SongToPlay);
set.Apply();
}
public IMvxBindingContext BindingContext { get; set; } // this was suggested by ReSharper
}
I get a NullReferenceException in MvxBaseFluentBindingDescription.cs as soon as the view is created. The exact location is below:
protected static string TargetPropertyName(Expression<Func<TTarget, object>> targetPropertyPath)
{
var parser = MvxBindingSingletonCache.Instance.PropertyExpressionParser; // <----- exception here**
var targetPropertyName = parser.Parse(targetPropertyPath).Print();
return targetPropertyName;
}
I have not seen a working example of creating a binding set on a Windows Phone emulator. Has anyone gotten this to work? Thanks.
I can confirm that the narrator said that remark a little too flippantly without actually thinking about how he might do it...
However, with a little effort, you definitely can get the CreateBindingSet to work in Windows if you want to.
Before you start, do consider some alternatives - in particular, I suspect most people will use either Windows DependencyProperty binding or some hand-crafted code-behind with a PropertyChanged event subscription.
If you do want to add CreateBindingSet code to a Windows project then:
Add the Binding and BindingEx assemblies to your Ui project - the easiest way to do this is using nuget to add the BindingEx package.
In your Setup class, override InitializeLastChance and use this opportunity to create a MvxWindowsBindingBuilder instance and to call DoRegistration on that builder. Both these first two steps are covered in the n=35 Tibet binding video - and it's this second step that will initialise the binding framework and help you get past your current 'NullReferenceException' (for the code, see BindMe.Store/Setup.cs)
In your view, you'll need to implement the IMvxBindingContextOwner interface and you'll need to ensure the binding context gets created. You should be able to do this as simply as BindingContext = new MvxBindingContext();
In your view, you'll need to make sure the binding context is given the same DataContext (view model) as the windows DataContext. For a Phone Page, the easiest way to do this is probably just to add BindingContext.DataContext = this.ViewModel; to the end of your phone page's OnNavigatedTo method. Both steps 3 and 4 could go in your BaseView if you intend to use Mvx Binding in other classes too.
With this done, you should be able to use the CreateBindingSet code - although do make sure that all binding is done after the new MvxBindingContext() has been created.
I've not got a windows machine with me right now so I'm afraid this answer code comes untested - please do post again if it does or doesn't work.
I can confirm it works almost perfectly; the only problem is, there are no defaults register, so one has to do the full binding like:
set.Bind(PageText).For(c => c.Text).To(vm => vm.Contents.PageText).OneTime();
to fix this, instead of registering MvxWindowsBindingBuilder, I am registering the following class. Note: I have just created this class, and needs testing.
public class UpdatedMvxWindowsBindingBuilder : MvxWindowsBindingBuilder
{
protected override void FillDefaultBindingNames(IMvxBindingNameRegistry registry)
{
base.FillDefaultBindingNames(registry);
registry.AddOrOverwrite(typeof(Button), "Command");
registry.AddOrOverwrite(typeof(HyperlinkButton), "Command");
//registry.AddOrOverwrite(typeof(UIBarButtonItem), "Clicked");
//registry.AddOrOverwrite(typeof(UISearchBar), "Text");
//registry.AddOrOverwrite(typeof(UITextField), "Text");
registry.AddOrOverwrite(typeof(TextBlock), "Text");
//registry.AddOrOverwrite(typeof(UILabel), "Text");
//registry.AddOrOverwrite(typeof(MvxCollectionViewSource), "ItemsSource");
//registry.AddOrOverwrite(typeof(MvxTableViewSource), "ItemsSource");
//registry.AddOrOverwrite(typeof(MvxImageView), "ImageUrl");
//registry.AddOrOverwrite(typeof(UIImageView), "Image");
//registry.AddOrOverwrite(typeof(UIDatePicker), "Date");
//registry.AddOrOverwrite(typeof(UISlider), "Value");
//registry.AddOrOverwrite(typeof(UISwitch), "On");
//registry.AddOrOverwrite(typeof(UIProgressView), "Progress");
//registry.AddOrOverwrite(typeof(IMvxImageHelper<UIImage>), "ImageUrl");
//registry.AddOrOverwrite(typeof(MvxImageViewLoader), "ImageUrl");
//if (_fillBindingNamesAction != null)
// _fillBindingNamesAction(registry);
}
}
This is a skeleton from Touch binding, and so far I have only updated three controls to test out (Button, HyperButton and TextBlock)

From synchronous flow to asynchronous flow dilemma

As a PHP programmer I'm very habituated to the fact that the program flow goes line by line, if I call function1() that have to return some value I know the program wont continue until that function makes a return.
Now, im developing a AS3 app using AIR, I need to download some images if some conditions are met, don't know how many, so im using a For like this:
for (var w:int=0; w < newData_array[2]['content'].length; w++ ) {
for (var j:int=0; j < oldData_array[2]['content'].length; j++ ) {
if((oldData_array[2]['content'][j]['id'] == newData_array[2]['content'][w]['id']) && (oldData_array[2]['content'][j]['last_mod'] != newData_array[2]['content'][w]['last_mod'])){
//need to download a image...
}
}
}
As you can see im just comparing each element from each array (newData_array and oldData_array). If the condition met, I need to download something, for that I'm using URLloader and as you know this function is asynchronous, adding a listener, an event will be triggered when the download is complete, the problem is very clear, since the urlloader wont stop the for cycle (like I would expect on a PHP alike language) I'm just going to download a bunch of images at the same time creating a disaster because I wont know when to save. So I need to use by any mean the listener, but since I'm not very habituated to this kind of procedures I'm pretty munch stuck.
Im not interested on the save to disk routines, that part is pretty much done, I just want to understand how I should structure this algorithm to make this work.
This annoyed me too, but one has to realize that you can't do something to something that doesn't exist in memory yet, and these loading operations can take quite some time. Being a single-threaded stack, Flash Player's load operations would require that the entire interface to freeze during the load (if restricted to the loop).
Obviously there's data available to the loop that dictates what you do with the image. The solution I've been using is create a custom load function that starts the load, and returns a proxy image . Your loop gets a container back and you can freely place your image where you want.
In the meantime, your loader listener has kept track of the active images loading, and their associated proxies. When loaded, swap the image in.
Your loop would look something like this...
for (var w:int in newData_array[2]['content']) {
for (var j:int in oldData_array[2]['content']) {
if ((oldData_array[2]['content'][j]['id'] == newData_array[2]['content'][w]['id']) && (oldData_array[2]['content'][j]['last_mod'] != newData_array[2]['content'][w]['last_mod'])){
var proxy:MovieClip = loadImage("image/path.jpg");
// Do stuff to proxy.
}
}
}
And your function + listener would look something like this...
var proxies:Object = {};
function loadImage(path:String):MovieClip {
// load Image
var proxy:MovieClip = new MovieClip();
proxies.path = proxy;
// Load Image
}
function imageLoaded(e:Event):void {
// Once loaded, use the filename as the proxy object's key to find the MovieClip to attach the image.
proxies[e.data.loaderInfo.filename].addChild(e.data);
}
This is just off the top of my head, so you'll need to find the actual variable names, but I hope that makes sense.
I am not really sure if I understood your problem but it seems to me that you simply add the according listener in your inner loop.
//take care this is pseudocode
var parent = ... // some stage object
for (var w:int=0; w < size1; w++ ) {
for (var j:int=0; j < size2; j++ ) {
if(some_condition){
request = new URLRequest(getNextImagePath();
urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, onComplete);
urlLoader.load(request);
}
}
}
function onComplete(event:Event) {
parent.addChild(createImageFromData(this.data));
}
I solved the problem using an third party library that pretty munch handles this problem.
https://github.com/arthur-debert/BulkLoader

Actionscript 3: Monitoring the activity level for multiple Microphones doesn't seem to work

For a project I want to show all available webcams and microphones, so that the user can easily select whichever webcam/microphone combination they prefer. I run into an issue with the microphones listing though.
Each microphone is listed with an activity animation and it's name. I am able to list all Microphones just fine (using the Microphone.names Array), but it seems like I can only get the activity viewer to work for one microphone. The other microphones show up with '-1' activity, which (as far as I know) is Flex for 'present, but not in use'. When unplugging the microphone that does show activity, the next one (in my case, the mic-in line on my motherboard) shows up with '0' activity (it's not connected, so that makes sense).
During my testing I have a total of 3 microphones available, the not-connected onboard mic-in port, and two connected microphones.
For testing purposes I use a timer that traces the current microphone activity each 100ms and the graph is also shown.
It does not seem to matter what default microphone I set via flash' settings panel.
The code
I've only attached the revelant code snippets below to make it easier for you to read through them. Please let me know if you prefer the entire code.
Main application.mxml
Note: cont is a VBox. i is defined before this code snippet.
var mics:Array = Microphone.names;
for(i=0; i < mics.length; i++){
var mic:settingsMicEntry = new assets.settingsMicEntry;
mic.d = {name: mics[i], index: i};
cont.addChild(mic);
}
assets/settingsMicEntry.mxml
timer is defined before this code snippet. the SoundTransform is added to silence local microphone playback. Excluding this code does not solve the problem, sadly (I've tried). display is an MXML Canvas object.
mic = Microphone.getMicrophone(d.index);
if(mic){
// Temporary: The Microphones' visualizer
var bar:Box = new Box();
bar.y = 50;
bar.height = 0;
bar.width = 66;
bar.setStyle("backgroundColor", 0x003300);
display.addChild(bar);
var tf:SoundTransform = new SoundTransform(0);
mic.setLoopBack(true);
mic.soundTransform = tf;
timer = new Timer(100);
timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void{
var h:int = Math.floor((display.height/100)*mic.activityLevel);
bar.height = (h>-1) ? h : 0;
bar.y = (h>-1) ? display.height-h : display.height;
trace('TIMER: '+h+' from '+d.name);
});
timer.start();
}
I'm pulling my hear out here, so any help is much appreciated!
Thanks,
-Dave
Ps.: Pardon the messiness of the code!
You can set up a mock NetStream connection using the OSMF library.
You'll need to import the classes from the NetMocker project (under libs/adobe - org.osmf.netmocker) and the classes NetConnectionCodes and NetStreamCodes (under framework/OSMF - org.osmf.net).
Check out that you need to create one NetStream for each microphone