Unity Coroutine Freeze on iOS/Android - android

i've been trying to make an app for mobile (both iOS and Android) and what this app does is quite simple:
Download a txt file from webserver
"Run" txt, the txt file has a command like "display" or "play" with an URL to resource (jpg or mp4)
Download or stream the resource to a texture in the scene (done)
Using GoogleVR (LatestVersion) to shot the whole thing
Now the problem is that as i start the coroutine to download stuff the game freezes on mobile but it doesn't freeze while in Editor.
Here's the code:
IEnumerator retrieveCommand(){
print ("Retrieving command...");
WWW rx = new WWW (host + "command.txt"); // host is the URL of server
yield return rx; // wait for end WWW
if (!string.IsNullOrEmpty (rx.error)) { // if there's an error i stop execution of coroutine
print (rx.error);
mex.text = rx.error;
yield break;
}
print ("Command: " + rx.text);
if (lastCommand != rx.text.Trim ()) { // if last command retrieved is NOT the same as the current
lastCommand = rx.text.Trim ();
command = rx.text.Trim ();
string[] argv = command.Split ('|'); // command is in form of <cmd>|parameter
mexdisplay = argv [0]; // argv[0] contains command, argv[1] contains the paramter
switch (argv [0]) { // what's the command?
case "PLAY":
video.GetComponent<MediaPlayerCtrl> ().Play ();
break;
case "STOP":
video.GetComponent<MediaPlayerCtrl> ().Stop ();
break;
case "PAUSE":
video.GetComponent<MediaPlayerCtrl> ().Pause ();
break;
case "GRAB": // set video resource
try {
video.GetComponent<MediaPlayerCtrl> ().m_strFileName = host + argv [1];
} catch (Exception e) {
print ("Exception: " + e);
}
break;
case "DISPLAY": // downloads and shows picture
print ("Display: " + host + argv [1]);
rx = new WWW (host + argv [1]);
yield return rx;
if (!string.IsNullOrEmpty (rx.error)) {
print (rx.error);
mex.text = rx.error;
yield break;
}
video.GetComponent<Renderer> ().material.mainTexture = rx.texture;
break;
}
}
asdf = true;
}
The coroutine is called every 10s by Update:
void Update(){
if(asdf){ // bool, if false -> running coroutine, if true -> not running->count 10 seconds
curr += Time.deltaTime;
if (curr >= time) { // time=10f, if counted to 10s start coroutine and reset timer
asdf = false;
curr = 0;
StartCoroutine (retrieveCommand ());
}
}
}
edit:
So it turns out it's like the camera stops rendering... any help? i'm using the GoogleVR camera prefabs...

Related

How to proper send messages via bluetooth from Android to Arduino continuously

