First benchmark working with capability-based RMI; adjustments in callbacks, etc.
[iot2.git] / benchmarks / drivers / AmcrestCamera / AmcrestCamera.java
1 package iotcode.AmcrestCamera;
2
3 // IoT Packages
4 import iotcode.annotation.*;
5 import iotcode.interfaces.*;
6 import iotruntime.IoTHTTP;
7 import iotruntime.slave.IoTSet;
8 import iotruntime.slave.IoTDeviceAddress;
9
10 // Standard Java Packages
11 import java.io.IOException;
12 import java.io.DataInputStream;
13 import java.io.InputStream;
14 import java.io.BufferedInputStream;
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.awt.image.BufferedImage;
20 import java.awt.image.ColorModel;
21 import java.awt.image.WritableRaster;
22 import java.awt.image.BufferedImage;
23 import javax.imageio.ImageIO;
24 import java.util.Base64;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.ArrayList;
29 import java.util.concurrent.locks.Lock;
30 import java.util.concurrent.locks.ReadWriteLock;
31 import java.util.concurrent.locks.ReentrantReadWriteLock;
32 import java.util.concurrent.atomic.AtomicBoolean;
33 import java.util.Iterator;
34 import javax.imageio.ImageIO;
35 import java.util.concurrent.CopyOnWriteArrayList;
36 import java.util.concurrent.Semaphore;
37
38 // RMI Packages
39 import java.rmi.Remote;
40 import java.rmi.RemoteException;
41
42 // Checker annotations
43 //import iotchecker.qual.*;
44
45 public class AmcrestCamera implements Camera {
46
47         /*******************************************************************************************************************************************
48         **
49         **  Variables
50         **
51         *******************************************************************************************************************************************/
52         private String credentialUsername = "";
53         private String credentialPassword = "";
54         private DataInputStream dataInStream = null;
55         private boolean isStreamConnected = false;
56         private byte[] latestImage = null;
57         private ReadWriteLock imageReadWriteLock = new ReentrantReadWriteLock();
58         private Lock imageReadLock = imageReadWriteLock.readLock();
59         private Lock imageWriteLock = imageReadWriteLock.writeLock();
60         private AtomicBoolean newFrameAvailable = new AtomicBoolean(false);
61         private ReadWriteLock timestampReadWriteLock = new ReentrantReadWriteLock();
62         private Lock timestampReadLock = timestampReadWriteLock.readLock();
63         private Lock timestampWriteLock = timestampReadWriteLock.writeLock();
64         private Date latestImageTimestamp = null;
65         private List <CameraSmartCallback> callbackList =
66             new CopyOnWriteArrayList <CameraSmartCallback> ();
67         private AtomicBoolean doEnd = new AtomicBoolean(false);
68         private IoTDeviceAddress deviceAddress = null;
69         private AtomicBoolean didInit = new AtomicBoolean();
70         private AtomicBoolean didStart = new AtomicBoolean();
71         static Semaphore settingsSettings = new Semaphore(1);
72
73         /*******************************************************************************************************************************************
74         **
75         **  Threads
76         **
77         *******************************************************************************************************************************************/
78         private Thread callbackThread = null;
79         private Thread workerThread = null;
80
81
82         /*******************************************************************************************************************************************
83         **
84         **  IoT Sets and Relations
85         **
86         *******************************************************************************************************************************************/
87
88         // IoTSet of Device Addresses.
89         // Will be filled with only 1 address.
90         @config private IoTSet<IoTDeviceAddress> cam_addresses;
91
92
93         public AmcrestCamera(String _credentialUsername, String _credentialPassword) throws RemoteException {
94                 credentialUsername = _credentialUsername;
95                 credentialPassword = _credentialPassword;
96         }
97
98         /*******************************************************************************************************************************************
99         **
100         **  Camera Interface Methods
101         **
102         *******************************************************************************************************************************************/
103
104         public byte[] getLatestFrame() {
105
106                 byte[] newImage = null;
107
108                 imageReadLock.lock();
109                 try {
110                         if (latestImage != null) {
111                                 newImage = Arrays.copyOf(latestImage, latestImage.length);
112                         }
113                 } catch (Exception x) {
114                         x.printStackTrace();
115                 }
116                 imageReadLock.unlock();
117
118                 return newImage;
119         }
120
121         public long getTimestamp() {
122                 timestampReadLock.lock();
123                 Date ret = (Date)latestImageTimestamp.clone();
124                 timestampReadLock.unlock();
125                 long retLong = ret.getTime();
126                 return retLong;
127         }
128
129         public void registerCallback(CameraSmartCallback _callbackTo) {
130                 callbackList.add(_callbackTo);
131         }
132
133         public boolean setFPS(int _fps) {
134                 try {
135                         settingsSettings.acquire();
136
137                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig&Encode[0].MainFormat[0].Video.FPS=" + Integer.toString(_fps);
138
139                         try {
140
141                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
142                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
143                                 String httpAuthCredentials = "Basic " + credsBase64;
144
145                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
146                                 httpConnection.setURL(camUrlString);
147                                 httpConnection.openConnection();
148                                 httpConnection.setDoInput(true);
149                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
150                                 httpConnection.connect();
151
152                                 InputStream is = httpConnection.getInputStream();
153                                 BufferedInputStream bis = new BufferedInputStream(is);
154                                 DataInputStream din = new DataInputStream(bis);
155
156                                 // wait for a response
157                                 try {
158                                         Thread.sleep(1000);
159                                 } catch (InterruptedException ie) {
160                                 }
161
162                                 byte[] byteBuf = new byte[100];
163                                 try {
164                                         int r = din.read(byteBuf, 0, byteBuf.length);
165                                         String retString = new String(byteBuf);
166
167                                         if (!retString.substring(0, 2).equals("OK")) {
168                                                 httpConnection.disconnect();
169                                                 return false;
170                                         }
171
172                                 } catch (Exception e) {
173                                         httpConnection.disconnect();
174                                         return false;
175                                         // e.printStackTrace();
176                                 }
177
178                                 httpConnection.disconnect();
179                         } catch (IOException e) {
180                                 return false;
181                         } catch (Exception e) {
182                                 return false;
183                         }
184                 } catch (Exception e) {
185                         e.printStackTrace();
186                 }
187                 settingsSettings.release();
188
189                 return true;
190         }
191
192         public int getMaxFPS() {
193                 // Hard coded since this is hardware dependant
194                 return 30;
195         }
196
197         public int getMinFPS() {
198                 // Hard coded since this is hardware dependant
199                 return 5;
200         }
201
202         public List<Resolution> getSupportedResolutions() {
203
204                 // Hard coded since this is hardware dependant
205                 List<Resolution> ret = new ArrayList<Resolution>();
206                 ret.add(Resolution.RES_1080P);
207                 ret.add(Resolution.RES_720P);
208                 ret.add(Resolution.RES_VGA);
209                 return ret;
210         }
211
212         public boolean setResolution(Resolution _res) {
213
214                 try {
215                         settingsSettings.acquire();
216
217
218                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig";
219
220                         if (_res == Resolution.RES_1080P) {
221                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=1080&Encode[0].MainFormat[0].Video.Width=1920";
222
223                         } else if (_res == Resolution.RES_720P) {
224                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=720&Encode[0].MainFormat[0].Video.Width=1280";
225
226                         } else if (_res == Resolution.RES_VGA) {
227                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=480&Encode[0].MainFormat[0].Video.Width=640";
228                         }
229
230
231                         try {
232
233                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
234                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
235                                 String httpAuthCredentials = "Basic " + credsBase64;
236
237                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
238                                 httpConnection.setURL(camUrlString);
239                                 httpConnection.openConnection();
240                                 httpConnection.setDoInput(true);
241                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
242                                 httpConnection.connect();
243
244                                 InputStream is = httpConnection.getInputStream();
245                                 BufferedInputStream bis = new BufferedInputStream(is);
246                                 DataInputStream din = new DataInputStream(bis);
247
248                                 // wait for a response
249                                 try {
250                                         Thread.sleep(1000);
251                                 } catch (InterruptedException ie) {
252                                 }
253
254                                 byte[] byteBuf = new byte[100];
255                                 try {
256                                         int r = din.read(byteBuf, 0, byteBuf.length);
257                                         String retString = new String(byteBuf);
258
259                                         if (!retString.substring(0, 2).equals("OK")) {
260                                                 httpConnection.disconnect();
261                                                 return false;
262                                         }
263
264                                 } catch (Exception e) {
265                                         httpConnection.disconnect();
266                                         return false;
267                                         // e.printStackTrace();
268                                 }
269
270                                 httpConnection.disconnect();
271                         } catch (IOException e) {
272                                 return false;
273                         } catch (Exception e) {
274                                 return false;
275                         }
276                 } catch (Exception e) {
277                         e.printStackTrace();
278                 }
279
280                 settingsSettings.release();
281
282                 return true;
283         }
284
285         public void start() {
286
287                 if (didStart.compareAndSet(false, true) == false) {
288                         return; // already started
289                 }
290
291
292
293                 doEnd.set(false);
294
295                 if (!streamConnect()) {
296                         return;
297                 }
298
299                 callbackThread = new Thread(new Runnable() {
300                         public void run() {
301                                 doCallbacks();
302                         }
303                 });
304                 callbackThread.start();
305
306                 workerThread = new Thread(new Runnable() {
307                         public void run() {
308                                 doWork();
309                         }
310                 });
311                 workerThread.start();
312         }
313
314         public void stop() {
315                 if (didStart.compareAndSet(true, false) == false) {
316                         return; // already stopped
317                 }
318
319                 doEnd.set(true);
320
321                 try {
322                         callbackThread.join();
323                         workerThread.join();
324                 } catch (Exception e) {
325                         e.printStackTrace();
326                 }
327
328                 streamDisconnect();
329         }
330
331         public void init() {
332                 if (didInit.compareAndSet(false, true) == false) {
333                         return; // already init
334                 }
335
336                 // get the device address and save it for later use when creating HTTP connections
337                 Iterator itr = cam_addresses.iterator();
338                 deviceAddress = (IoTDeviceAddress)itr.next();
339
340                 System.out.println("Address: " + deviceAddress.getCompleteAddress());
341         }
342
343         /*******************************************************************************************************************************************
344         **
345         **  Helper Methods
346         **
347         *******************************************************************************************************************************************/
348         private byte[] readFromStream(int num) {
349                 byte[] byteBuf = new byte[num];
350                 try {
351                         dataInStream.readFully(byteBuf, 0, byteBuf.length);
352                 } catch (Exception e) {
353                         e.printStackTrace();
354                 }
355
356                 return byteBuf;
357         }
358
359         private void findBoundry() {
360                 String boundary = "**************";
361                 while (true) {
362                         byte b = readFromStream(1)[0];
363                         boundary = boundary.substring(1);
364                         boundary += (char)b;
365
366                         if (boundary.equals("--myboundary\r\n")) {
367                                 break;
368                         }
369                 }
370         }
371
372         private String getLine() {
373                 String line = "";
374                 while (true) {
375                         byte b = readFromStream(1)[0];
376                         char c = (char)b;
377
378                         if (c == '\n') {
379                                 break;
380                         } else if (c != '\r') {
381                                 line += c;
382                         }
383                 }
384
385                 return line;
386         }
387
388         private BufferedImage parseImage() {
389
390                 findBoundry();
391
392                 String contentTypeString = getLine();
393                 String contentLengthString = getLine();
394
395                 // remove the new line characters \r\n
396                 readFromStream(2);
397
398                 int imageDataLength = Integer.parseInt(contentLengthString.substring(16));
399
400                 byte[] imageDataBuf = readFromStream(imageDataLength);
401
402                 // remove the new line characters \r\n
403                 readFromStream(2);
404
405
406                 try {
407                         InputStream imageInStream = new ByteArrayInputStream(imageDataBuf);
408                         return ImageIO.read(imageInStream);
409
410                 } catch (Exception e) {
411                         e.printStackTrace();
412                         System.out.println("Has Exception");
413
414                 }
415
416                 return null;
417         }
418
419         private boolean streamConnect() {
420
421                 try {
422
423                         String credsPreBase64 = credentialUsername + ":" + credentialPassword;
424                         String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
425                         String httpAuthCredentials = "Basic " + credsBase64;
426
427                         IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
428                         httpConnection.setURL("/cgi-bin/mjpg/video.cgi?");
429                         httpConnection.openConnection();
430                         httpConnection.setDoInput(true);
431                         httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
432                         httpConnection.connect();
433
434                         InputStream is = httpConnection.getInputStream();
435                         BufferedInputStream bis = new BufferedInputStream(is);
436                         dataInStream = new DataInputStream(bis);
437
438                         isStreamConnected = true;
439
440                 } catch (IOException e) {
441                         isStreamConnected = false;
442
443                 } catch (Exception e) {
444                         isStreamConnected = false;
445                 }
446
447                 return isStreamConnected;
448         }
449
450         private void streamDisconnect() {
451                 try {
452                         if (isStreamConnected) {
453                                 dataInStream.close();
454                                 isStreamConnected = false;
455                         }
456                 } catch (Exception e) {
457                 }
458         }
459
460         private void doCallbacks() {
461
462                 while (!doEnd.get()) {
463                         if (newFrameAvailable.compareAndSet(true, false)) {
464
465                                 for (CameraSmartCallback c : callbackList) {
466
467                                         c.newCameraFrameAvailable(this.getLatestFrame(), this.getTimestamp());
468                                 }
469                         } else {
470
471                                 // Sleep for 15 millisec to give time for new frame to arrive
472                                 try {
473                                         Thread.sleep(15);
474                                 } catch (InterruptedException ie) {
475                                 }
476                         }
477                 }
478
479         }
480
481         private void doWork() {
482
483                 // parse the images that are loaded into the buffer
484                 while (!doEnd.get()) {
485
486                         BufferedImage img = parseImage();
487
488                         if (img != null) {
489
490                                 timestampWriteLock.lock();
491                                 latestImageTimestamp = new Date();
492                                 timestampWriteLock.unlock();
493
494                                 imageWriteLock.lock();
495
496                                 try {
497                                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
498                                         ImageIO.write(img, "jpg", baos);
499                                         baos.flush();
500                                         latestImage = baos.toByteArray();
501                                         baos.close();
502
503                                 } catch (Exception e) {
504
505                                 }
506                                 imageWriteLock.unlock();
507
508                                 newFrameAvailable.set(true);
509                         }
510
511                         try {
512                                 if (dataInStream.available() > 120000) {
513                                         dataInStream.skip(120000);
514                                 }
515                         } catch (Exception e) {
516                         }
517                 }
518
519         }
520
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537