Source code: org/jempeg/empeg/protocol/ProtocolClient.java
1 /**
2 * This file is licensed under the GPL.
3 *
4 * See the LICENSE0 file included in this release, or
5 * http://www.opensource.org/licenses/gpl-license.html
6 * for the details of the license.
7 */
8 package org.jempeg.empeg.protocol;
9
10 import org.jempeg.empeg.protocol.event.ProtocolActivityEvent;
11 import org.jempeg.empeg.protocol.event.ProtocolListenerIfc;
12 import org.jempeg.empeg.protocol.event.RequestEvent;
13 import org.jempeg.empeg.protocol.event.RequestListenerIfc;
14 import org.jempeg.empeg.protocol.event.TuneDatabaseEntryEvent;
15 import org.jempeg.empeg.protocol.event.TuneDatabaseIndexEvent;
16 import org.jempeg.empeg.protocol.event.TuneDatabaseListenerIfc;
17 import org.jempeg.empeg.protocol.packet.MountRequestPacket;
18 import org.jempeg.empeg.protocol.packet.StatFSResponsePacket;
19 import org.jempeg.empeg.util.FIDConstants;
20 import org.jempeg.util.Debug;
21 import org.jempeg.util.NumericEnum;
22 import org.jempeg.util.TypeConversionUtils;
23
24 import java.io.BufferedInputStream;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.FileNotFoundException;
28 import java.io.InputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.net.Socket;
32 import java.util.StringTokenizer;
33
34 /**
35 * ProtocolClient defines the protocol
36 * communication layer at a higher level
37 * than Request. ProtocolClient exposes
38 * all of the core processes that can be
39 * performed via the Empeg protocol.
40 *
41 * @author Mike Schrag
42 * @version $Revision: 1.17 $
43 */
44 public class ProtocolClient {
45 public static final int DEFAULT_MAX_RETRIES = 16;
46
47 public static final int PROTOCOL_VERSION_MAJOR = 6;
48 public static final int PROTOCOL_VERSION_MINOR = 0;
49
50 private ConnectionIfc myConn;
51 private int myProtocolVersionMajor;
52 private int myProtocolVersionMinor;
53 private int myMaximumRetryCount;
54 private ProtocolListenerIfc myListener;
55
56 public ProtocolClient(ConnectionIfc _conn) {
57 this(_conn, DEFAULT_MAX_RETRIES);
58 }
59
60 public ProtocolClient(ConnectionIfc _conn, int _maximumRetryCount) {
61 myProtocolVersionMajor = -1;
62 myProtocolVersionMinor = -1;
63
64 myMaximumRetryCount = _maximumRetryCount;
65 myConn = _conn;
66 }
67
68 public ProtocolListenerIfc setProtocolListener(ProtocolListenerIfc _listener) {
69 ProtocolListenerIfc oldListener = myListener;
70 myListener = _listener;
71 return oldListener;
72 }
73
74 public ProtocolListenerIfc getProtocolListener() {
75 return myListener;
76 }
77
78 public ConnectionIfc getConnection() {
79 return myConn;
80 }
81
82 public void open() throws IOException {
83 myConn.open();
84 }
85
86 public void close() throws IOException {
87 myConn.close();
88 }
89
90 protected void fireProgressReported(int _activity, long _current, long _maximum) {
91 if (myListener != null) {
92 ProtocolActivityEvent event = new ProtocolActivityEvent(this, _activity, _current, _maximum);
93 myListener.progressReported(event);
94 }
95 }
96
97 public void setMaximumRetryCount(int _maximumRetryCount) {
98 myMaximumRetryCount = _maximumRetryCount;
99 }
100
101 public String getPlayerConfiguration() throws IOException {
102 String s;
103 try {
104 //Debug.println("ProtocolClient.getPlayerConfiguration()");
105 byte[] data = readFIDToMemory(FIDConstants.FID_CONFIGFILE);
106 s = new String(data);
107 //Debug.println("ProtocolClient.getPlayerConfiguration() = 0");
108 }
109 catch (FileNotFoundException e) {
110 Debug.println("The player configuration file config.ini didn't exist, nomatter.");
111 s = "";
112 }
113 return s;
114 }
115
116 public synchronized long statFID(long _fid) throws IOException {
117 boolean wasOpen = open0();
118 Request r = new Request(myConn);
119 fireProgressReported(ProtocolActivityEvent.STAT, 0, 1);
120
121 long result = -1;
122
123 boolean succeeded = false;
124 for (int retryCount = 0; !succeeded; retryCount ++) {
125 try {
126 result = r.statFID(new EmpegFILEID(_fid)).getValue();
127 succeeded = true;
128 } catch (FileNotFoundException e) {
129 // don't bother retrying if the file doesn't exist
130 throw e;
131 } catch (Throwable t) {
132 errorAction(t, retryCount);
133 }
134 }
135
136 fireProgressReported(ProtocolActivityEvent.STAT, 1, 1);
137 close0(wasOpen);
138 return result;
139 }
140
141 public synchronized byte[] readFIDPartial(long _fid, long _offset, long _requiredSize) throws IOException {
142 boolean wasOpen = open0();
143 Request r = new Request(myConn);
144 _requiredSize = Math.min(_requiredSize, myConn.getPacketSize());
145
146 EmpegCharArray buffer = null;
147
148 boolean succeeded = false;
149 for (int retryCount = 0; !succeeded; retryCount ++) {
150 try {
151 buffer = r.readFID(new EmpegUINT32(_fid), new EmpegUINT32(_offset), new EmpegUINT32(_requiredSize));
152 succeeded = true;
153 } catch (Throwable t) {
154 errorAction(t, retryCount);
155 }
156 }
157
158 close0(wasOpen);
159
160 //Debug.println("readFidPartial: You asked for " + _requiredSize + " bytes, and I gave you " + buffer.length + " bytes.");
161 return buffer.getValue();
162 }
163
164 public byte[] readFIDToMemory(long _fid) throws IOException {
165 //Debug.println("ProtocolClient.readFIDToMemory()");
166 ByteArrayOutputStream baos = new ByteArrayOutputStream();
167 readFID(_fid, baos);
168 byte[] buffer = baos.toByteArray();
169 //Debug.println("ProtocolClient.readFIDToMemory() = done");
170 return buffer;
171 }
172
173 /**
174 * Reads the bytes from the empeg for the given _fid and writes them out to the
175 * given OutputStream. Use ByteArrayOutputStream to read into memory.
176 */
177 public synchronized void readFID(long _fid, OutputStream _os) throws IOException {
178 boolean wasOpen = open0();
179
180 //Debug.println("ProtocolClient.readFID: " + _fid);
181 Request r = new Request(myConn);
182
183 fireProgressReported(ProtocolActivityEvent.STAT, 0, 1);
184 long size = -1;
185 boolean succeeded = false;
186 for (int retryCount = 0; !succeeded; retryCount ++) {
187 try {
188 size = r.statFID(new EmpegFILEID(_fid)).getValue();
189 succeeded = true;
190 } catch (FileNotFoundException e) {
191 // don't bother retrying if the file doesn't exist
192 throw e;
193 } catch (Throwable t) {
194 errorAction(t, retryCount);
195 }
196 }
197
198 if (size < 0) {
199 throw new IOException("ProtocolClient.readFID: size = " + size);
200 }
201
202 r.newRequest();
203
204 fireProgressReported(ProtocolActivityEvent.STAT, 1, 1);
205
206 fireProgressReported(ProtocolActivityEvent.READ, 0, size);
207
208 long offset = 0;
209 do {
210 byte[] chunk = null;
211 succeeded = false;
212 for (int retryCount = 0; !succeeded; retryCount ++) {
213 try {
214 chunk = r.readFID(new EmpegUINT32(_fid), new EmpegUINT32(offset), new EmpegUINT32(Math.min(myConn.getPacketSize(), size - offset))).getValue();
215
216 _os.write(chunk);
217
218 r.newRequest();
219 offset += chunk.length;
220
221 fireProgressReported(ProtocolActivityEvent.READ, offset, size);
222
223 succeeded = true;
224 } catch (Throwable t) {
225 errorAction(t, retryCount);
226 }
227 }
228 } while (offset < size);
229
230 close0(wasOpen);
231 //Debug.println("ProtocolClient.readFID: " + _fid + " Done.");
232 }
233
234 public synchronized long prepareFID(long _fid, long _size) throws IOException {
235 boolean wasOpen = open0();
236 Request r = new Request(myConn);
237 long result = -1;
238
239 boolean succeeded = false;
240 for (int retryCount = 0; !succeeded; retryCount ++) {
241 try {
242 result = r.prepareFID(new EmpegUINT32(_fid), new EmpegUINT32(_size)).getValue();
243 succeeded = true;
244 } catch (Throwable t) {
245 errorAction(t, retryCount);
246 }
247 }
248
249 close0(wasOpen);
250 return result;
251 }
252
253 public void writeFIDPartial(long _fid, long _initialOffset, byte[] _bytes, int _offset, int _length) throws IOException {
254 ByteArrayInputStream bais = new ByteArrayInputStream(_bytes, _offset, _length);
255 writeFID(_fid, _initialOffset, bais, _length);
256 }
257
258 public void writeFIDPartial(long _fid, long _initialOffset, byte[] _bytes) throws IOException {
259 ByteArrayInputStream bais = new ByteArrayInputStream(_bytes);
260 writeFID(_fid, _initialOffset, bais, _bytes.length);
261 }
262
263 public void writeFIDFromMemory(long _fid, byte[] _bytes) throws IOException {
264 ByteArrayInputStream bais = new ByteArrayInputStream(_bytes);
265 writeFID(_fid, 0, bais, _bytes.length);
266 }
267
268 public void writeFID(long _fid, InputStream _is, long _size) throws IOException {
269 writeFID(_fid, 0, _is, _size);
270 }
271
272 /**
273 * Reads all the bytes from the given InputStream and writes them to the given
274 * _fid on the empeg (starting at the _initialOffset on the empeg). Use ByteArrayInputStream for in-memory arrays.
275 */
276 public synchronized void writeFID(long _fid, long _initialOffset, InputStream _is, long _size) throws IOException {
277 boolean wasOpen = open0();
278
279 Request r = new Request(myConn);
280
281 long maxProgress = _size + _size / 4;
282 fireProgressReported(ProtocolActivityEvent.PREPARE, 0, maxProgress);
283
284 boolean succeeded = false;
285 for (int retryCount = 0; !succeeded; retryCount ++) {
286 try {
287 r.prepareFID(new EmpegUINT32(_fid), new EmpegUINT32(_size));
288 succeeded = true;
289 } catch (Throwable t) {
290 errorAction(t, retryCount);
291 }
292 }
293
294 fireProgressReported(ProtocolActivityEvent.PREPARE, _size / 4, maxProgress);
295 long offset = 0;
296 do {
297 r.newRequest();
298 EmpegCharArray chunk = new EmpegCharArray(Math.min(myConn.getPacketSize(), (int)(_size - offset)));
299 long chunkOffset = 0;
300 while (chunkOffset < chunk.getLength()) {
301 chunkOffset += _is.read(chunk.getValue(), (int)chunkOffset, (int)(chunk.getLength() - chunkOffset));
302 }
303
304 succeeded = false;
305 for (int retryCount = 0; !succeeded; retryCount ++) {
306 try {
307 r.writeFID(new EmpegUINT32(_fid), new EmpegUINT32(_initialOffset + offset), chunk);
308 succeeded = true;
309 } catch (Throwable t) {
310 errorAction(t, retryCount);
311 }
312 }
313
314 offset += chunk.getLength();
315 fireProgressReported(ProtocolActivityEvent.WRITE, offset + _size / 4, maxProgress);
316 } while (offset < _size);
317
318 fireProgressReported(ProtocolActivityEvent.WRITE, maxProgress, maxProgress);
319 close0(wasOpen);
320 }
321
322 public synchronized void checkDatabaseAvailability() throws IOException {
323 //Debug.println("ProtocolClient.checkDatabaseAvailability()");
324 boolean wasOpen = open0();
325
326 int result;
327 long size;
328
329 size = statFID(FIDConstants.FID_TAGINDEX);
330 if (size < 16) {
331 throw new IOException("Tag database is suspiciously small. Failing.");
332 }
333 //System.out.println("Tag database is " + size + " bytes.");
334
335 size = statFID(FIDConstants.FID_STATICDATABASE);
336 if (size < 16) {
337 throw new IOException("Static database is suspiciously small. Failing.");
338 }
339 //System.out.println("Static database is " + size + " bytes.");
340
341 size = statFID(FIDConstants.FID_PLAYLISTDATABASE);
342 //System.out.println("Playlist database is " + size + " bytes.");
343
344 //Debug.println("ProtocolClient.checkDatabaseAvailability() = " + size);
345 close0(wasOpen);
346 }
347
348 public synchronized void retrieveTagIndex(TuneDatabaseListenerIfc _listener) throws IOException {
349 boolean wasOpen = open0();
350
351 checkProtocolVersion();
352
353 byte[] tagBuffer = readFIDToMemory(FIDConstants.FID_TAGINDEX);
354 if (tagBuffer.length <= 16) {
355 throw new IOException("Tags file is suspiciously short (" + tagBuffer.length + " bytes), failing gracefully.");
356 }
357
358 String str = new String(tagBuffer);
359 StringTokenizer tokenizer = new StringTokenizer(str, "\n");
360 int index = 0;
361 while (tokenizer.hasMoreTokens()) {
362 String tagName = tokenizer.nextToken();
363 if (tagName.length() > 0) {
364 _listener.tagIndexFound(new TuneDatabaseIndexEvent(this, index, tagName));
365 index ++;
366 }
367 }
368
369 close0(wasOpen);
370 }
371
372 public synchronized void deleteDatabases() throws IOException {
373 boolean wasOpen = open0();
374 deleteFID(FIDConstants.FID_STATICDATABASE);
375 deleteFID(FIDConstants.FID_TAGINDEX);
376 deleteFID(FIDConstants.FID_PLAYLISTDATABASE);
377 close0(wasOpen);
378 }
379
380 public synchronized void retrieveDatabases(TuneDatabaseListenerIfc _listener) throws IOException {
381 boolean wasOpen = open0();
382 byte[] staticBuffer = readFIDToMemory(FIDConstants.FID_STATICDATABASE);
383 byte[] dynamicBuffer = readFIDToMemory(FIDConstants.FID_DYNAMICDATABASE);
384 EmpegInputStream dynDataEIS = new EmpegInputStream(new ByteArrayInputStream(dynamicBuffer));
385
386 int staticPos = 0;
387 int index = 0;
388
389 WrappedDynamicData wrappedDynData = new WrappedDynamicData();
390 try {
391 wrappedDynData.read(dynDataEIS);
392 }
393 catch (IOException e) {
394 e.printStackTrace();
395 }
396
397 while (staticPos < staticBuffer.length) {
398 DynamicData dynData = null;
399 try {
400 wrappedDynData.readNextDynamicData(dynDataEIS);
401 dynData = wrappedDynData.getDynamicData();
402 }
403 catch (IOException e) {
404 Debug.println(e.getMessage());
405 }
406
407 if (staticBuffer[staticPos] != -1) {
408 boolean stopReading = _listener.databaseEntryFound(new TuneDatabaseEntryEvent(this, FIDConstants.makeFID(index, FIDConstants.FIDTYPE_TUNE), staticBuffer, staticPos, dynData));
409 if (stopReading) {
410 break;
411 }
412 }
413
414 // Skip to the next record
415 while (staticBuffer[staticPos] != -1 && staticPos < staticBuffer.length) {
416 staticPos ++;
417 staticPos += TypeConversionUtils.toUnsigned8(staticBuffer[staticPos]) + 1;
418 }
419 staticPos ++;
420 index ++;
421 }
422 close0(wasOpen);
423 }
424
425 public synchronized boolean isUnitConnected() {
426 boolean connected = false;
427 boolean wasOpen = false;
428 try {
429 wasOpen = open0();
430
431 myConn.flushReceiveBuffer();
432
433 Request req = new Request(myConn);
434 req.ping();
435 connected = true;
436 getProtocolVersion0(req);
437 }
438 catch (Throwable t) {
439 Debug.println(t);
440 connected = false;
441 }
442 try {
443 close0(wasOpen);
444 }
445 catch (Throwable t) {
446 Debug.println(t);
447 }
448
449 return connected;
450 }
451
452 public void checkProtocolVersion() throws IOException {
453 if (myProtocolVersionMajor < 0 // assume OK until proven guilty
454 || myProtocolVersionMajor == PROTOCOL_VERSION_MAJOR) {
455 // return;
456 } else if (myProtocolVersionMajor > PROTOCOL_VERSION_MAJOR) {
457 throw new IOException("Empeg is using a protocol newer than the one I am using.");
458 } else {
459 Debug.println("Empeg is using a protocol that is older than the one I am using.");
460 // throw new IOException("Empeg is using a protocol that is older than the one I am using.");
461 }
462 }
463
464 public void waitForPlayer(int _retries) throws IOException {
465 int i;
466 for(i = 0; i < _retries; i ++) {
467 if(isUnitConnected()) {
468 break;
469 }
470 try { Thread.sleep(1000); } catch (Exception e) { }
471 }
472 if(i == _retries) {
473 throw new IOException("Timed out.");
474 }
475 }
476
477 public void waitForUnitConnected() throws IOException {
478 waitForUnitConnected(90000);
479 }
480
481 public synchronized void waitForUnitConnected(long _timeout) throws IOException {
482 myConn.pause();
483
484 try {
485 myConn.unpause();
486 }
487 catch (Throwable t) {
488 Debug.println(t);
489 }
490
491 // myConn.setTimeout(5000);
492 boolean unitConnected = false;
493 long startTime = System.currentTimeMillis();
494 long curTime = 0;
495 Request req = new Request(myConn);
496 do {
497 curTime = (System.currentTimeMillis() - startTime);
498 fireProgressReported(ProtocolActivityEvent.WAITING, curTime, _timeout);
499
500 if (!myConn.isOpen()) {
501 try {
502 myConn.unpause();
503 }
504 catch (Throwable t) {
505 Debug.println(t);
506 }
507 }
508
509 try {
510 req.ping();
511 getProtocolVersion0(req);
512 unitConnected = true;
513 }
514 catch (Throwable t) {
515 Debug.println(t);
516 }
517 } while (!unitConnected && !myConn.isOpen() && curTime < _timeout);
518
519 fireProgressReported(ProtocolActivityEvent.WAITING, _timeout, _timeout);
520 }
521
522 public synchronized void enableWrite(boolean _writeAccess) throws IOException {
523 boolean wasOpen = open0();
524
525 Request r = new Request(myConn);
526 fireProgressReported(ProtocolActivityEvent.REMOUNT, 0, 1);
527
528 boolean succeeded = false;
529 for (int retryCount = 0; !succeeded; retryCount ++) {
530 try {
531 r.mount((_writeAccess) ? MountRequestPacket.MODE_READWRITE : MountRequestPacket.MODE_READONLY);
532 succeeded = true;
533 } catch (Throwable t) {
534 errorAction(t, retryCount);
535 }
536 }
537
538 fireProgressReported(ProtocolActivityEvent.REMOUNT, 1, 1);
539 close0(wasOpen);
540 }
541
542 public synchronized void rebuildPlayerDatabase(long _options) throws IOException {
543 boolean wasOpen = open0();
544
545 Request r = new Request(myConn);
546
547 RequestProgress requestProgress = new RequestProgress(ProtocolActivityEvent.REBUILD);
548 r.setRequestListener(requestProgress);
549
550 boolean succeeded = false;
551 for (int retryCount = 0; !succeeded; retryCount ++) {
552 try {
553 r.buildAndSaveDatabase(new EmpegUINT32(_options));
554 succeeded = true;
555 } catch (Throwable t) {
556 errorAction(t, retryCount);
557 }
558 }
559
560 fireProgressReported(ProtocolActivityEvent.REBUILD, 1, 1);
561
562 close0(wasOpen);
563 }
564
565 public void deleteFID(long _fid) throws IOException {
566 deleteFID(_fid, 0xFFFF);
567 }
568
569 public synchronized void deleteFID(long _fid, long _idMask) throws IOException {
570 boolean wasOpen = open0();
571
572 Request r = new Request(myConn);
573 fireProgressReported(ProtocolActivityEvent.DELETE, 0, 1);
574
575 boolean succeeded = false;
576 for (int retryCount = 0; !succeeded; retryCount ++) {
577 try {
578 r.deleteFID(new EmpegFILEID(_fid), new EmpegUINT32(_idMask));
579 succeeded = true;
580 } catch (Throwable t) {
581 errorAction(t, retryCount);
582 }
583 }
584
585 fireProgressReported(ProtocolActivityEvent.DELETE, 1, 1);
586 close0(wasOpen);
587 }
588
589 public synchronized StatFSResponsePacket getDiskInfo() throws IOException {
590 boolean wasOpen = open0();
591
592 Request r = new Request(myConn);
593 fireProgressReported(ProtocolActivityEvent.DISK_INFO, 0, 1);
594 StatFSResponsePacket diskInfo = null;
595
596 boolean succeeded = false;
597 for (int retryCount = 0; !succeeded; retryCount ++) {
598 try {
599 diskInfo = r.freeSpace();
600 succeeded = true;
601 } catch (Throwable t) {
602 errorAction(t, retryCount);
603 }
604 }
605
606 fireProgressReported(ProtocolActivityEvent.DISK_INFO, 1, 1);
607 close0(wasOpen);
608 return diskInfo;
609 }
610
611 public synchronized void fsck(String _drive) throws IOException {
612 boolean wasOpen = open0();
613
614 Request r = new Request(myConn);
615
616 RequestProgress requestProgress = new RequestProgress(ProtocolActivityEvent.CHECK);
617 r.setRequestListener(requestProgress);
618 long result = -1;
619
620 boolean succeeded = false;
621 for (int retryCount = 0; !succeeded; retryCount ++) {
622 try {
623 myConn.flushReceiveBuffer();
624 result = r.fsck(_drive, new EmpegInt(0)).getValue();
625 succeeded = true;
626 } catch (Throwable t) {
627 errorAction(t, retryCount);
628 }
629 }
630
631 boolean bad = false;
632
633 if ((result & 1) != 0) {
634 System.err.println("FSCK corrected some errors on drive " + _drive);
635 }
636 if ((result & 2) != 0) {
637 System.err.println("FSCK thinks the system should be rebooted on drive " + _drive);
638 bad = true;
639 }
640 if ((result & 4) != 0) {
641 System.err.println("FSCK left stuff uncorrected on drive " + _drive);
642 bad = true;
643 }
644 if ((result & 8) != 0) {
645 System.err.println("FSCK reported operational error on drive " + _drive);
646 bad = true;
647 }
648 if ((result & 16) != 0) {
649 System.err.println("FSCK report usage or syntax error on drive " + _drive);
650 bad = true;
651 }
652 if ((result & 128) != 0) {
653 System.err.println("FSCK reported shared library error on drive " + _drive);
654 bad = true;
655 }
656 if ((result & 512) != 0) {
657 System.err.println("FSCK reported disk is not present on drive " + _drive);
658 }
659
660 if (bad) {
661 throw new IOException("FSCK found an serious problem (check logs for explanation).");
662 }
663
664 fireProgressReported(ProtocolActivityEvent.CHECK, 1, 1);
665 close0(wasOpen);
666 }
667
668 public synchronized void checkMedia() throws IOException {
669 boolean wasOpen = open0();
670
671 fsck("/dev/hda4");
672 fsck("/dev/hdc4");
673
674 close0(wasOpen);
675 }
676
677 public void sendCommand(long _command) throws IOException {
678 sendCommand(_command, 0, 0, "");
679 }
680
681 public void sendCommand(long _command, long _parameter0) throws IOException {
682 sendCommand(_command, _parameter0, 0, "");
683 }
684
685 public void sendCommand(long _command, long _parameter0, long _parameter1) throws IOException {
686 sendCommand(_command, _parameter0, _parameter1, "");
687 }
688
689 public synchronized void sendCommand(long _command, long _parameter0, long _parameter1, String _parameter2) throws IOException {
690 boolean wasOpen = open0();
691
692 Request r = new Request(myConn);
693
694 boolean succeeded = false;
695 for (int retryCount = 0; !succeeded; retryCount ++) {
696 try {
697 myConn.flushReceiveBuffer();
698 r.sendCommand(new EmpegInt(_command), new EmpegInt(_parameter0), new EmpegInt(_parameter1), _parameter2);
699 succeeded = true;
700 } catch (Throwable t) {
701 errorAction(t, retryCount);
702 }
703 }
704
705 close0(wasOpen);
706 }
707
708 public void restartPlayer(boolean _autoSlumber) throws IOException {
709 restartPlayer(_autoSlumber, true);
710 }
711
712 public synchronized void restartPlayer(boolean _autoSlumber, boolean _waitForCompletion) throws IOException {
713 long param = Request.RESTART_PLAYER;
714 if (_autoSlumber) {
715 param |= Request.RESTART_IN_SLUMBER;
716 }
717 internalRestart(param, _waitForCompletion);
718
719 }
720
721 public void restartUnit(boolean _autoSlumber) throws IOException {
722 restartUnit(_autoSlumber, true);
723 }
724
725 public synchronized void restartUnit(boolean _autoSlumber, boolean _waitForCompletion) throws IOException {
726 long param = Request.RESTART_UNIT;
727 if (_autoSlumber) {
728 param |= Request.RESTART_IN_SLUMBER;
729 }
730 internalRestart(param, _waitForCompletion);
731 }
732
733 protected void internalRestart(long _param, boolean _waitForCompletion) throws IOException {
734 sendCommand(Request.COM_RESTART, _param);
735
736 if (_waitForCompletion) {
737 try {
738 Thread.sleep(2000);
739 } catch (Exception e) {
740 }
741
742 waitForUnitConnected();
743 }
744 }
745
746 public void lockUI(boolean _lock) throws IOException {
747 sendCommand(Request.COM_LOCKUI, _lock ? 1 : 0);
748 }
749
750 public void setSlumber(boolean _slumber) throws IOException {
751 sendCommand(Request.COM_SLUMBER, _slumber ? 1 : 0);
752 }
753
754 public void playerFID(long _fid) throws IOException {
755 sendCommand(Request.COM_PLAYFID, _fid);
756 }
757
758 public void setPlayState(long _playState) throws IOException {
759 sendCommand(Request.COM_PLAYSTATE, _playState);
760 }
761
762 public synchronized byte[] grabScreen() throws IOException {
763 boolean wasOpen = open0();
764 Request r = new Request(myConn);
765 byte[] screen = r.grabScreen(new EmpegInt(0)).getValue();
766 close0(wasOpen);
767 return screen;
768 }
769
770 protected boolean open0() throws IOException {
771 boolean isOpen = myConn.isOpen();
772 if (!isOpen) {
773 myConn.open();
774 }
775 return isOpen;
776 }
777
778 protected void close0(boolean _wasOpen) throws IOException {
779 if (!_wasOpen) {
780 myConn.close();
781 }
782 }
783
784 public String getPlayerType() throws IOException {
785 String type;
786 try {
787 byte[] buffer = readFIDToMemory(FIDConstants.FID_PLAYERTYPE);
788 type = new String(buffer, 0, buffer.length - 1);
789 }
790 catch (FileNotFoundException e) {
791 // ... That's ok ...
792 type = "";
793 }
794 return type;
795 }
796
797 public PlayerVersionInfo getVersionInfo() throws IOException {
798 //Debug.println("ProtocolClient.getVersionInfo()");
799
800 byte[] buffer = readFIDToMemory(FIDConstants.FID_VERSION);
801 String versionStr = new String(buffer);
802 StringTokenizer tokenizer = new StringTokenizer(versionStr, "\n");
803 String version = tokenizer.nextToken();
804 String beta = tokenizer.nextToken();
805 String protocolStr = tokenizer.nextToken();
806 int protocol = Integer.parseInt(protocolStr);
807 PlayerVersionInfo versionInfo = new PlayerVersionInfo(version, beta, protocol);
808
809 //Debug.println("ProtocolClient.getVersionInfo() = done");
810
811 return versionInfo;
812 }
813
814 public synchronized void getProtocolVersion0(Request _request) throws IOException {
815 myProtocolVersionMajor = _request.getProtocolVersionMajor().getValue();
816 myProtocolVersionMinor = _request.getProtocolVersionMinor().getValue();
817 }
818
819 public synchronized int[] getProtocolVersion() throws IOException {
820 if (myProtocolVersionMajor == -1 || myProtocolVersionMinor == -1) {
821 boolean wasOpen = open0();
822 Request r = new Request(myConn);
823 r.ping();
824 getProtocolVersion0(r);
825 close0(wasOpen);
826 }
827
828 int[] majMin = new int[2];
829 majMin[0] = myProtocolVersionMajor;
830 majMin[1] = myProtocolVersionMinor;
831
832 return majMin;
833 }
834
835 public void setPlayerConfiguration(String _configStr) throws IOException {
836 writeFIDFromMemory(FIDConstants.FID_CONFIGFILE, _configStr.getBytes());
837 }
838
839 public PlayerIdentity getPlayerIdentity() throws IOException {
840 PlayerIdentity playerID = new PlayerIdentity();
841
842 byte[] buffer = readFIDToMemory(FIDConstants.FID_ID);
843 String idStr = new String(buffer);
844 StringTokenizer tokenizer = new StringTokenizer(idStr, "\n");
845 while (tokenizer.hasMoreTokens()) {
846 String token = tokenizer.nextToken();
847 int colonIndex = token.indexOf(':');
848 String key = token.substring(0, colonIndex).trim();
849 String value = token.substring(colonIndex + 1).trim();
850
851 if (key.equals("hwrev")) {
852 playerID.setHWRev(value);
853 } else if (key.equals("serial")) {
854 playerID.setSerial(value);
855 } else if (key.equals("build")) {
856 playerID.setBuild(value);
857 } else if (key.equals("id")) {
858 playerID.setID(value);
859 } else if (key.equals("ram")) {
860 playerID.setRAM(value);
861 } else if (key.equals("flash")) {
862 playerID.setFlash(value);
863 } else {
864 Debug.println("getPlayerIdentity: Don't know what to do with key = " + key + "; value = " + value);
865 }
866 }
867
868 return playerID;
869 }
870
871 protected void errorAction(Throwable _t, int _retries) throws IOException {
872 Debug.println("Retry #" + _retries + " failed. (" + _t.getMessage() + ")");
873 Debug.println(_t);
874 //_t.printStackTrace();
875
876 //org.jempeg.util.Debug.println("Flushing because of failure...");
877 myConn.flushReceiveBuffer();
878
879 if (_retries >= myMaximumRetryCount) {
880 throw new IOException("Operation failure exceeded maximum retry count.");
881 }
882
883 while (_retries > 3) {
884 try {
885 //org.jempeg.util.Debug.println("Sleeping due to excessive retries...");
886 Thread.sleep(1000);
887 } catch (InterruptedException e) {
888 }
889 _retries --;
890 }
891 }
892
893 protected class RequestProgress implements RequestListenerIfc {
894 private int myActivity;
895
896 public RequestProgress(int _activity) {
897 myActivity = _activity;
898 }
899
900 public void actionProgressed(RequestEvent _event) {
901 if (myListener == null) {
902 return;
903 }
904
905 long progress;
906 long maximum = _event.getMaximum();
907 long stage = _event.getStage();
908 long stageMaximum = _event.getStageMaximum();
909 long current = _event.getCurrent();
910 long total = maximum * stageMaximum;
911 if ((stage != stageMaximum) || (current != maximum)) {
912 progress = (stage - 1) * maximum + current;
913 } else {
914 progress = total;
915 }
916
917 if (progress > total) {
918 progress = total;
919 }
920
921 fireProgressReported(myActivity, progress, total);
922 }
923 }
924 }