I have a goal to control some arduino device via BT with help of my android phone.
When I touch a screen and move my finger around, android app generate some data, depending on my finger position, forming a string message, and then trying to send it over BT.
The problem is, when the app attempts to send many many iterations of this command.
For example, the command is: String command = "[code]command(data)/";
When I just tap a time on a screen, the app write the command once and send it over BT, and it looks good on the other side (arduino).
But when I hold and move the finger, app trying to rewrite the command every "frame", and also trying to send this command every "frame" (I mean, every moment, many many times). And then I see something like: "[code]co[cod[co[c[mma(da]coode[c[co".
The feeling is... it gets one characters array and mixed it with another, when sending... or begin sending another message before stops sending previous.
Here is the code that gets some values on touch event:
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initPosX = x;
break;
case MotionEvent.ACTION_MOVE:
// some code that make counts and convert values...
// prepare string as a command.
String command = "[code]command(" + value + ")/";
Log.d("command", command);
// send data via BT
sendData(command);
break;
case MotionEvent.ACTION_UP:
//code
break;
default:
break;
}
Also I have BT settings up code, it all works good.
And this is the main part. Code that sending the string:
protected void sendData(String message) {
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
//some exception code
}
}
outStream = btSocket.getOutputStream();
So... I really don't know why this happens. I wasted entire day trying to search something about.
Will be very appreciated if someone can give me a glue, where to dig next.
Thanks.
UPDATE:
Arduino side code:
if (Serial.available() > 0) {
char c = Serial.read(); // read char from BT
serialMessage.concat(c); // add this char to string.
delay(5);
if (c == '/') {
lcd.setCursor(0,0);
lcd.print(serialMessage); // print message on a display.
command = serialMessage;
serialMessage = "";
}
}
else {
if (serialMessage != "") {
lcd.setCursor(0,0);
lcd.print(serialMessage); // print message on a display.
serialMessage = "";
}
//command = serialMessage;
}
UPDATE 2:
This is a real Serial input, when I tap once
[code]command(0.0)/
and when I move finger left and right
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.23)/
[code]cm()dm()[c]a.[em1[(/
em1[em1[]a.cca.[e)[dm(/
dm(/
em1[em1[co0ood)dmd4ood8oon2ccn0cca0/
ccn.[]a-)dm(6oon.[]a1[]od0o0[c]a1[]a1[em-/
em-)dm()dm(0odcn.cca0a.[]a.[em0/
em0)dm()dm()dm(/
em1/
em1[]a1[]a.ccn0oon7ccn4c]a.ccn.[em-)dm()oodod0ccn.ccn.[]m-/
d0ooood0ccn.ccn.[]a1[]a-/
em-/
em(5ood7c]a0/
em-)ood0[em0)dm()dm(3od)dm(/
dm(/
em1[em1[]a.c]a)dodm()ood2ccn./
ed9[]a1[]a-/
em-/
em()dm()dmd0od0ooood0oon.codecn1[]a0/
[dm(5ccn.cd0ccn1ccn.[]d4ooood7ocn3
UPDATE 3:
Taps without delay:
[
code]c
ommand(0.0)/
[code]command(0.0)/
[
code]c
ommand(0.0)/
[code]command(0.0)/
[
code]c
ommand(0.0)/
[code]command(0.0)/
UPDATE 4:
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.0)/
[code]command(0.01)/
[code]command(0.07)/
[code]command(0.15)/
[code]command(0.23)/
[code]command(0.29)/
[code]command(0.33)/
[code]command(0.37)/
[code]command(0.41)/
[co(0.44)/
[code]commandmmand(0.51)/
[code]code]command(0.6)/
[cod0.63)/
[cod0.65)/
[code]command(0.66)67)/
[code]command(0.68)/
2)/
Yes. It was overflowed serial.
I solve this issue in two steps.
First, I decrease delay for char reading on the arduino side from 5 to 1.
Second, I send a message/command only 10 times per second.
There is a code that makes this:
public void send(String string) {
if ((System.currentTimeMillis() - lastTimeSend) > 100) {
byte[] bytes = string.getBytes();
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
lastTimeSend = System.currentTimeMillis();
}
}

Digital persona SDK - native problems

I am using in my app Digital Persona SDK for fingerprint identification.
When i use the identify function on less then 250 fmds it works fine.
Engine.Candidate candidates[] = m_engine.Identify(searchedFmd, 0, fmdArray, DEFAULT_THRESHOLD, 1); //fmdArray < 250
But with fmdArray > 250 it gives me a native runtime error:
A/art: art/runtime/indirect_reference_table.cc:132] JNI ERROR (app bug): local reference table overflow (max=512)
Now i runned this app on couple of android devices and came to conclusion that my app crushes with fmdArray > 250 when its running on android 7. But android 8 works fine. In 8 i can preform a check on even 4000 fmds and it works fine.
But i need to run this code in a specific device, that running android 7.
I tried to run it in couple of threads of 250 fmds only. But after single run there is another problem with the SDK. On the second run it doesnt works.
This is what i do:
First i get a fingerprint capture that i want to identify:
Reader.CaptureResult capture = m_reader.Capture(fidFormat, UrUSDK.DefaultImageProcessing, m_DPI, timeout);
// In second run, code after this line is not executed.
// My guees its not coming back from native. No exeptions. No errors.
...
Fmd scannedFmd = m_engine.CreateFmd(capture.image, fmdFormat);
...
int index = identifyFinger(fmds, scannedFmd);
...
private int identifyFinger(List<Fmd> fmdSearchArray, Fmd scannedFmd) {
List<List<Fmd>> lists = splitToChunks(fmdSearchArray);
AtomicInteger index = new AtomicInteger(-1);
List<Callable<Void>> threads = new ArrayList<>(lists.size());
AtomicInteger iteratorIndex = new AtomicInteger(0);
for (int i = 0; i < lists.size(); i++) {
int currentChunk = i;
Callable<Void> thread = () -> {
System.out.println(Thread.currentThread().getName() + " with chunk: " + iteratorIndex.getAndIncrement());
Fmd[] fmds = lists.get(currentChunk).toArray(new Fmd[IDENTIFY_BOUNDARY]);
try {
Engine.Candidate[] candidates = m_engine.Identify(scannedFmd, 0, fmds, threshold, 1);
if (candidates.length > 0) {
index.set(candidates[0].fmd_index + (currentChunk * IDENTIFY_BOUNDARY));
}
} catch (UareUException e) {
}
System.out.println(Thread.currentThread().getName() + " with chunk: " + currentChunk + " finished!");
return null;
};
threads.add(thread);
}
try {
List<Future<Void>> futures = executorService.invokeAll(threads);
System.out.println("All threads finished: " + index.get());
return index.get();
} catch (InterruptedException e) {
e.printStackTrace();
return -1;
}
}
...
private List<List<Fmd>> splitToChunks(List<Fmd> fmdSearchArray) {
int size = fmdSearchArray.size();
List<List<Fmd>> lists;
if (size > IDENTIFY_BOUNDARY) {
int chunks = size / IDENTIFY_BOUNDARY;
if (size % IDENTIFY_BOUNDARY > 0) {
chunks++;
}
lists = new ArrayList<>(chunks);
for (int i = 0; i < chunks; i++) {
if (i + 1 == chunks) {
lists.add(new ArrayList<>(fmdSearchArray.subList(i * IDENTIFY_BOUNDARY, size)));
break;
}
lists.add(new ArrayList<>(fmdSearchArray.subList(i * IDENTIFY_BOUNDARY, (i + 1) * IDENTIFY_BOUNDARY)));
}
} else {
lists = new ArrayList<>(1);
lists.add(fmdSearchArray);
}
return lists;
}
The problem with this code is that it runs once. But at another try it doesnt come back from the native code of Caprture call.
So my question is:
How i can overcome this and make it work from my java code?
Or at least what is the direction of the solution?
The root cause is that this Identify function holds on to at least two references per returned Candidate after pushing it to the result array. It should instead release the references after pushing, so its use of the (limited) local reference table remain constant. You should file a bug about that.
The simplest workaround for now is to cut your fmdArray into 250-sized chunks and call Identify for each chunk.

Output file using FFmpeg in Xamarin Android

I'm building an android app using Xamarin. The requirement of the app is to capture video from the camera and encode the video to send it across to a server.
Initially, I was using an encoder library on the server-side to encode recorded video but it was proving to be extremely unreliable and inefficient especially for large-sized video files. I have posted my issues on another thread here
I then decided to encode the video on the client-side and then send it to the server. I've found encoding to be a bit complicated and there isn't much information available on how this can be done. So, I searched for the only way I knew how to encode a video that is by using FFmpeg codec. I've found some solutions. There's a project on GitHub that demonstrates how FFmpeg is used inside a Xamarin android project. However, running the solution doesn't give any output. The project has a binary FFmpeg file which is installed to the phone directory using the code below:
_ffmpegBin = InstallBinary(XamarinAndroidFFmpeg.Resource.Raw.ffmpeg, "ffmpeg", false);
Below is the example code for encoding video into a different set of outputs:
_workingDirectory = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var sourceMp4 = "cat1.mp4";
var destinationPathAndFilename = System.IO.Path.Combine (_workingDirectory, "cat1_out.mp4");
var destinationPathAndFilename2 = System.IO.Path.Combine (_workingDirectory, "cat1_out2.mp4");
var destinationPathAndFilename4 = System.IO.Path.Combine (_workingDirectory, "cat1_out4.wav");
if (File.Exists (destinationPathAndFilename))
File.Delete (destinationPathAndFilename);
CreateSampleFile(Resource.Raw.cat1, _workingDirectory, sourceMp4);
var ffmpeg = new FFMpeg (this, _workingDirectory);
var sourceClip = new Clip (System.IO.Path.Combine(_workingDirectory, sourceMp4));
var result = ffmpeg.GetInfo (sourceClip);
var br = System.Environment.NewLine;
// There are callbacks based on Standard Output and Standard Error when ffmpeg binary is running as a process:
var onComplete = new MyCommand ((_) => {
RunOnUiThread(() =>_logView.Append("DONE!" + br + br));
});
var onMessage = new MyCommand ((message) => {
RunOnUiThread(() =>_logView.Append(message + br + br));
});
var callbacks = new FFMpegCallbacks (onComplete, onMessage);
// 1. The idea of this first test is to show that video editing is possible via FFmpeg:
// It results in a 150x150 movie that eventually zooms on a cat ear. This is desaturated, and there's a fade-in.
var filters = new List<VideoFilter> ();
filters.Add (new FadeVideoFilter ("in", 0, 100));
filters.Add(new CropVideoFilter("150","150","0","0"));
filters.Add(new ColorVideoFilter(1.0m, 1.0m, 0.0m, 0.5m, 1.0m, 1.0m, 1.0m, 1.0m));
var outputClip = new Clip (destinationPathAndFilename) { videoFilter = VideoFilter.Build (filters) };
outputClip.H264_CRF = "18"; // It's the quality coefficient for H264 - Default is 28. I think 18 is pretty good.
ffmpeg.ProcessVideo(sourceClip, outputClip, true, new FFMpegCallbacks(onComplete, onMessage));
//2. This is a similar version in command line only:
string[] cmds = new string[] {
"-y",
"-i",
sourceClip.path,
"-strict",
"-2",
"-vf",
"mp=eq2=1:1.68:0.3:1.25:1:0.96:1",
destinationPathAndFilename2,
"-acodec",
"copy",
};
ffmpeg.Execute (cmds, callbacks);
// 3. This lists codecs:
string[] cmds3 = new string[] {
"-codecs",
};
ffmpeg.Execute (cmds, callbacks);
// 4. This convers to WAV
// Note that the cat movie just has some silent house noise.
ffmpeg.ConvertToWaveAudio(sourceClip, destinationPathAndFilename4, 44100, 2, callbacks, true);
I have tried different commands but no output file is generated. I have tried to use another project found here but this one has the same issue. I don't get any errors but no output file is generated. I'm really hoping someone can help me find a way I can manage to use FFmpeg in my project or some way to compress video to transport it to the server.
I will really appreciate if someone can point me in the right direction.
Just figure how to get the output by adding the permission in AndroidManifest file.
android.permission.WRITE_EXTERNAL_STORAG
Please read the update on the repository, it says that there is a second package, Xamarin.Android.MP4Transcoder for Android 6.0 onwards.
Install NuGet https://www.nuget.org/packages/Xamarin.Android.MP4Transcoder/
await Xamarin.MP4Transcoder.Transcoder
.For720pFormat()
.ConvertAsync(inputFile, ouputFile, f => {
onProgress?.Invoke((int)(f * (double)100), 100);
});
return ouputFile;
For Previous Android versions
Soruce Code https://github.com/neurospeech/xamarin-android-ffmpeg
Install-Package Xamarin.Android.FFmpeg
Use this as template, this lets you log output as well as calculates progress.
You can take a look at source, this one downloads ffmpeg and verifies sha1 hash on first use.
public class VideoConverter
{
public VideoConverter()
{
}
public File ConvertFile(Context contex,
File inputFile,
Action<string> logger = null,
Action<int,int> onProgress = null)
{
File ouputFile = new File(inputFile.CanonicalPath + ".mpg");
ouputFile.DeleteOnExit();
List<string> cmd = new List<string>();
cmd.Add("-y");
cmd.Add("-i");
cmd.Add(inputFile.CanonicalPath);
MediaMetadataRetriever m = new MediaMetadataRetriever();
m.SetDataSource(inputFile.CanonicalPath);
string rotate = m.ExtractMetadata(Android.Media.MetadataKey.VideoRotation);
int r = 0;
if (!string.IsNullOrWhiteSpace(rotate)) {
r = int.Parse(rotate);
}
cmd.Add("-b:v");
cmd.Add("1M");
cmd.Add("-b:a");
cmd.Add("128k");
switch (r)
{
case 270:
cmd.Add("-vf scale=-1:480,transpose=cclock");
break;
case 180:
cmd.Add("-vf scale=-1:480,transpose=cclock,transpose=cclock");
break;
case 90:
cmd.Add("-vf scale=480:-1,transpose=clock");
break;
case 0:
cmd.Add("-vf scale=-1:480");
break;
default:
break;
}
cmd.Add("-f");
cmd.Add("mpeg");
cmd.Add(ouputFile.CanonicalPath);
string cmdParams = string.Join(" ", cmd);
int total = 0;
int current = 0;
await FFMpeg.Xamarin.FFMpegLibrary.Run(
context,
cmdParams
, (s) => {
logger?.Invoke(s);
int n = Extract(s, "Duration:", ",");
if (n != -1) {
total = n;
}
n = Extract(s, "time=", " bitrate=");
if (n != -1) {
current = n;
onProgress?.Invoke(current, total);
}
});
return ouputFile;
}
int Extract(String text, String start, String end)
{
int i = text.IndexOf(start);
if (i != -1)
{
text = text.Substring(i + start.Length);
i = text.IndexOf(end);
if (i != -1)
{
text = text.Substring(0, i);
return parseTime(text);
}
}
return -1;
}
public static int parseTime(String time)
{
time = time.Trim();
String[] tokens = time.Split(':');
int hours = int.Parse(tokens[0]);
int minutes = int.Parse(tokens[1]);
float seconds = float.Parse(tokens[2]);
int s = (int)seconds * 100;
return hours * 360000 + minutes * 60100 + s;
}
}

How to access texture/models from cloud/WEB at run time in android app using Unity 3D?

I have been trying to download and load the texture or other models from a WEB at run time by using WWW class.
The app works well on Unity Editor but when I deploy it on android device it doesn't load/download the texture.
Please somebody guide me.
I have used the following code in script.
void Start()
{
StartCoroutine(loadMovie());
}
IEnumerator loadTexture()
{
WWW www = new WWW("http://images.earthcam.com/ec_metros/ourcams/fridays.jpg");
yield return www;
// Debug.Log(www.movie.duration + " <--- wwww");
if (www.error != null)
{
Debug.Log("Error: Can't load texture! - " + www.error);
yield break;
}
else
{
Texture2D texture = www.texture as Texture2D;
Debug.Log("Texture loaded");
Debug.Log(www.texture);
gameObject.GetComponent<Renderer>().material.mainTexture = texture;
}
}
First of all, remove Debug.Log(www.texture); from the code, then re-try your code.
You have IEnumerator loadTexture() but you are calling StartCoroutine(loadMovie()); . This means that you are likely calling another function or maybe that's a type in your question.
void Start()
{
StartCoroutine(loadTexture());
}
IEnumerator loadTexture()
{
WWW www = new WWW("http://images.earthcam.com/ec_metros/ourcams/fridays.jpg");
//Wait for download to finish
while(!www.isDone){
Debug.Log("Progress: "+www.progress);
yield return null;
}
if ((www==null) || (www.error != null))
{
Debug.Log("Error: Can't load texture! - " + www.error);
yield break;
}
gameObject.GetComponent<Renderer>().material.mainTexture = www.texture;
}
Not compiled but should work.
EDIT:
From the file you sent, change the Minimum API Level to 4.1.

Dowloading images random error

I have the following piece of code:
function download_img(imgToDownload, imgToRemove){
var url = remote_url+imgToDownload; // image url
root_path = get_root_path();
var flag = "working";
var flag_delete = false;
var imageToDownloadPath = root_path + "/" + imgToDownload; // full file path
var imageToRemovePath = root_path + "/" + imgToRemove; // full file path
try{
var fileTransfer = new FileTransfer();
fileTransfer.download(url, imageToDownloadPath,
function () {
if(imgToRemove != "" && imgToRemove != null){
var entry = new FileEntry("foo", imageToRemovePath);
entry.remove(function (){alert("fine");flag_delete = true;}, function (){alert("marron");flag_delete = true;});
}
else{
flag_delete = true;
}
flag = "done";
},
function (error) {
flag = "done";
flag_delete = true;
}
);
}catch(error){
alert("Error capturado: "+error.message);
}
while(flag=="working" && !flag_delete){
try{
setTimeout(
function() {
/* Código */
},
300
);
}
catch(error){
alert("Error en el bucle: " + error.message);
}
}
}
I have had problems downloading the files which apparently seemed to be a sync conflict, I mean, looks like something was avorting the execution before the file/s was/were downloaded.
I have used two flags to make sure not to continue until files are downloaded (and old ones deleted if necessary). The idea is to change flag's values when the action is completed and keep the code waiting in a loop.
The results this code is giving is as follows:
It never seems to enter the success fileTransfer.download sucess method (I used an alert which never triggered) even though the first file downloads properly.
The flags are never changed so the code stays stuck in the loop, and it does not continue downloading other files.
I think it might be a very basic jQuery behaviour but I am just starting with this technologies and I am a little lost. If anyone could give me a clue on that I would really appreciate it.
Thanks!!

Categories

Resources