Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }