package com.dappervision.wearscript.managers; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.util.Base64; import com.dappervision.picarus.IPicarusService; import com.dappervision.wearscript.BackgroundService; import com.dappervision.wearscript.Log; import com.dappervision.wearscript.Utils; import com.dappervision.wearscript.events.CameraEvents; import com.dappervision.wearscript.events.PicarusBenchmarkEvent; import com.dappervision.wearscript.events.PicarusEvent; import com.dappervision.wearscript.events.PicarusModelCreateEvent; import com.dappervision.wearscript.events.PicarusModelProcessEvent; import com.dappervision.wearscript.events.PicarusModelProcessStreamEvent; import com.dappervision.wearscript.events.PicarusModelProcessWarpEvent; import com.dappervision.wearscript.events.PicarusRegistrationSampleEvent; import com.dappervision.wearscript.events.WarpHEvent; import org.msgpack.MessagePack; import org.msgpack.type.ArrayValue; import org.msgpack.type.Value; import org.msgpack.type.ValueFactory; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; public class PicarusManager extends Manager { public static final String TAG = "PicarusManager"; public static String MODEL_STREAM = "MODELSTREAM:"; public static String MODEL_WARP = "MODELWARP:"; private byte[] arModel; private byte[] registrationMatchModel; private byte[] registrationPointModel; private long registrationMatchModelCached, registrationPointModelCached, arModelCached; private ServiceConnection picarusConnection; private IBinder picarusService; private TreeMap<Integer, Long> modelCache; private TreeSet<Integer> modelStream; private TreeSet<Integer> modelWarp; private byte[] pointSample; public PicarusManager(BackgroundService service) { super(service); // TODO(brandyn): Verify that models are thread safe, if not then synchronize on the modelPointer // TODO(brandyn): Free all models in the cache on reset() registrationMatchModelCached = registrationMatchModelCached = 0; String model = "kYKia3eDrXBhdHRlcm5fc2NhbGXLP/AAAAAAAACmdGhyZXNoFKdvY3RhdmVzAqRuYW1lu3BpY2FydXMuQlJJU0tJbWFnZUZlYXR1cmUyZA=="; registrationPointModel = Base64.decode(model.getBytes(), Base64.NO_WRAP); model = "kYKia3eDqG1heF9kaXN0eKttaW5faW5saWVycwqtcmVwcm9qX3RocmVzaMtAFAAAAAAAAKRuYW1l2gAkcGljYXJ1cy5JbWFnZUhvbW9ncmFwaHlSYW5zYWNIYW1taW5n"; registrationMatchModel = Base64.decode(model.getBytes(), Base64.NO_WRAP); model = "kYKia3eApG5hbWW4cGljYXJ1cy5BUk1hcmtlckRldGVjdG9y"; arModel = Base64.decode(model.getBytes(), Base64.NO_WRAP); // Bind Service picarusConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { Log.i(TAG, "Service Connected"); picarusService = service; } public void onServiceDisconnected(ComponentName className) { Log.i(TAG, "Service Disconnected"); } }; Log.i(TAG, "Calling bindService"); service.bindService(new Intent("com.dappervision.picarus.PicarusService"), picarusConnection, Context.BIND_AUTO_CREATE); reset(); } @Override public void shutdown() { if (picarusConnection != null) { service.unbindService(picarusConnection); picarusConnection = null; } super.shutdown(); } @Override public void reset() { super.reset(); if (modelCache != null && !modelCache.isEmpty()) { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); for (Integer id : modelCache.keySet()) { try { picarus.deleteModel(id); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); } } } modelCache = new TreeMap<Integer, Long>(); modelStream = new TreeSet<Integer>(); modelWarp = new TreeSet<Integer>(); } public void makeCachedModels() { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); if (registrationPointModelCached != 0 && registrationMatchModelCached != 0 && arModelCached != 0) return; try { registrationPointModelCached = picarus.createModel(registrationPointModel); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); return; } try { registrationMatchModelCached = picarus.createModel(registrationMatchModel); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); return; } try { arModelCached = picarus.createModel(arModel); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); return; } } public void onEventBackgroundThread(PicarusBenchmarkEvent e) { File dir = new File(Utils.dataPath() + "/samples/"); IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); long model = 0; try { model = picarus.createModel(registrationPointModel); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); return; } for (File f : dir.listFiles()) { Log.d(TAG, "Benchmark Dir: " + f.getName()); File[] fns = f.listFiles(); Arrays.sort(fns); for (File f2 : fns) { Log.d(TAG, "Bench: Pre File: " + f2.getName()); byte data[] = Utils.LoadFile(f2); Log.d(TAG, "Bench: File: " + f2.getName()); try { byte imagePoints[] = picarus.processBinary(model, data); Log.d(TAG, "Bench: Points: " + imagePoints.length); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); } } } } public void onEventBackgroundThread(PicarusModelCreateEvent e) { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); try { Long modelPointer = picarus.createModel(e.getModel()); synchronized (this) { modelCache.put(e.getId(), modelPointer); } makeCallDirect(e.getCallback(), ""); } catch (RemoteException e1) { Log.e(TAG, "Execution error"); } } public void onEventBackgroundThread(PicarusModelProcessEvent e) { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); Long modelPointer = modelCache.get(e.getId()); if (modelPointer == null) return; try { byte[] output = picarus.processBinary(modelPointer, e.getInput()); makeCallDirect(e.getCallback(), "'" + Base64.encodeToString(output, Base64.NO_WRAP) + "'"); } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } } public void onEventBackgroundThread(PicarusModelProcessStreamEvent e) { synchronized (this) { modelStream.add(e.getId()); } } public void onEventBackgroundThread(PicarusModelProcessWarpEvent e) { synchronized (this) { modelWarp.add(e.getId()); } } public void onEventBackgroundThread(PicarusEvent e) { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); try { makeCall(e.getCallback(), "'" + Base64.encodeToString(picarus.processBinaryOld(e.getModel(), e.getInput()), Base64.NO_WRAP) + "'"); } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } Log.d(TAG, "Called"); unregisterCallback(e.getCallback()); } public void onEventBackgroundThread(PicarusRegistrationSampleEvent e) { // TODO(brandyn): Look into whether this should be async synchronized (this) { IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); makeCachedModels(); Log.d(TAG, "Trying to call"); byte [] input = e.getJPEG(); try { pointSample = picarus.processBinary(registrationPointModelCached, input); } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } TreeSet<Integer> modelWarpCopy; synchronized (this) { modelWarpCopy = new TreeSet<Integer>(modelWarp); } for (Integer id : modelWarpCopy) { try { Long modelPointer = modelCache.get(id); byte [] output = picarus.processBinary(modelPointer, input); Log.d(TAG, "Picarus calling warp model"); makeCall(MODEL_WARP + id, "'" + Base64.encodeToString(output, Base64.NO_WRAP) + "'"); } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } } } } public byte[] msgpackPoints(byte[] points0, byte[] points1) { List<Value> data = new ArrayList<Value>(); MessagePack msgpack = new MessagePack(); data.add(ValueFactory.createRawValue(points0)); data.add(ValueFactory.createRawValue(points1)); try { return msgpack.write(data); } catch (IOException e) { // TODO(brandyn): Handle } return null; } public double[] msgpackParseH(byte[] match) { double [] h = new double[9]; MessagePack msgpack = new MessagePack(); ArrayValue hArray = null; try { hArray = msgpack.read(match).asArrayValue().get(0).asArrayValue(); } catch (IOException e) { Log.e(TAG, "Couldn't parse H"); return null; } for (int i = 0; i < 9; i++) { h[i] = hArray.get(i).asFloatValue().getDouble(); Log.d(TAG, String.format("H[%d]: %f", i, h[i])); } return h; } public void processFrame(CameraEvents.Frame frameEvent) { synchronized (this) { if (modelStream.isEmpty() && pointSample == null) return; } // TODO(brandyn): Benchmark this vs jpeg byte[] frameJPEG = frameEvent.getCameraFrame().getJPEG(); if (frameJPEG == null) { Log.w(TAG, "Picarus stream unable to get frameJPEG"); return; } Log.d(TAG, "frameJPEG Length: " + frameJPEG.length); IPicarusService picarus = IPicarusService.Stub.asInterface(picarusService); Log.d(TAG, "CamPath: Pre Picarus"); TreeSet<Integer> modelStreamCopy; synchronized (this) { modelStreamCopy = new TreeSet<Integer>(modelStream); } for (Integer id : modelStreamCopy) { try { Log.w(TAG, "Picarus stream model:" + id); Long modelPointer = modelCache.get(id); if (modelPointer == null) { Log.w(TAG, "Picarus stream model doesn't exist in cache"); continue; } byte [] output = picarus.processBinary(modelPointer, frameJPEG); if (output == null || output.length == 0) { Log.w(TAG, "Picarus stream model returned null"); continue; } Log.w(TAG, "Model Output Size: " + output.length); makeCall(MODEL_STREAM + id, "'" + Base64.encodeToString(output, Base64.NO_WRAP) + "'"); } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } } if (pointSample != null) { byte imagePoints[]; makeCachedModels(); try { Log.d(TAG, "CamPath: Picarus points"); imagePoints = picarus.processBinary(registrationPointModelCached, frameJPEG); Log.d(TAG, "CamPath: Picarus match"); byte match[] = picarus.processBinary(registrationMatchModelCached, msgpackPoints(pointSample, imagePoints)); if (match != null) { Log.d(TAG, "CamPath: Match: " + match.length); Utils.eventBusPost(new WarpHEvent(msgpackParseH(match))); } } catch (RemoteException exeption) { Log.w(TAG, "PicarusService closed"); } } Log.d(TAG, "CamPath: Post Picarus"); } }