001/*
002 *  $Rev: 1393 $:     Revision of last commit
003 *  $Author: tgutwin $:  Author of last commit
004 *  $Date: 2020-10-10 19:22:00 -0700 (Sat, 10 Oct 2020) $:    Date of last commit
005 *  $URL: svn://fred.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/sockets/PirateTunesClientThread.java $
006 */
007/*
008 *
009 *  Written by Tom Gutwin - WebARTS Design.
010 *  Copyright (C) 2020 WebARTS Design, North Vancouver Canada
011 *  http://www.webarts.bc.ca
012 *
013 *  This program is free software; you can redistribute it and/or modify
014 *  it under the terms of the GNU General Public License as published by
015 *  the Free Software Foundation; either version 2 of the License, or
016 *  (at your option) any later version.
017 *
018 *  This program is distributed in the hope that it will be useful,
019 *  but WITHOUT ANY WARRANTY; without_ even the implied warranty of
020 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
021 *  GNU General Public License for more details.
022 *
023 *  You should have received a copy of the GNU General Public License
024 *  along with this program; if not, write to the Free Software
025 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
026 */
027
028package ca.bc.webarts.tools.sockets;
029
030import java.io.BufferedReader;
031import java.io.DataInputStream;
032import java.io.InputStreamReader;
033import java.io.PrintStream;
034import java.io.IOException;
035import java.net.Socket;
036import java.util.Arrays;
037import java.util.ArrayList;
038import java.util.Collections;
039import java.util.List;
040import java.util.Vector;
041
042import ca.bc.webarts.JOggPlayerListener;
043
044
045/** The ClientThread extension used by the {@link JOggPlayerSocketServer JOggPlayerSocketServer} ({@link TCPSocketServer TCPSocketServer}) to
046  * deal with playing tunes through the Pi PirateAudio shield.  Each time a SocketConnection comes in, this client Thread is spawned to handle the request.
047  * It does all the Vorbis Ogg playing using the {@link ca.bc.webarts.JOggPlayerListener JOggPlayerListener} class.
048  *
049  **/
050public class PirateTunesClientThread extends ClientThread
051{
052  /** The root dir for all ogg content with Artist/Album subDirs.
053    * It gets pre-pended to ALL commadparms that represent tunes.
054    **/
055  protected String piSndOggRootDir_ = "/mnt/nas/snd/ogg";
056
057  /** DEPRECATED flag to use ogg123. **/
058  @Deprecated
059  protected boolean useOgg123_ = false;
060
061  /** Class instance to the JOggPlayer. **/
062  protected JOggPlayerListener player_ = JOggPlayerListener.getInstance();
063  Thread playerThread_ = new Thread(player_, "JOggPlayerListener");;
064  Thread looperThread_ = null;
065  long currentPlayerThreadId_ = 0;
066  /** Any responses (if any) to send back to client. **/
067  Vector <String> responses_ = new Vector <String> ();
068  /** Flags if the command will send a response. **/
069  boolean responseExpected_ = false;
070
071
072  /** Contstructor that accepts the clientSocket to grab data /command from.
073    *
074    * @param clientSocket the clientSocket to grab data /command from
075    **/
076  public PirateTunesClientThread(Socket clientSocket)
077  {
078    super(clientSocket);
079    debug_=2; // 0 is silent, 1 is error only; 2 is basic info, 3 is verbose, 4 is all
080  }
081
082
083  /** Pass the already instantiated JOggPlayerListener to this class. **/
084  @Deprecated
085  public int setPlayer(ca.bc.webarts.JOggPlayerListener player)
086  {
087    int retVal = 1;
088    player_ = player;
089    playerThread_ = new Thread(player_, "JOggPlayerListener");
090
091    return retVal;
092  }
093
094
095  /** DEPRECATED method to play tunes using ogg123.
096    *
097    * @param cmdArgs the command requests received over the socket
098    **/
099  @Deprecated
100  protected int runWithOgg123(String[] cmdArgs)
101  {
102    int retVal = 1;
103      java.util.List<String> results = null;
104      int exitCode = 0;
105
106      String killer = "/usr/bin/killer";
107      String ogg123 = "/usr/bin/ogg123";
108      String ogginfo = "/usr/bin/ogginfo";
109
110      List <String> stopCmdList = Collections.synchronizedList(new <String> ArrayList());  //Arrays.asList(cmdArgs);
111      stopCmdList.add(killer);
112      stopCmdList.add(ogg123);
113
114      List <String> cmdList = Collections.synchronizedList(new <String> ArrayList());  //Arrays.asList(cmdArgs);
115      cmdList.add(ogg123);
116
117      boolean stopCommand = false;
118      boolean validCommand = true;
119
120      String piTunePath = "";
121      if(!"stop".equalsIgnoreCase(cmdArgs[0])) piTunePath = piSndOggRootDir_+"/"+cmdArgs[1];
122      switch (cmdArgs[0])
123      {
124        case "tune" :                // tune songNamePath
125          cmdList.add("-q");
126          cmdList.add(piTunePath);
127          break;
128
129        case "tunes" :                // tunes dirNamePath
130          cmdList.add("-q");
131          cmdList.add(piTunePath);
132          break;
133
134        case "shuffletunes" :         // shuffleTunes dirNamePath
135        case "shuffleTunes" :         // shuffleTunes dirNamePath
136          cmdList.add("-q");
137          cmdList.add("-z");
138          cmdList.add(piTunePath);
139          break;
140
141        case "repeatshuffletunes" :         // shuffleTunes dirNamePath
142        case "repeatShuffleTunes" :         // shuffleTunes dirNamePath
143          cmdList.add("-q");
144          cmdList.add("-Z");
145          cmdList.add(piTunePath);
146          break;
147
148        case "stop" :
149          stopCommand= true;
150          break;
151
152        default:
153          validCommand = false;
154      }
155
156      /* Execute the request. */
157      if(validCommand)
158      {
159        synchronized (this)
160        {
161
162          // send a native command
163          if (debug_>1) System.out.print("Executing an audio command...");
164          java.lang.Process procRet = null;
165          try
166          {
167            // ALWAYS Call a STOP first
168            java.lang.ProcessBuilder pb = new java.lang.ProcessBuilder(stopCmdList);
169            pb.directory(new java.io.File(piSndOggRootDir_));  //TEMP_DIR));
170            procRet = pb.start();
171            exitCode = procRet.waitFor();
172
173            if(!stopCommand)
174            {
175              // Now the real command
176              pb = new java.lang.ProcessBuilder(cmdList);
177              procRet = pb.start();
178              os.println("...");
179              if (debug_>1) System.out.println(" !!");
180              results = readOutput(procRet.getInputStream());
181              exitCode = procRet.waitFor();
182            }
183          }
184          catch (Exception ex)
185          {
186            ex.printStackTrace();
187            procRet = null;
188          }
189          if(procRet!=null && procRet.exitValue()==0)
190          {
191            os.println(TCPSocketServer.SUCCESS);
192            if(results!=null) for(String s : results) os.println(s);
193          }
194          else
195            os.println(TCPSocketServer.ERROR);
196
197          os.println(TCPSocketServer.END);
198
199        }
200        retVal = 0;
201      }
202      else if (debug_>0) System.out.println(" INValid Command: "+cmdArgs[0]);
203      if (debug_>1) System.out.println("   >Closing ClientThread: "+ Thread.currentThread().getId());
204
205    return retVal;
206  }
207
208
209  /** The primary method that parses the commad params and handles them by sending appropriate signals to JOggPlayerListener.
210    *
211    * @param cmdArgs the command requests received over the socket
212    **/
213  protected int runWithJOggPlayer(String[] cmdArgs)
214  {
215    int retVal = 1;
216    player_ = JOggPlayerListener.getInstance();
217
218    List <String> cmdList = Collections.synchronizedList(new <String> ArrayList());  //Arrays.asList(cmdArgs);
219
220    String piTunePath = "";
221    if("tune".equalsIgnoreCase(cmdArgs[0]) ||
222       "tunes".equalsIgnoreCase(cmdArgs[0]))
223    {
224      //this one always starts FRESHand Clean
225      player_.clearPlaylist();
226      player_.clearStopSignal();
227
228      piTunePath = piSndOggRootDir_+"/"+cmdArgs[1];
229      if (cmdArgs.length >1)
230      {
231        for (int i = 1; i < cmdArgs.length; i++)
232        {
233          piTunePath = piSndOggRootDir_+"/"+cmdArgs[i];
234          player_.addToPlaylist(piTunePath);
235        }
236
237        player_.signalStopPlay();              // needed to ensure ungarbled start to the songs
238        ca.bc.webarts.widgets.Util.sleep(200); // needed to ensure ungarbled start to the songs
239
240        // START Playing
241        player_.play_sound();
242        currentPlayerThreadId_ = playerThread_.getId();
243        retVal = 0;
244      }
245    }
246    else if("tunesDir".equalsIgnoreCase(cmdArgs[0]) ||
247            "album".equalsIgnoreCase(cmdArgs[0])||
248            "artist".equalsIgnoreCase(cmdArgs[0]))
249    {
250      //this one always starts FRESHand Clean
251      player_.clearPlaylist();
252      player_.clearStopSignal();
253
254      piTunePath = piSndOggRootDir_+"/"+cmdArgs[1];
255      if (cmdArgs.length >1)
256      {
257        String [] piTunePaths = new String [ cmdArgs.length-1];
258        for (int i = 1; i < cmdArgs.length; i++)
259        {
260          piTunePaths[i-1] = piSndOggRootDir_+"/"+cmdArgs[i];
261        }
262        player_.addDirFilesToPlaylist(piTunePaths, true);
263
264        player_.signalStopPlay();              // needed to ensure ungarbled start to the songs
265        ca.bc.webarts.widgets.Util.sleep(200); // needed to ensure ungarbled start to the songs
266
267        // START Playing
268        player_.play_sound();
269        currentPlayerThreadId_ = playerThread_.getId();
270        retVal = 0;
271      }
272    }
273
274    /* add Add a single item */
275    else if("add".equalsIgnoreCase(cmdArgs[0]))
276    {
277      piTunePath = piSndOggRootDir_+"/"+cmdArgs[1];
278      if (cmdArgs.length >1)
279      {
280        String [] piTunePaths = new String [ cmdArgs.length-1];
281        for (int i = 1; i < cmdArgs.length; i++)
282        {
283          piTunePaths[i-1] = piSndOggRootDir_+"/"+cmdArgs[i];
284          piTunePath = piSndOggRootDir_+"/"+cmdArgs[i];
285          player_.addToPlaylist(piTunePath);
286        }
287        //player_.addToPlaylist(piTunePath);
288
289        //player_.play_sound();
290        currentPlayerThreadId_ = playerThread_.getId();
291        retVal = 0;
292      }
293    }
294
295    /* addDir Adds all songs recursively */
296    else if("addDir".equalsIgnoreCase(cmdArgs[0]))
297    {
298      piTunePath = piSndOggRootDir_+"/"+cmdArgs[1];
299      if (cmdArgs.length >1)
300      {
301        String [] piTunePaths = new String [ cmdArgs.length-1];
302        for (int i = 1; i < cmdArgs.length; i++)
303        {
304          piTunePaths[i-1] = piSndOggRootDir_+"/"+cmdArgs[i];
305        }
306        player_.addDirFilesToPlaylist(piTunePaths, true);
307
308        //player_.play_sound();
309        currentPlayerThreadId_ = playerThread_.getId();
310        retVal = 0;
311      }
312    }
313    else if("playNum".equalsIgnoreCase(cmdArgs[0]))
314    {
315      if (cmdArgs.length >1)
316      {
317        try
318        {
319          int pNum =  Integer.parseInt(cmdArgs[1]);
320          if(true  || !player_.isStopped())
321          {
322            player_.signalStopPlay();
323            ca.bc.webarts.widgets.Util.sleep(200);
324          }
325          player_.play_sound(pNum);
326          currentPlayerThreadId_ = playerThread_.getId();
327          retVal = 0;
328        }
329        catch(Exception ex)
330        {
331          if (debug_>0) System.out.println(" playNum requires an int as a second parameter:\n"+cmdArgs[1]+ "\n   is NOT an int");
332        }
333      }
334      else
335        if (debug_>0) System.out.println(" playNum requires an int as a second parameter");
336    }
337    else if("clearPlaylist".equalsIgnoreCase(cmdArgs[0]))
338    {
339      player_.clearPlaylist();
340      currentPlayerThreadId_ = playerThread_.getId();
341      retVal = 0;
342    }
343    else if("getShuffling".equalsIgnoreCase(cmdArgs[0]))
344    {
345      responseExpected_ = true;
346      responses_.add(""+player_.getShuffling());
347      currentPlayerThreadId_ = playerThread_.getId();
348      retVal = 0;
349    }
350    else if("shufflePlay".equalsIgnoreCase(cmdArgs[0]))
351    {
352      if (debug_>1) System.out.print("\n       >>  ** PirateTunes shufflePlay linearPlay Request ");
353      player_.setShuffling(true);
354      currentPlayerThreadId_ = playerThread_.getId();
355      responseExpected_ = true;
356      ca.bc.webarts.widgets.Util.sleep(200);
357      responses_.add("shuffle");
358      retVal = 0;
359    }
360    else if("linearPlay".equalsIgnoreCase(cmdArgs[0]))
361    {
362      if (debug_>1) System.out.print("\n       >>  **PirateTunes linearPlay Request ");
363      player_.setShuffling(false);
364      currentPlayerThreadId_ = playerThread_.getId();
365      responseExpected_ = true;
366      ca.bc.webarts.widgets.Util.sleep(200);
367      responses_.add("linear");
368      retVal = 0;
369    }
370    else if("next".equalsIgnoreCase(cmdArgs[0]))
371    {
372      player_.signalNextInPlaylist();
373      currentPlayerThreadId_ = playerThread_.getId();
374      responseExpected_ = true;
375      ca.bc.webarts.widgets.Util.sleep(200);
376      responses_.add(player_.getTitle());
377      retVal = 0;
378    }
379    else if("play".equalsIgnoreCase(cmdArgs[0]))
380    {
381      if(!player_.isStopped())
382      {
383        player_.signalStopPlay();
384        ca.bc.webarts.widgets.Util.sleep(200);
385      }
386      player_.play_current_sound();
387      currentPlayerThreadId_ = playerThread_.getId();
388      retVal = 0;
389    }
390    else if( "pause".equalsIgnoreCase(cmdArgs[0])||
391             "unpause".equalsIgnoreCase(cmdArgs[0])||
392             "togglepause".equalsIgnoreCase(cmdArgs[0]))
393    {
394      player_.signalLoopPaused();
395      currentPlayerThreadId_ = playerThread_.getId();
396      retVal = 0;
397    }
398    else if("previous".equalsIgnoreCase(cmdArgs[0]) ||
399            "prev".equalsIgnoreCase(cmdArgs[0]))
400    {
401      player_.signalPreviousInPlaylist();
402      currentPlayerThreadId_ = playerThread_.getId();
403      responseExpected_ = true;
404      ca.bc.webarts.widgets.Util.sleep(200);
405      responses_.add(player_.getTitle());
406      retVal = 0;
407    }
408    else if("stop".equalsIgnoreCase(cmdArgs[0]))
409    {
410      if (debug_>1) System.out.println("     threadID="+currentPlayerThreadId_+  "   Stopping the current song...");
411      player_.signalStopPlay();
412      retVal = 0;
413    }
414    else if("getCurrentPlaylistIndex".equalsIgnoreCase(cmdArgs[0]))
415    {
416      responseExpected_ = true;
417      responses_.add(""+player_.getCurrentPlaylistIndex());
418      currentPlayerThreadId_ = playerThread_.getId();
419      retVal = 0;
420    }
421    else if("getPlaylistSize".equalsIgnoreCase(cmdArgs[0]))
422    {
423      responseExpected_ = true;
424      responses_.add(""+player_.getPlaylistSize());
425      currentPlayerThreadId_ = playerThread_.getId();
426      retVal = 0;
427    }
428    else if("getTitle".equalsIgnoreCase(cmdArgs[0]))
429    {
430      responseExpected_ = true;
431      responses_.add(player_.getTitle());
432      currentPlayerThreadId_ = playerThread_.getId();
433      retVal = 0;
434    }
435    else if("getFilename".equalsIgnoreCase(cmdArgs[0]))
436    {
437      responseExpected_ = true;
438      responses_.add(player_.getFilename());
439      currentPlayerThreadId_ = playerThread_.getId();
440      retVal = 0;
441    }
442    else if("getAlbumCoverURL".equalsIgnoreCase(cmdArgs[0]))
443    {
444      responseExpected_ = true;
445      responses_.add(player_.getAlbumCoverURL());
446      currentPlayerThreadId_ = playerThread_.getId();
447      retVal = 0;
448    }
449    else if("getArtistName".equalsIgnoreCase(cmdArgs[0]))
450    {
451      responseExpected_ = true;
452      responses_.add(player_.getArtistName());
453      currentPlayerThreadId_ = playerThread_.getId();
454      retVal = 0;
455    }
456    else if("getAlbumName".equalsIgnoreCase(cmdArgs[0]))
457    {
458      responseExpected_ = true;
459      responses_.add(player_.getAlbumName());
460      currentPlayerThreadId_ = playerThread_.getId();
461      retVal = 0;
462    }
463    else if("getSongName".equalsIgnoreCase(cmdArgs[0]))
464    {
465      responseExpected_ = true;
466      responses_.add(player_.getSongName() );
467      currentPlayerThreadId_ = playerThread_.getId();
468      retVal = 0;
469    }
470    else if("getSongComments".equalsIgnoreCase(cmdArgs[0]))
471    {
472      responseExpected_ = true;
473      responses_.addAll(player_.getSongComments() );
474      currentPlayerThreadId_ = playerThread_.getId();
475      retVal = 0;
476    }
477    else if("getAlbumTrackNum".equalsIgnoreCase(cmdArgs[0]))
478    {
479      responseExpected_ = true;
480      String numStr = "??";
481         int pNum =  player_.getAlbumTrackNum();
482         if(pNum>0) numStr = ""+pNum;
483      responses_.add(numStr);
484      currentPlayerThreadId_ = playerThread_.getId();
485      retVal = 0;
486    }
487    else if("getSongDuration".equalsIgnoreCase(cmdArgs[0]))
488    {
489      responseExpected_ = true;
490      String numStr = "??";
491         int pNum =  player_.retrieveSongDurationInMiliSeconds();
492         if(pNum>0) numStr = ""+pNum;
493      responses_.add(numStr);
494      currentPlayerThreadId_ = playerThread_.getId();
495      retVal = 0;
496    }
497    else if("getSongTimePlaying".equalsIgnoreCase(cmdArgs[0]))
498    {
499      responseExpected_ = true;
500      String numStr = "??";
501         int pNum =  player_.retrieveCurrentTunePlayTimeInMiliSeconds();
502         if(pNum>0) numStr = ""+pNum;
503      responses_.add(numStr);
504      currentPlayerThreadId_ = playerThread_.getId();
505      retVal = 0;
506    }
507    else if("getSongProgress".equalsIgnoreCase(cmdArgs[0]))
508    {
509      responseExpected_ = true;
510      String numStr = "??";
511         int pNum =  player_.retrieveTuneProgressRatio();
512         if(pNum>0) numStr = ""+pNum;
513      responses_.add(numStr);
514      currentPlayerThreadId_ = playerThread_.getId();
515      retVal = 0;
516    }
517    else if("getIndexedPlaylist".equalsIgnoreCase(cmdArgs[0]))
518    {
519      responseExpected_ = true;
520      responses_.addAll(player_.getIndexedPlaylistArtistAlbumSongnames(true));
521      //for (int i=0; i< player_.getPlaylistSize();i++)
522      //  responses_.add(i+" : "+player_.playlist_.get(i));
523      currentPlayerThreadId_ = playerThread_.getId();
524      retVal = 0;
525    }
526    else if("getPlaylist".equalsIgnoreCase(cmdArgs[0]))
527    {
528      responseExpected_ = true;
529      responses_.addAll(player_.getIndexedPlaylistArtistAlbumSongnames(false));
530      //for (int i=0; i< player_.getPlaylistSize();i++)
531      //  responses_.add(i+" : "+player_.playlist_.get(i));
532      currentPlayerThreadId_ = playerThread_.getId();
533      retVal = 0;
534    }
535    else if("isStopped".equalsIgnoreCase(cmdArgs[0]))
536    {
537      responseExpected_ = true;
538      String numStr = "??";
539         boolean bVal =  player_.isStopped();
540      responses_.add(""+bVal);
541      currentPlayerThreadId_ = playerThread_.getId();
542      retVal = 0;
543    }
544    else if("isSongPlaying".equalsIgnoreCase(cmdArgs[0]))
545    {
546      responseExpected_ = true;
547      String numStr = "??";
548         boolean bVal =  player_.isPlaying();
549      responses_.add(""+bVal);
550      currentPlayerThreadId_ = playerThread_.getId();
551      retVal = 0;
552    }
553    else if("isSongPaused".equalsIgnoreCase(cmdArgs[0]))
554    {
555      responseExpected_ = true;
556      String numStr = "??";
557         boolean bVal =  player_.isPaused();
558      responses_.add(""+bVal);
559      currentPlayerThreadId_ = playerThread_.getId();
560      retVal = 0;
561    }
562    else
563    {
564      if (debug_>0) System.out.println("   > PirateTunesClientThread.runWithJOggPlayer\n    need a valid command [ commandList, stop, pause, resume... ]");
565      responseExpected_ = true;
566      responses_.add("   > PirateTunesClientThread.runWithJOggPlayer\n       "+cmdArgs[0]+"\n   need a valid command [ commandList, stop, pause, resume... ]");
567      currentPlayerThreadId_ = playerThread_.getId();
568      retVal = 1;
569    }
570
571    return retVal;
572  }
573
574
575  /** The Overriden thread execution method.  **/
576  @Override
577  public void run()
578  {
579    String TEMP_DIR = System.getProperty("java.io.tmpdir");
580    Thread me = Thread.currentThread();
581    int retVal = 0;
582    try
583    {
584      /*
585       * Create input and output streams for this client.
586       */
587      if (debug_>2) System.out.println("   >Starting PirateTunesClientThread: "+ me.getId());
588
589      is = new DataInputStream(clientSocket.getInputStream()); // this uses a deprecated readline API, hence the BufferedReader
590      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
591      os = new PrintStream(clientSocket.getOutputStream());  //used to send responses
592      String clientRequest = "";
593
594      //os.println("?");
595      clientRequest = bufferedReader.readLine().trim();  // is.readLine().trim();
596      if (debug_>1) System.out.print("\nNEW\n > PirateTunesClientRequest: ");
597      String[] cmdArgs = clientRequest.split("\\s");
598      if (debug_>1) System.out.println(Arrays.toString(cmdArgs));
599
600      if(cmdArgs!=null && cmdArgs.length>0 ) //&& !"stop".equalsIgnoreCase(cmdArgs[0]))
601      {
602        // 1st check for non-JOggPlayer requests
603        if("commandList".equalsIgnoreCase(cmdArgs[0]))
604        {
605          responseExpected_ = true;
606          responses_.addAll(getCommandList());  //addAll(Collection<? extends E> c)
607          currentPlayerThreadId_ = playerThread_.getId();
608        }
609        else if(useOgg123_)
610        {
611          retVal = runWithOgg123(cmdArgs);
612        }
613        else
614        {
615          if (debug_>1) System.out.print("   > PirateTunesClientRequest passing control to JOggPlayer ");
616          retVal = runWithJOggPlayer(cmdArgs);
617        }
618      }
619
620      /* Check if response */
621      if(responseExpected_)
622      {
623        if(os!=null )
624        {
625          if(retVal==0)
626          {
627            os.println(TCPSocketServer.SUCCESS);
628          }
629          else
630          {
631            os.println(TCPSocketServer.ERROR);
632          }
633          if(responses_.size()>0)
634            for(String s : responses_ ) os.println(s);
635
636          os.println(TCPSocketServer.END);
637
638        }
639      }
640
641      if (debug_>2) System.out.println("\n   > PirateTunesClientThread: "+ me.getId()+" CLEANUP");
642      //while(!player_.isStopped())
643        ca.bc.webarts.widgets.Util.sleep(1000);
644      /*
645       * Close the output stream, close the input stream, close the socket.
646       */
647      is.close();
648      os.close();
649      clientSocket.close();
650      playerThread_ = null;
651      player_=null;
652    }
653    catch (IOException e)
654    {
655       if (debug_>0)   System.out.println("   IOException PirateTunesClientThread: "+ e.getMessage());
656
657    }
658    if (debug_>2) System.out.println("\n   <EXITING PirateTunesClientThread: "+ me.getId());
659  }
660
661
662  public static Vector<String> getCommandList()
663  {
664    Vector<String> retVal = new Vector<String>();
665    String[] cmds = {
666                      "tune",
667                      "tunes",
668                      "tunesDir",
669                      "album",
670                      "artist",
671                      "playNum",
672                      "clearPlaylist",
673                      "next",
674                      "pause",
675                      "previous",
676                      "prev",
677                      "play",
678                      "stop",
679                      "add",
680                      "addDir",
681                      "artistAlbumsList",
682                      "getTitle",
683                      "getAlbumCoverURL",
684                      "getFilename",
685                      "getArtistName",
686                      "getAlbumName",
687                      "getSongName",
688                      "getAlbumTrackNum",
689                      "getCurrentPlaylistIndex",
690                      "getPlaylistSize",
691                      "getPlaylist",
692                      "getIndexedPlaylist",
693                      "getSongComments",
694                      "getSongDuration",
695                      "getSongTimePlaying",
696                      "getSongProgress",
697                      "getPlaylist",
698                      "isStopped",
699                      "isSongPlaying",
700                      "isSongPaused",
701                      "shufflePlay",
702                      "linearPlay",
703                      "getShuffling",
704                      "commandList"
705                    };
706    for(int i=0; i<cmds.length;i++) retVal.add(cmds[i]);
707    return retVal;
708  }
709
710
711  public static Vector<String> getCommandWithNoOptionsList()
712  {
713    Vector<String> retVal = new Vector<String>();
714    String[] cmds = {
715                      "clearPlaylist",
716                      "next",
717                      "pause",
718                      "previous",
719                      "prev",
720                      "play",
721                      "stop",
722                      "artistAlbumsList",
723                      "getTitle",
724                      "getAlbumCoverURL",
725                      "getFilename",
726                      "getArtistName",
727                      "getAlbumName",
728                      "getSongName",
729                      "getAlbumTrackNum",
730                      "getCurrentPlaylistIndex",
731                      "getPlaylistSize",
732                      "getPlaylist",
733                      "getIndexedPlaylist",
734                      "getSongComments",
735                      "getSongDuration",
736                      "getSongTimePlaying",
737                      "getSongProgress",
738                      "getPlaylist",
739                      "isStopped",
740                      "isSongPlaying",
741                      "isSongPaused",
742                      "shufflePlay",
743                      "linearPlay",
744                      "getShuffling",
745                      "commandList"
746                    };
747    for(int i=0; i<cmds.length;i++) retVal.add(cmds[i]);
748    return retVal;
749  }
750}