001/* 002 * $URL: svn://fred.webarts.bc.ca/open/trunk/projects/jOggPlayer/ca/bc/webarts/JOggPlayerListener.java $ 003 * $Revision: 1358 $ 004 * $Date: 2020-06-20 14:25:16 -0700 (Sat, 20 Jun 2020) $ 005 * $Author: tgutwin $ 006 */ 007/* 008 * TOM Gutwin's fork of... 009 * JOggPlayer -- pure Java Ogg Vorbis player 010 * into a nonGUI singleton class that functions like a Listener to 011 * take commands and play tunes from the playlist 012 * Written by: Tom Gutwin WebARTS Design 013 * Copyright (C) 2020 WebARTS Design, Burnaby Canada 014 * 015 * It is based on Java Vorbis Ogg Audio/Decoder/Player code from JCraft,Inc. 016 * Copyright (C) 2000 ymnk, JCraft,Inc. 017 * 018 * This program is free software; you can redistribute it and/or modify 019 * it under the terms of the GNU General Public License as published by 020 * the Free Software Foundation; either version 2 of the License, or 021 * (at your option) any later version. 022 * 023 * This program is distributed in the hope that it will be useful, 024 * but WITHOUT ANY WARRANTY; without even the implied warranty of 025 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 026 * GNU General Public License for more details. 027 * 028 * You should have received a copy of the GNU General Public License 029 * along with this program; if not, write to the Free Software 030 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 031 */ 032/* 033 * Original Java Vorbis Ogg Audio/Decoder/Player code Written by: 034 * 2000 ymnk<ymnk@jcraft.com> 035 * Copyright (C) 2000 ymnk, JCraft,Inc. 036 * http://www.jcraft.com 037 * 038 * Many thanks to 039 * Monty <monty@xiph.org> and 040 * The XIPHOPHORUS Company http://www.xiph.org/ . 041 * JOrbis has been based on their awesome works, Vorbis codec and 042 * JOrbisPlayer depends on JOrbis. 043 * 044 */ 045 046package ca.bc.webarts; 047 048import com.jcraft.jogg.*; 049 050import com.jcraft.jorbis.*; 051import java.applet.*; 052import java.awt.*; 053import java.awt.event.*; 054import java.io.*; 055import java.net.*; 056 057import java.util.*; 058 059import javax.sound.midi.*; 060import javax.sound.sampled.*; 061import javax.swing.*; 062 063import ca.bc.webarts.widgets.Util; 064 065 066/** 067 * A Singleton JOggPlayer that does NOT function from the commandline or gui; 068 * only as an intantiated class from another app such as a TCP PortListener. 069 * <br><br><b><u>Example Method in another class:</u></b><br> 070 * <pre> 071 * protected int runWithJOggPlayer(String[] cmdArgs) 072 * { 073 * int retVal = 1; 074 * JOggPlayerListener player_ = JOggPlayerListener.getInstance(); 075 * String piTunePath = ""; 076 * if(!"stop".equalsIgnoreCase(cmdArgs[0])) 077 * { 078 * piTunePath = "/mnt/nas/snd/ogg"+"/"+cmdArgs[1]; 079 * if (cmdArgs.length >1) 080 * { 081 * for (int i = 1; i < cmdArgs.length; i++) 082 * { 083 * piTunePath = piSndOggRootDir_+"/"+cmdArgs[i]; 084 * player_.addToPlaylist(piTunePath); 085 * } 086 * } 087 * player_.play_sound(); // this send the message to start the player thread and return here 088 * retVal = 0; 089 * } 090 * else // stop was called 091 * { 092 * // call stop 093 * player_.signalStopPlay(); 094 * } 095 * // because all the above calls send signals to JOggPlayerListener to execute in a separate Thread 096 * // they quickly return back here 097 * // so, we can do extra stuff here while we wait 098 * if(retVal==0) 099 * { 100 * System.out.println("\n waiting until song"+("tunes".equalsIgnoreCase(cmdArgs[0])?"s":"")+ 101 * " are done"); 102 * 103 * while(player_ != null && player_.isPlaying()) 104 * { 105 * ca.bc.webarts.widgets.Util.sleep(5*1000); 106 * System.out.print(player_.retrieveCurrentTunePlayTimeInMiliSeconds()/1000+ "("+ player_.retrieveTuneProgressRatio()+") "); 107 * } 108 * System.out.println("\nJOggPlayer is done."); 109 * } 110 * return retVal; 111 * }</pre> 112 * <br> 113 * <b>See a pre-built sample commandline app called {@link JOggPlayerCommandline JOggPlayerCommandline} that uses this class</b> 114 * <br> 115 * See https://dzone.com/articles/singleton-in-java for Singleton implementation style. 116 * 117 * @author tgutwin 118 */ 119public class JOggPlayerListener implements Runnable 120{ 121 122 /** Debug level. 0 is silent, 1 is error only; 2 is basic info, 3 is verbose, 4 is all **/ 123 int debug_ = 2; 124 125 /** 126 * The File Load Buffer multiplier - the num kbites to take . 127 */ 128 final static int BUFFER_MULTIPLE = 4; 129 130 /** The Play buffer size. */ 131 final static int BUFSIZE = BUFFER_MULTIPLE * 1024 * 3; 132 133 /** the size (bytes) to allocate for the pcm conversion buffer. */ 134 static int convsize_ = BUFSIZE * 2; 135 136 /** The pcm conversion buffer. */ 137 static byte[] convbuffer_ = new byte[convsize_]; 138 139 /** Description of the Field */ 140 private int RETRY = 3; 141 142 /** Description of the Field */ 143 int retry = RETRY; 144 145 /** The Ogg Vorbis stream of data. */ 146 InputStream oggVorbisBitStream_ = null; 147 148 /** The (optional) UDP port to retrieve the Vorvis data FROM. */ 149 int udp_port = -1; 150 /** Description of the Field */ 151 String udp_baddress = null; 152 153 /** Description of the Field */ 154 String playlistfile = "playlist"; 155 156 /** The JCraft JOgg SyncState. */ 157 SyncState oy; 158 /** The JCraft JOgg StreamState. */ 159 StreamState os; 160 /** Vorbis Ogg Data. */ 161 Page og; 162 /** Vorbis Ogg Data. */ 163 Packet op; 164 /** Vorbis Ogg Data. */ 165 Info vi; 166 /** The currently being read Vorbis Comment. */ 167 Comment vc; 168 /** Vorbis Ogg Data. */ 169 DspState vd; 170 /** Vorbis Ogg Data. */ 171 Block vb; 172 173 /** 174 * Holds the current tune Vorbis Comments. 175 */ 176 Vector<String> songComments_ = new <String>Vector(); 177 178 179 /** Description of the Field */ 180 byte[] buffer = null; 181 /** current bytes being worked on.*/ 182 int bytes = 0; 183 184 /** Description of the Field */ 185 int rate = 0; 186 /** Description of the Field */ 187 int channels = 0; 188 /** Description of the Field */ 189 int left_vol_scale = 100; 190 /** Description of the Field */ 191 int right_vol_scale = 100; 192 /** Description of the Field */ 193 SourceDataLine outputLine = null; 194 /** Description of the Field */ 195 String current_source = null; 196 197 int current_songDuration_ = 0; 198 199 /** Description of the Field */ 200 int frameSizeInBytes; 201 /** Description of the Field */ 202 int bufferLengthInBytes; 203 204 /** Description of the Field */ 205 boolean playonstartup = true; 206 207 boolean playing_ = false; 208 209 /** 210 * Signals the playing loop to jump to next tune in playlist. 211 */ 212 private boolean signalNextInPlaylist_ = false; 213 /** 214 * Signals the playing loop to jump to previous tune in playlist. 215 */ 216 private boolean signalPreviousInPlaylist_ = false; 217 /** 218 * Signals the playing loop to pause in a sleep loop until !loopPaused_. 219 */ 220 private boolean loopPaused_ = false; 221 /** 222 * Signals the playing loop to stop. 223 */ 224 private boolean loopStopped_ = false; 225 226 /** 227 * These variables are used to distinguish stopped, paused, playing states. 228 * We need them to control Thread. 229 */ 230 public static final int UNKNOWN = -1; 231 public static final int PLAYING = 0; 232 public static final int PAUSED = 1; 233 public static final int STOPPED = 2; 234 public static final int OPENED = 3; 235 public static final int SEEKING = 4; 236 private int m_status = UNKNOWN; 237 238 /** 239 * Description of the Field 240 */ 241 boolean timerRunning_ = false; 242 243 Date date = new Date(); 244 245 /** The bytes retrieved from current playing tune. It is used to calculate progress through the tune file. */ 246 int progressCount_ = 0; 247 248 public static String albumCoverURLBase_ = "https://fred.webarts.bc.ca:9443/tunes/tunes"; 249 250 /** 251 * The thread that watches the time the song has been playing. 252 * Handles the Timer display in its own Thread.<P> 253 * 254 * Why not use the Timer class in the JDK??? Because it is since JDK 1.3. 255 */ 256 class TimerThread extends Thread 257 { 258 int min = 0; 259 int sec = 0; 260 long pausedTime = 0l; 261 int pausedMin = 0; 262 int pausedSec = 0; 263 Date runningDate; 264 long runningTime = 0l; 265 int playTime = 0; 266 /** the current tune's length /duration in Seconds. **/ 267 int songDuration = 0; 268 long startPauseTime = 0l; 269 long lastPauseTime = 0l; 270 long newPauseTime = 0l; 271 long historyPauseTime = 0l; 272 int diffDate = 0; 273 String timeString_ = "00:00"; 274 275 276 /** the playtime in mSec. 277 * 278 * @return int the playing time in milli seconds 279 **/ 280 public int getPlayTime() 281 { 282 return playTime; 283 } 284 285 286 /** the length of the current tune in mSec. NOT Truly Implemented YET. 287 * 288 * @return int the length of the current tune in milli seconds 289 **/ 290 public int getSongDurationInMiliSeconds() 291 { 292 songDuration = ((int) (playTime / 1000)); //update it first 293 return songDuration; 294 } 295 296 297 /** The progress through the song ratio between 0 to 1000. 298 * 299 * @return int between 0 to 1000 300 **/ 301 public int getSongProgressRatio() 302 { 303 String item = (String) playlist_.get(currentPlaylistIndex_); 304 int currTuneFileLength = (int) (new File(item)).length(); 305 306 return progressCount_ / currTuneFileLength ; // * ((int) (playTime / 1000))/; 307 } 308 309 310 public void run() 311 { 312 date = new Date(); 313 timerRunning_ = true; 314 while (playing_ && timerRunning_) 315 { 316 ca.bc.webarts.widgets.Util.sleep(490); 317 runningDate = new Date(); 318 runningTime = runningDate.getTime(); 319 diffDate = (int) ((runningTime - date.getTime())); 320 if (getLoopPaused()) 321 { 322 pausedTime = runningTime - startPauseTime; 323 newPauseTime = runningTime - lastPauseTime; 324 historyPauseTime += newPauseTime; 325 pausedMin = (int) historyPauseTime / 60000; 326 pausedSec = (int) (historyPauseTime / 1000 - pausedMin * 60); 327 328 // Flash Tne Paused Message 329 if (((int) (historyPauseTime / 1000)) % 2 == 0) 330 { 331 //timeLabelValue.setText(timeString_ + " (PAUSED)"); 332 } 333 else 334 { 335 //timeLabelValue.setText(timeString_); 336 } 337 lastPauseTime = runningTime; 338 339 } 340 else 341 { 342 playTime = diffDate - (int)historyPauseTime; 343 min = (int) (playTime / 60000); 344 sec = ((int) (playTime / 1000)) - min * 60; 345 //songDuration = songProgress.getMaximum()*((int) (playTime / 1000))/progressCount_; 346 songDuration = ((int) (playTime / 1000)); 347 timeString_ = (min < 9 ? "0" : "") + min + ":" + (sec < 10 ? "0" : "") + sec; 348 //timeLabelValue.setText(timeString_ + " (" + progressCount_ / 1000 + "kB)"); 349 startPauseTime = runningTime; 350 lastPauseTime = runningTime; 351 } 352 } 353 } 354 }; 355 /** Timer Thread. Use {@link #startTimer() startTimer} method to init and start the timer. **/ 356 TimerThread timeWatcherThread_ = null; 357 358 /** Description of the Field */ 359 public Vector <String> playlist_ = new Vector<String>(); 360 int currentPlaylistIndex_ = -1; 361 362 private boolean shuffling_ = false; 363 364 /** Description of the Field */ 365 Thread playerThread_ = null; 366 367 /** Singleton instance. **/ 368 private static JOggPlayerListener INSTANCE = null; 369 370 371 /** Private constructor for Singleton instance. **/ 372 private JOggPlayerListener() {} 373 374 375 /** Singleton instance getter. 376 * @return the singelton JOggPlayerListener object 377 **/ 378 public static JOggPlayerListener getInstance() 379 { 380 if (INSTANCE == null) 381 { 382 synchronized (JOggPlayerListener.class) 383 { 384 if (INSTANCE == null) { System.out.println("** JOggPlayerListener** NEW Instance Created"); INSTANCE = new JOggPlayerListener();} 385 } 386 } 387 return INSTANCE; 388 } 389 390 391 /** Description of the Method */ 392 public void start() 393 { 394 play_sound(); 395 } 396 397 398 /** 399 * Reads from the oggVorbisBitStream_ a specified number of Bytes(BUFSIZE) worth 400 * sarting at index and puts them in the specified buffer[]. 401 * 402 * @param buffer the byteBuffer holding the read in data 403 * @param index where to start reading from the string 404 * @param BUFSIZE the max number of bytes to read 405 * @return the number of bytes read or -1 if error. 406 */ 407 private int readFromStream(byte[] buffer, int index, int BUFSIZE) 408 { 409 int bytes = 0; 410 try 411 { 412 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 413 progressCount_ += bytes; 414 } 415 catch (Exception e) 416 { 417 System.err.println(e.getMessage()); 418 System.err.println("Cannot Read Selected Song - index=" + index); 419 bytes = -1; 420 } 421 return bytes; 422 } 423 424 425 /** 426 * Helper method to encapsulate the starting of the timeWatcherRunnable_.* 427 */ 428 private void startTimer() 429 { 430 if (timeWatcherThread_ == null) 431 { 432 timeWatcherThread_ = new TimerThread(); 433 timeWatcherThread_.start(); 434 } 435 else if (!timeWatcherThread_.isAlive()) 436 { 437 timerRunning_ = false; 438 timeWatcherThread_ = new TimerThread(); 439 timeWatcherThread_.start(); 440 } 441 else if (!timeWatcherThread_.isAlive()) 442 { 443 timeWatcherThread_ = new TimerThread(); 444 timeWatcherThread_.start(); 445 } 446 } 447 448 449 private void reStartTimer() 450 { 451 timeWatcherThread_ = null; 452 startTimer(); 453 } 454 455 456 public int retrieveCurrentTunePlayTimeInMiliSeconds() 457 { 458 int retVal = -1; 459 if(timerRunning_) retVal = timeWatcherThread_.getPlayTime(); 460 return retVal; 461 } 462 463 464 public int retrieveTuneProgressRatio() 465 { 466 int retVal = -1; 467 if(timerRunning_) retVal = timeWatcherThread_.getSongProgressRatio(); 468 return retVal; 469 } 470 471 472 public int retrieveSongDurationInMiliSeconds() 473 { 474 int retVal = current_songDuration_; 475 476 //if(timerRunning_) retVal = timeWatcherThread_.getSongDurationInMiliSeconds(); // the timer should not be the source for this 477 return retVal; 478 } 479 480 481 public synchronized int getStatus() { return m_status; } 482 public synchronized boolean isPaused() { return (m_status==PAUSED); } 483 public synchronized boolean isPlaying() { return (m_status==PLAYING); } 484 public synchronized boolean isStopped() { return (m_status==STOPPED); } 485 486 487 /** 488 * Set Method for class field 'songComments_'. 489 * 490 * @param songComments is the value to set this class field to. 491 * 492 **/ 493 public void setSongComments(Vector<String> songComments) 494 { 495 this.songComments_ = songComments; 496 } // setSongComments Method 497 498 499 /** 500 * Get Method for class field 'songComments_'. 501 * 502 * @return Vector<String> - The value the class field 'songComments_'. 503 * 504 **/ 505 public Vector<String> getSongComments() 506 { 507 return songComments_; 508 } // getSongComments Method 509 510 511 /** 512 * The Runnable to do the actual playing of the song. All the rest of this class 513 * is fluff to get to this point [:)] . This code was developed by the jCraft 514 * group. 515 * 516 */ 517 public void run() 518 { 519 SyncState oggSyncState_ = null; 520 Page oggPage_ = og; 521 Packet oggPacket_ = op; 522 StreamState oggStreamState_ = os; 523 Info vorbisInfo = vi; 524 Comment vorbisComment = vc; 525 DspState vorbisDspState = vd; 526 Block vorbisBlock = vb; 527 528 retry = RETRY; 529 boolean stopSignal = false; 530 boolean loopTrace = false; 531 532 System.out.println(" >> >>> run()>"); 533 534 Thread me = Thread.currentThread(); 535 me.setPriority(Thread.MAX_PRIORITY); 536 537 //currentPlaylistIndex_ = 0; 538 if(playlist_.size()>0) 539 { 540 String item = (String) playlist_.get(currentPlaylistIndex_); 541 oggVorbisBitStream_ = selectSource(item); // turns a named item into its InputStream 542 543 progressCount_ = 0; 544 int index = 0; 545 boolean streamStillHasData = (oggVorbisBitStream_ != null); //true; 546 if (streamStillHasData) 547 try 548 { 549 while (!stopSignal || 550 ( playing_ && (streamStillHasData || (currentPlaylistIndex_ < playlist_.size())) ) 551 ) 552 { 553 clearPlaylistSignals(); 554 init_jorbis(); // gets all the oy, og ...streams seup 555 556 oggSyncState_ = oy; 557 oggPage_ = og; 558 oggPacket_ = op; 559 oggStreamState_ = os; 560 vorbisInfo = vi; 561 vorbisComment = vc; 562 vorbisDspState = vd; 563 vorbisBlock = vb; 564 565 /* Get the next Song setup */ 566 item = (String) playlist_.get(currentPlaylistIndex_); 567 /* ************************************************ */ 568 569 System.out.print("\n >> JOggPlayerListener Thread starting to play item"); 570 System.out.println("["+currentPlaylistIndex_+"/"+(playlist_.size()-1)+"] "+item); 571 572 oggVorbisBitStream_ = selectSource(item); // turns a named item into its InputStream 573 int eos = 0; 574 //System.out.println(" run() Init file..."); 575 576 index = oggSyncState_.buffer(BUFSIZE); 577 buffer = oggSyncState_.data; 578 579 bytes = readFromStream(buffer, index, BUFSIZE); 580 if (bytes == -1) 581 { 582 streamStillHasData = false; 583 System.out.println(" >> ERROR Cannot get any data from selected Ogg bitstream."); 584 break; 585 } 586 oggSyncState_.wrote(bytes); 587 if (oggSyncState_.pageout(oggPage_) != 1) 588 { 589 streamStillHasData = false; 590 if (bytes < BUFSIZE) 591 { 592 System.out.println(" >> ERROR No more data"); 593 break; 594 } 595 System.out.println(" >> ERROR Input does not appear to be an Ogg bitstream."); 596 break; 597 } 598 oggStreamState_.init(oggPage_.serialno()); 599 vorbisInfo.init(); 600 vorbisComment.init(); 601 if (oggStreamState_.pagein(oggPage_) < 0) 602 { 603 // error; stream version mismatch perhaps 604 System.out.println(" >> ERROR reading first page of Ogg bitstream data."); 605 break; 606 } 607 int tmpInt = oggStreamState_.packetout(oggPacket_); 608 if (tmpInt != 1) 609 { 610 // no page? must not be vorbis 611 System.out.println(" >> ERROR reading initial header packet. ("+tmpInt + ")"); 612 break; 613 } 614 tmpInt = vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_); 615 if (tmpInt < 0) 616 { 617 // error case; not a vorbis header 618 System.out.println(" >> ERROR This Ogg bitstream does not contain Vorbis audio data. ("+tmpInt + ")"); 619 break; 620 } 621 System.out.println(" >> Valid Ogg bitstream."); 622 int i = 0; 623 while (i < 2) 624 { 625 while (i < 2) 626 { 627 int result = oggSyncState_.pageout(oggPage_); 628 if (result == 0) 629 { 630 break; 631 } // Need more data 632 if (result == 1) 633 { 634 oggStreamState_.pagein(oggPage_); 635 while (i < 2) 636 { 637 result = oggStreamState_.packetout(oggPacket_); 638 if (result == 0) 639 { 640 break; 641 } 642 if (result == -1) 643 { 644 System.out.println(" >> ERROR Corrupt secondary header. Exiting."); 645 return; 646 } 647 vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_); 648 i++; 649 } 650 } 651 } 652 index = oggSyncState_.buffer(BUFSIZE); 653 buffer = oggSyncState_.data; 654 bytes = readFromStream(buffer, index, BUFSIZE); 655 if (bytes == -1) 656 { 657 break; 658 } 659 if (bytes == 0 && i < 2) 660 { 661 System.out.println(" >> ERROR End of file before finding all Vorbis headers!"); 662 return; 663 } 664 oggSyncState_.wrote(bytes); 665 } 666 667 /* So Far So good on the stream, continue with */ 668 /* Vorbis user_comments */ 669 byte[][] ptr = vorbisComment.user_comments; 670 String currComment = ""; 671 songComments_.clear(); 672 for (int j = 0; j < ptr.length; j++) 673 { 674 if (ptr[j] == null) 675 { 676 break; 677 } 678 currComment = (new String(ptr[j], 0, ptr[j].length - 1)).trim(); 679 songComments_.add(currComment); 680 681 //System.out.println("Comment: " + currComment); 682 } 683 currComment = "Bitstream: " + vorbisInfo.channels + " channel," + vorbisInfo.rate + "Hz"; 684 //currComment = "Bitstream: " + playList.getSongChannels(sel) + " channel," + playList.getSongBitrate(sel) + "Hz"; 685 songComments_.add(currComment); 686 //System.out.println(currComment); 687 currComment = "Encoded by: " + new String(vorbisComment.vendor, 0, 688 vorbisComment.vendor.length - 1); 689 songComments_.add(currComment); 690 691 convsize_ = BUFSIZE / vorbisInfo.channels; 692 vorbisDspState.synthesis_init(vorbisInfo); 693 vorbisBlock.init(vorbisDspState); 694 double[][][] _pcm = new double[1][][]; 695 float[][][] _pcmf = new float[1][][]; 696 int[] _index = new int[vorbisInfo.channels]; 697 getOutputLine(vorbisInfo.channels, vorbisInfo.rate); 698 reStartTimer(); 699 700 System.out.print(" run() Decoding "); 701 702 while (eos == 0) 703 { 704 if(loopTrace) System.out.print(" *"); 705 while (eos == 0) 706 { 707 if(loopTrace) System.out.print(" **"); 708 if (!playing_ || playerThread_ == null) 709 { 710 System.err.println("bye."); 711 timerRunning_ = false; 712 try 713 { 714 //outputLine.drain(); 715 //outputLine.stop(); 716 //outputLine.close(); 717 oggVorbisBitStream_.close(); 718 } 719 catch (Exception ee) 720 { 721 } 722 return; 723 } 724 int result = oggSyncState_.pageout(oggPage_); 725 if (result == 0) 726 { 727 //System.err.println("Puked on oggSyncState_.pageout(oggPage_)"); 728 break; 729 } // need more data 730 if (result == -1) 731 { // missing or corrupt data at this page position 732 System.err.println(" >> Corrupt or missing data in bitstream; " + 733 "continuing..."); 734 } 735 else 736 { 737 oggStreamState_.pagein(oggPage_); 738 739 /* This is the endless Play song loop */ 740 /* ---------------------------------- */ 741 result = 1; 742 while (playing_ && result!=0) 743 { 744 result = oggStreamState_.packetout(oggPacket_); 745 if(loopTrace) System.out.print(" ***"+result); 746 //if (result == 0) 747 //{ 748 // break; 749 //} // need more data 750 if (result <1 ) //== -1) 751 { // missing or corrupt data at this page position 752 // no reason to complain; already complained above 753 } 754 else // only if there is data 755 { 756 if(loopTrace) System.out.print("!!"); 757 // we have a packet. Decode it 758 int samples; 759 if (vorbisBlock.synthesis(oggPacket_) == 0) 760 { // test for success! 761 if(loopTrace) System.out.print("!"); 762 vorbisDspState.synthesis_blockin(vorbisBlock); 763 } 764 765 /* ****************************************** */ 766 /* This is the Data Read and convert Block */ 767 /* ****************************************** */ 768 // start sampling the data into _pcmf 769 samples = vorbisDspState.synthesis_pcmout(_pcmf, _index); 770 if(loopTrace) System.out.print("["+samples+"]"); 771 while (samples > 0) 772 { //samples holds the size of data in recent read 773 774 if(loopTrace) System.out.print("."); 775 776 //double[][] pcm = _pcm[0]; // not used DELETE ME 777 float[][] pcmf = _pcmf[0]; 778 boolean clipflag = false; 779 int bout = (samples < convsize_ ? samples : convsize_); 780 double fVal = 0.0; 781 // convert doubles to 16 bit signed ints (host order) and interleave 782 for (i = 0; i < vorbisInfo.channels; i++) 783 { 784 int pointer = i * 2; 785 //int ptr=i; 786 int mono = _index[i]; 787 for (int j = 0; j < bout; j++) 788 { 789 fVal = (float) pcmf[i][mono + j] * 32767.; 790 /* 791 * volume Adjust 792 */ 793 //fVal = fVal * currentVolumeMultiplier_; 794 int val = (int) (fVal); 795 if (val > 32767) 796 { 797 val = 32767; 798 clipflag = true; 799 } 800 if (val < -32768) 801 { 802 val = -32768; 803 clipflag = true; 804 } 805 if (val < 0) 806 { 807 val = val | 0x8000; 808 } 809 convbuffer_[pointer] = (byte) (val); 810 convbuffer_[pointer + 1] = (byte) (val >>> 8); 811 pointer += 2 * (vorbisInfo.channels); 812 } 813 } 814 815 // transfer the converted bytes to the output line 816 outputLine.write(convbuffer_, 0, 2 * vorbisInfo.channels * bout); 817 vorbisDspState.synthesis_read(bout); 818 819 // read next sample and go back 820 samples = vorbisDspState.synthesis_pcmout(_pcmf, _index); 821 } // inner decoding loop 822 823 /* loop control lives here */ 824 /* *********************** */ 825 if(getLoopStopped()) 826 { 827 System.out.println("\n >> ** STOP Signal "); 828 stopSignal = true; 829 playing_ = false; 830 m_status = STOPPED; 831 eos = 1; 832 result=0; 833 break; 834 } 835 if(getSignalPreviousInPlaylist()) 836 { 837 //do something 838 System.out.print("\n >> ** Previous Signal from: "+currentPlaylistIndex_); 839 currentPlaylistIndex_--; 840 if(currentPlaylistIndex_ < 0) currentPlaylistIndex_=playlist_.size()-1; 841 System.out.println(" to: "+currentPlaylistIndex_); 842 eos = 1; 843 result=0; 844 currentPlaylistIndex_--; 845 } 846 if(getSignalNextInPlaylist()) 847 { 848 //do something 849 System.out.print("\n >> ** NEXT Signal from: "+currentPlaylistIndex_); 850 if(!getShuffling()) 851 { 852 currentPlaylistIndex_++; 853 if(currentPlaylistIndex_ >= playlist_.size()) currentPlaylistIndex_=0; 854 System.out.println(" to: "+currentPlaylistIndex_); 855 } 856 else 857 { 858 currentPlaylistIndex_ = (int) (Math.random() * playlist_.size()); 859 System.out.println(" to: "+currentPlaylistIndex_); 860 } 861 currentPlaylistIndex_--; 862 eos = 1; 863 result=0; 864 } 865 // Pause the stream 866 boolean wasPaused = false; 867 while (getLoopPaused()) 868 { 869 pausePlayback(); 870 ca.bc.webarts.widgets.Util.sleep(250); 871 wasPaused = true; 872 } 873 if(wasPaused) resumePlayback(); 874 875 } //valid packet processed 876 877 } //// Still more data until playing_ stops ORresult =0 878 //System.out.print("."); 879 880 if (stopSignal || oggPage_.eos() != 0) 881 { 882 eos = 1; 883 } 884 }// Endless Play Loop until playing_ stops us OR the ogg stream was empty 885 } 886 887 //System.out.println(" * IN loop1 getting more buffer data"); 888 if (!stopSignal && eos == 0) 889 { 890 index = oggSyncState_.buffer(BUFSIZE); 891 buffer = oggSyncState_.data; 892 bytes = readFromStream(buffer, index, BUFSIZE); 893 if (bytes == -1) 894 { 895 System.out.println("\n Current tune Ogg Stream empty."); 896 streamStillHasData = false; 897 eos = 1; 898 //break; 899 } 900 else 901 { 902 oggSyncState_.wrote(bytes); 903 if (bytes == 0) 904 { 905 System.out.println("No data left in Ogg Stream."); 906 eos = 1; 907 } 908 } 909 } 910 } 911 System.out.print(" << run() DONE Decoding, cleaning up "); 912 if (oggStreamState_!=null) oggStreamState_.clear(); 913 if (vorbisBlock!=null)vorbisBlock.clear(); 914 if (vorbisDspState!=null)vorbisDspState.clear(); 915 if (vorbisInfo!=null)vorbisInfo.clear(); 916 System.out.println("\n >> <<< Done Song >>>"); 917 918 // loop back 919 if(!getLoopStopped() ) 920 { 921 // Shuffle ??? NEXT song 922 if(!getShuffling()) 923 { 924 if(++currentPlaylistIndex_ >= playlist_.size()) currentPlaylistIndex_=0; 925 //System.out.println(" to: "+currentPlaylistIndex_); 926 } 927 else 928 { 929 currentPlaylistIndex_ = (int) (Math.random() * playlist_.size()); 930 //System.out.println(" to: "+currentPlaylistIndex_); 931 } 932 } 933 else if(getSignalPreviousInPlaylist() || getSignalNextInPlaylist()) eos = 0; 934 935 System.out.println(" >> Do we go back for another tune???\n"+ 936 " playing_="+playing_+ 937 "\n currentPlaylistIndex_="+currentPlaylistIndex_+" / "+(playlist_.size()-1)+ 938 "\n shuffling="+getShuffling()+ 939 "\n stopSignal="+stopSignal+ 940 "\n streamStillHasData="+streamStillHasData+ 941 " (currentPlaylistIndex_<playlist_.size())="+(currentPlaylistIndex_<playlist_.size())); 942 } // main song loop 943 System.out.println(" << NOPE - DONE Looping\n"); 944 945 if (oggSyncState_!=null) oggSyncState_.clear(); 946 System.out.println(" << Done Playlist."); 947 timerRunning_ = false; 948 stop_sound(); 949 try 950 { 951 if (oggVorbisBitStream_ != null) oggVorbisBitStream_.close(); 952 playing_ = false; //playerThread_ = null; 953 } 954 catch (Exception e) 955 { 956 } 957 } 958 catch (Exception ex) 959 { 960 //System.out.println("Ogg Stream Exception. "+ex.getMessage()); 961 ex.printStackTrace(); 962 System.out.println("Ogg Stream Exception. "+ex.getMessage()); 963 } 964 965 } 966 else 967 System.out.println(" No songs in playlist."); 968 969 stop(); 970 stopSignal = false; 971 clearStopSignal(); 972 System.out.println(" << EXITING JOggPlayerListener Thread: "+ me.getId()); 973 } 974 975 976 /** 977 * Threadsafe signal the current play to STOP. 978 * 979 **/ 980 public synchronized void signalStopPlay() 981 { 982 this.loopStopped_ = true; 983 } // signalStopPlay Method 984 985 986 /** 987 * Threadsafe Sets loopStopped_backto false after successfull stop. 988 * 989 **/ 990 public synchronized void clearStopSignal() 991 { 992 this.loopStopped_ = false; 993 } // signalStopPlay Method 994 995 996 public synchronized Vector<String> getPlaylistArtistAlbumSongnames(){return getIndexedPlaylistArtistAlbumSongnames(false);} 997 public synchronized Vector<String> getIndexedPlaylistArtistAlbumSongnames(boolean addIndex) 998 { 999 if (debug_>1) System.out.println(" JOggPlayerListener: getIndexedPlaylistArtistAlbumSongnames(addIndex="+addIndex+")"); 1000 Vector<String> retVal = new Vector<String>(); 1001 for (int i=0; i< playlist_.size(); i++) 1002 { 1003 retVal.add((addIndex?""+i+") ":"")+getArtistName(i)+" / "+getAlbumName(i)+" / " +getTitle(i)); 1004 } 1005 if (debug_>1) System.out.println(" : IndexedPlaylist="); 1006 int t = 0; 1007 if (debug_>1) for(String sss : retVal) System.out.println(" "+(t++) +") "+sss); 1008 return retVal ; 1009 } // getSignalNextInPlaylist Method 1010 1011 1012 /** Threadsafe Get Method for class var currentPlaylistIndex_. 1013 * 1014 * @return int currentPlaylistIndex_ 1015 **/ 1016 public synchronized int getCurrentPlaylistIndex() 1017 { 1018 return this.currentPlaylistIndex_ ; 1019 } // getSignalNextInPlaylist Method 1020 1021 1022 /** Threadsafe Get Method for class var currentPlaylistIndex_. 1023 * 1024 * @return int currentPlaylistIndex_ 1025 **/ 1026 public synchronized int getPlaylistSize() 1027 { 1028 return this.playlist_.size() ; 1029 } // getSignalNextInPlaylist Method 1030 1031 1032 /** 1033 * signal the current play to jump to next in playlist. 1034 * 1035 **/ 1036 public synchronized void signalNextInPlaylist() 1037 { 1038 this.signalNextInPlaylist_ = true; 1039 } // signalNextInPlaylist Method 1040 1041 1042 /** Threadsafe Get Method for class var signalNextInPlaylist_. 1043 * 1044 * @return boolean signalNextInPlaylist_ 1045 **/ 1046 public synchronized boolean getSignalNextInPlaylist() 1047 { 1048 return this.signalNextInPlaylist_ ; 1049 } // getSignalNextInPlaylist Method 1050 1051 1052 /** 1053 * Threadsafe signal the current play to jump to previous in playlist. 1054 * 1055 **/ 1056 public synchronized void signalPreviousInPlaylist() 1057 { 1058 this.signalPreviousInPlaylist_ = true; 1059 } // signalPreviousInPlaylist Method 1060 1061 1062 /** Threadsafe Get Method for class var signalPreviousInPlaylist_. 1063 * 1064 * @return boolean signalPreviousInPlaylist_ 1065 **/ 1066 public synchronized boolean getSignalPreviousInPlaylist() 1067 { 1068 return this.signalPreviousInPlaylist_ ; 1069 } // getSignalPreviousInPlaylist Method 1070 1071 1072 /** 1073 * Set Method for class field 'shuffling_'. 1074 * 1075 * @param shuffling is the value to set this class field to. 1076 * 1077 **/ 1078 public synchronized void setShuffling(boolean shuffling) 1079 { 1080 this.shuffling_ = shuffling; 1081 } // setShuffling Method 1082 1083 1084 /** 1085 * Get Method for class field 'shuffling_'. 1086 * 1087 * @return boolean - The value the class field 'shuffling_'. 1088 * 1089 **/ 1090 public synchronized boolean getShuffling() 1091 { 1092 return this.shuffling_; 1093 } // getShuffling Method 1094 1095 1096 /** 1097 * Threadsafe Clears ALL thread signals for the playlist playing. 1098 * 1099 **/ 1100 public synchronized void clearPlaylistSignals() 1101 { 1102 this.signalNextInPlaylist_ = false; 1103 this.signalPreviousInPlaylist_ = false; 1104 } protected void togglePause() 1105 { 1106 if (m_status == PLAYING) pausePlayback(); 1107 else if (m_status == PAUSED) resumePlayback(); 1108 } 1109 1110 1111 /** 1112 * Pauses the playback.<br> 1113 * 1114 * Player Status = PAUSED. 1115 */ 1116 protected void pausePlayback() 1117 { 1118 if (outputLine != null) 1119 { 1120 if (m_status == PLAYING) 1121 { 1122 outputLine.drain(); //flush(); 1123 outputLine.stop(); 1124 m_status = PAUSED; 1125 //log.info("pausePlayback() completed"); 1126 //notifyEvent(BasicPlayerEvent.PAUSED, getEncodedStreamPosition(), -1, null); 1127 } 1128 } 1129 } 1130 1131 /** 1132 * Resumes the playback.<br> 1133 * 1134 * Player Status = PLAYING. 1135 */ 1136 protected void resumePlayback() 1137 { 1138 if (outputLine != null) 1139 { 1140 if (m_status == PAUSED) 1141 { 1142 outputLine.start(); 1143 m_status = PLAYING; 1144 //log.info("resumePlayback() completed"); 1145 //notifyEvent(BasicPlayerEvent.RESUMED, getEncodedStreamPosition(), -1, null); 1146 } 1147 } 1148 } 1149 1150 1151 /** Threadsafe Send a signal to toggle the paused state of the loop playing. **/ 1152 public synchronized void signalLoopPaused() 1153 { 1154 setLoopPaused(!getLoopPaused()); 1155 } 1156 1157 /** 1158 * Threadsafe Set Method for class field 'loopPaused_'. 1159 * 1160 * @param loopPaused is the value to set this class field to. 1161 * 1162 **/ 1163 public synchronized void setLoopPaused(boolean loopPaused) 1164 { 1165 this.loopPaused_ = loopPaused; 1166 } // setLoopPaused Method 1167 1168 1169 /** 1170 * Threadsafe Get Method for class field 'loopPaused_'. 1171 * 1172 * @return boolean - The value the class field 'loopPaused_'. 1173 * 1174 **/ 1175 public synchronized boolean getLoopPaused() 1176 { 1177 return loopPaused_; 1178 } // getLoopPaused Method 1179 1180 1181 /** Threadsafe Get method for class var loopStopped_. 1182 * @return boolean loopStopped_ 1183 **/ 1184 public synchronized boolean getLoopStopped() 1185 { 1186 return loopStopped_; 1187 } // getLoopPaused Method 1188 1189 1190 /** 1191 * Gets the Filename of the current item in the playlist. 1192 * 1193 * @return The current tune title value 1194 */ 1195 public String getFilename() 1196 { 1197 return getFilename(currentPlaylistIndex_); 1198 } 1199 1200 1201 /** 1202 * Gets the Filename of the specified item in the playlist. 1203 * 1204 * @param playlistItem the item to get name for 1205 * @return The current tune title value 1206 */ 1207 public String getFilename(int playListIndex) 1208 { 1209 String retVal = ""; 1210 if(playListIndex>-1) retVal = (String) playlist_.get(playListIndex); 1211 return retVal; 1212 } 1213 1214 1215 /** 1216 * Gets the title of the current item in the playlist. It is everything after the last '/' in the filename. 1217 * 1218 * @return String The current tune title value 1219 */ 1220 public String getTitle() 1221 { 1222 return getTitle(currentPlaylistIndex_); 1223 } 1224 1225 1226 /** 1227 * Gets the title of the specified item in the playlist. It is everything after the last '/' in the filename. 1228 * 1229 * @param playlistItem the item to get name for 1230 * @return String The current tune title value 1231 */ 1232 public String getTitle(int playListIndex) 1233 { 1234 String retVal = ""; 1235 if(playListIndex>-1) 1236 try { 1237 String f = getFilename(playListIndex); 1238 retVal = f.substring(f.lastIndexOf(ca.bc.webarts.widgets.Util.SYSTEM_FILE_SEPERATOR)+1).trim().replace("&","&"); 1239 } catch(Exception ex) { /* return empty retVal */ ex.printStackTrace();} 1240 return retVal; 1241 } 1242 1243 1244 public String getAlbumCoverURL() 1245 { 1246 return getAlbumCoverURL(currentPlaylistIndex_); 1247 } 1248 /** 1249 * Gets the Album Cover URL of the current item in the playlist. 1250 * 1251 * @return String The URL 1252 */ 1253 public String getAlbumCoverURL(int playListIndex) 1254 { 1255 String retVal = ""; 1256 String t = ""; 1257 String aName = ""; 1258 String alName = ""; 1259 if(playListIndex>-1) 1260 { 1261 t = getTitle(playListIndex); 1262 try 1263 { 1264 int endIndex = t.indexOf("_"); 1265 if(endIndex<0) endIndex = t.indexOf("-")-2; 1266 aName = t.substring(0,endIndex); 1267 } 1268 catch(Exception ex) { /* return empty retVal */ ex.printStackTrace();System.out.println(" playlist["+playListIndex+"] title="+t); } 1269 } 1270 if(playListIndex>-1) 1271 { 1272 t = getFilename(playListIndex); 1273 try 1274 { 1275 String tt = t.substring(0,t.lastIndexOf(ca.bc.webarts.widgets.Util.SYSTEM_FILE_SEPERATOR)); 1276 alName = tt.substring(tt.lastIndexOf(ca.bc.webarts.widgets.Util.SYSTEM_FILE_SEPERATOR)+1); 1277 retVal = albumCoverURLBase_ 1278 +"/"+aName.replace("&","&") 1279 +"/"+alName.replace("&","&") 1280 +"/cover.jpg"; 1281 1282 } 1283 catch(Exception ex) { /* return empty retVal */ ex.printStackTrace(); System.out.println(" playlist["+playListIndex+"] filename="+t); } 1284 } 1285 1286 return retVal; 1287 } 1288 1289 1290 /** 1291 * Gets the Artist name of the current item in the playlist. 1292 * 1293 * @return String The Artist name 1294 */ 1295 public String getArtistName() 1296 { 1297 return getArtistName(currentPlaylistIndex_); 1298 } 1299 1300 1301 /** 1302 * Gets the Artist name of the passed in playListIndex in the playlist. 1303 * 1304 * @return String The title value 1305 */ 1306 public String getArtistName(int playListIndex) 1307 { 1308 return getArtistName(playListIndex, true); 1309 } 1310 1311 1312 /** 1313 * Gets the Artist name of the passed in playListIndex in the playlist. 1314 * 1315 * @return String The title value 1316 */ 1317 public String getArtistName(int playListIndex, boolean capsToSpaces) 1318 { 1319 String retVal = ""; 1320 String t = ""; 1321 if(playListIndex>-1) 1322 { 1323 t = getTitle(playListIndex); 1324 try 1325 { 1326 int endIndex = t.indexOf("_"); 1327 if(endIndex<0) endIndex = t.indexOf("-")-2; 1328 retVal = Util.tokenReplace(t.substring(0,endIndex),"&","&"); 1329 if(capsToSpaces) 1330 retVal = ca.bc.webarts.widgets.Util.capsToSpacesInString( retVal); 1331 1332 /* handle some special cases */ 1333 if(retVal.equals("I N X S")) retVal = "INXS"; 1334 else if(retVal.equals("Inxs")) retVal = "INXS"; 1335 else if(retVal.equals("A C D C")) retVal = "ACDC"; 1336 else if(retVal.equals("Acdc")) retVal = "ACDC"; 1337 } 1338 catch(Exception ex) { /* return empty retVal */ ex.printStackTrace();System.out.println(" playlist["+playListIndex+"] title="+t); } 1339 } 1340 1341 return retVal; 1342 } 1343 1344 1345 /** 1346 * Gets the Song name of the current item in the playlist. 1347 * 1348 * @return String The current tune Song name 1349 */ 1350 public String getSongName() 1351 { 1352 return getSongName(currentPlaylistIndex_); 1353 } 1354 1355 1356 /** 1357 * Gets the Song name of the passed in playListIndex in the playlist. 1358 * 1359 * @return String The current tune Song name 1360 */ 1361 public String getSongName(int playListIndex) 1362 { 1363 String retVal = ""; 1364 String t = ""; 1365 if(playListIndex>-1) 1366 { 1367 t = getTitle(playListIndex); 1368 try 1369 { 1370 String number = "00"; 1371 String cdNumber = "01"; 1372 boolean multiCD = false; 1373 int numSize = 2; 1374 if(t.indexOf("_")>0) 1375 number = t.substring(t.indexOf("_")+1, t.indexOf("-", t.indexOf("_")+1)); 1376 else if(t.indexOf("-")>0) 1377 number = t.substring(t.indexOf("-")-2, t.indexOf("-")); 1378 if(number.length()>2) 1379 { 1380 // it includes a disc number 1381 multiCD = true; 1382 numSize = 4; 1383 cdNumber = Util.left(number,2); 1384 number = Util.right(number,2); 1385 } 1386 1387 1388 String art = "";; 1389 if(t.indexOf("-")>0) 1390 art = t.substring(0,t.indexOf("-")); 1391 if(art.indexOf("_")>0) 1392 { 1393 art = art.substring(0,t.indexOf("_")); 1394 } 1395 else 1396 { 1397 art = art.substring(0,art.length()-numSize-2); 1398 } 1399 //artistName_ = art; 1400 1401 int endIndex = t.indexOf("_"); 1402 if(endIndex<0) endIndex = t.indexOf("-")-numSize; 1403 retVal = ca.bc.webarts.widgets.Util.capsToSpacesInString(t.substring(endIndex+numSize+2, t.lastIndexOf("."))); 1404 } 1405 catch(Exception ex) { /* return empty retVal */ ex.printStackTrace();System.out.println(" playlist["+playListIndex+"] title="+t); } 1406 } 1407 1408 return retVal; 1409 } 1410 1411 1412 /** 1413 * Gets the Album Name of the passed in playlistItem in the playlist. 1414 * 1415 * @return String The Album Name of current tune 1416 */ 1417 public String getAlbumName() 1418 { 1419 return getAlbumName(currentPlaylistIndex_); 1420 } 1421 1422 1423 /** 1424 * Gets the Album Name of the passed in playListIndex in the playlist. 1425 * 1426 * @return String The Album Name of current tune 1427 */ 1428 public String getAlbumName(int playListIndex) 1429 { 1430 return getAlbumName(playListIndex, true); 1431 } 1432 1433 1434 /** 1435 * Gets the Album Name of the passed in playListIndex in the playlist. 1436 * 1437 * @return String The Album Name of current tune 1438 */ 1439 public String getAlbumName(int playListIndex, boolean capsToSpaces) 1440 { 1441 String retVal = ""; 1442 String t = ""; 1443 if(playListIndex>-1) 1444 { 1445 t = getFilename(playListIndex); 1446 try 1447 { 1448 String tt = t.substring(0,t.lastIndexOf(ca.bc.webarts.widgets.Util.SYSTEM_FILE_SEPERATOR)); 1449 retVal = tt.substring(tt.lastIndexOf(ca.bc.webarts.widgets.Util.SYSTEM_FILE_SEPERATOR)+1); 1450 if(capsToSpaces) 1451 retVal = ca.bc.webarts.widgets.Util.capsToSpacesInString(retVal); 1452 } 1453 catch(Exception ex) { /* return empty retVal */ ex.printStackTrace(); System.out.println(" playlist["+playListIndex+"] filename="+t); } 1454 } 1455 1456 return retVal; 1457 } 1458 1459 1460 /** 1461 * Gets the album TrackNum of the current item in the playlist. 1462 * 1463 * @return int The TrackNum 1464 */ 1465 public int getAlbumTrackNum() 1466 { 1467 return getAlbumTrackNum(currentPlaylistIndex_); 1468 } 1469 1470 1471 /** 1472 * Gets the album TrackNum of the passed in playListIndex in the playlist. 1473 * 1474 * @return int The TrackNum 1475 */ 1476 public int getAlbumTrackNum(int playListIndex) 1477 { 1478 int retVal = 0; 1479 String t = getTitle(playListIndex); 1480 try 1481 { 1482 String number = "00"; 1483 String cdNumber = "01"; 1484 boolean multiCD = false; 1485 int numSize = 2; 1486 if(t.indexOf("_")>0) 1487 number = t.substring(t.indexOf("_")+1, t.indexOf("-", t.indexOf("_")+1)); 1488 else if(t.indexOf("-")>0) 1489 number = t.substring(t.indexOf("-")-2, t.indexOf("-")); 1490 if(number.length()>2) 1491 { 1492 // it includes a disc number 1493 multiCD = true; 1494 numSize = 4; 1495 cdNumber = Util.left(number,2); 1496 number = Util.right(number,2); 1497 } 1498 retVal = Integer.parseInt(cdNumber); 1499 1500 //retVal = Integer.parseInt(t.substring(t.indexOf("_")+1 , t.indexOf("_")+3)); 1501 1502 } 1503 catch(Exception ex) { /* return empty retVal */ } 1504 1505 return retVal; 1506 } 1507 1508 1509 /** Starts the playing from index 0 in the playlist. */ 1510 public void play_sound() 1511 { 1512 play_sound(0); 1513 } 1514 1515 1516 /** Starts the playing from current index in the playlist. */ 1517 public void play_current_sound() 1518 { 1519 play_sound(currentPlaylistIndex_); 1520 } 1521 1522 1523 /** Start playing a tune from the playlist starting from the index passed in as a parameter playListIndex. 1524 * 1525 * @param playListIndex is the tune to start playing 1526 */ 1527 public void play_sound(int playListIndex) 1528 { 1529 1530 if(playListIndex>=0 && playListIndex<playlist_.size()) 1531 { 1532 if(isPlaying()) 1533 { 1534 signalStopPlay(); 1535 ca.bc.webarts.widgets.Util.sleep(300); 1536 } 1537 currentPlaylistIndex_ = playListIndex; 1538 playerThread_ = new Thread(JOggPlayerListener.getInstance()); 1539 clearStopSignal(); 1540 playing_ = true; 1541 m_status = PLAYING; 1542 playerThread_.start(); 1543 System.out.println(" >> JOggPlayerListener thread now started playing playlist item #"+playListIndex+"/"+(playlist_.size()-1)); 1544 } 1545 else 1546 System.out.println(" >> JOggPlayerListener ERROR: there are not that many ["+playListIndex+"] tunes in the playlist = "+(playlist_.size()-1)); 1547 } 1548 1549 1550 /** 1551 * Stop the playback 1552 * Player Status = STOPPED. 1553 **/ 1554 public void stop() 1555 { 1556 if (playerThread_ != null) 1557 { 1558 try 1559 { 1560 System.out.println(" >> Closing JOggPlayerListener.outputLines"+ Thread.currentThread().getId()); 1561 outputLine.drain(); 1562 outputLine.stop(); 1563 outputLine.close(); 1564 if (oggVorbisBitStream_ != null) 1565 { 1566 oggVorbisBitStream_.close(); 1567 } 1568 } 1569 catch (Exception e) 1570 { 1571 System.out.println(" >> error closing JOggPlayerListener output streams: "+e.getMessage()); 1572 } 1573 } 1574 playerThread_ = null; 1575 m_status = STOPPED; 1576 } 1577 1578 1579 /** Stops play */ 1580 public void stop_sound() 1581 { 1582 playerThread_ = null; 1583 m_status = STOPPED; 1584 } 1585 1586 1587 /** instantaites all the JOgg streams and states. */ 1588 void init_jorbis() 1589 { 1590 oy = new SyncState(); 1591 os = new StreamState(); 1592 og = new Page(); 1593 op = new Packet(); 1594 1595 vi = new Info(); 1596 vc = new Comment(); 1597 vd = new DspState(); 1598 vb = new Block(vd); 1599 1600 buffer = null; 1601 bytes = 0; 1602 1603 oy.init(); 1604 } 1605 1606 1607 /** 1608 * Gets the outputLine attribute of the JOggPlayerListener object 1609 * 1610 * @param channels Description of the Parameter 1611 * @param rate Description of the Parameter 1612 * @return The outputLine value 1613 */ 1614 SourceDataLine getOutputLine(int channels, int rate) 1615 { 1616 if (outputLine == null || this.rate != rate || this.channels != channels) 1617 { 1618 if (outputLine != null) 1619 { 1620 outputLine.drain(); 1621 outputLine.stop(); 1622 outputLine.close(); 1623 } 1624 init_audio(channels, rate); 1625 outputLine.start(); 1626 } 1627 return outputLine; 1628 } 1629 1630 1631 /** 1632 * Description of the Method 1633 * 1634 * @param channels Description of the Parameter 1635 * @param rate Description of the Parameter 1636 */ 1637 void init_audio(int channels, int rate) 1638 { 1639 try 1640 { 1641 //ClassLoader originalClassLoader=null; 1642 //try{ 1643 // originalClassLoader=Thread.currentThread().getContextClassLoader(); 1644 // Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); 1645 //} 1646 //catch(Exception ee){ 1647 // System.out.println(ee); 1648 //} 1649 AudioFormat audioFormat = 1650 new AudioFormat((float) rate, 1651 16, 1652 channels, 1653 true, // PCM_Signed 1654 false// littleEndian 1655 ); 1656 DataLine.Info info = 1657 new DataLine.Info(SourceDataLine.class, 1658 audioFormat, 1659 AudioSystem.NOT_SPECIFIED 1660 ); 1661 1662 if (!AudioSystem.isLineSupported(info)) 1663 { 1664 //System.out.println("Line " + info + " not supported."); 1665 return; 1666 } 1667 1668 try 1669 { 1670 outputLine = (SourceDataLine) AudioSystem.getLine(info); 1671 //outputLine.addLineListener(this); 1672 outputLine.open(audioFormat); 1673 } 1674 catch (LineUnavailableException ex) 1675 { 1676 System.out.println("Unable to open the sourceDataLine: " + ex); 1677 return; 1678 } 1679 catch (IllegalArgumentException ex) 1680 { 1681 System.out.println("Illegal Argument: " + ex); 1682 return; 1683 } 1684 1685 frameSizeInBytes = audioFormat.getFrameSize(); 1686 int bufferLengthInFrames = outputLine.getBufferSize() / frameSizeInBytes / 2; 1687 bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; 1688 1689 //buffer = new byte[bufferLengthInBytes]; 1690 //if(originalClassLoader!=null) 1691 // Thread.currentThread().setContextClassLoader(originalClassLoader); 1692 1693 this.rate = rate; 1694 this.channels = channels; 1695 } 1696 catch (Exception ee) 1697 { 1698 System.out.println(ee); 1699 } 1700 } 1701 1702 1703 /** 1704 * turns a named item into its InputStream. 1705 * 1706 * @param item Description of the Parameter 1707 * @return Description of the Return Value 1708 */ 1709 InputStream selectSource(String item) 1710 { 1711 //System.getProperty(" Selecting source InputStream for item: "+ item); 1712 if (item.endsWith(".pls")) 1713 { 1714 item = fetch_pls(item); 1715 if (item == null) 1716 { 1717 return null; 1718 } 1719 //System.out.println("fetch: "+item); 1720 } 1721 else if (item.endsWith(".m3u")) 1722 { 1723 item = fetch_m3u(item); 1724 if (item == null) 1725 { 1726 return null; 1727 } 1728 //System.out.println("fetch: "+item); 1729 } 1730 1731 if (!item.endsWith(".ogg")) 1732 { 1733 return null; 1734 } 1735 1736 InputStream is = null; 1737 URLConnection urlc = null; 1738 try 1739 { 1740 URL url = null; 1741 url = new URL(item); 1742 urlc = url.openConnection(); 1743 is = urlc.getInputStream(); 1744 current_source = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + url.getFile(); 1745 current_songDuration_ = (urlc.getContentLength() > 0 ? urlc.getContentLength() : 0); 1746 } 1747 catch (Exception ee) 1748 { 1749 //System.err.println(ee); 1750 //ignore and try the next 1751 } 1752 1753 if (is == null) 1754 { 1755 //System.getProperty(" Trying item as a file..."); 1756 try 1757 { 1758 is = new FileInputStream( //System.getProperty("user.dir") + 1759 //System.getProperty("file.separator") + 1760 item); 1761 current_source = null; 1762 //ifweget here its a valid file 1763 current_songDuration_ = (int) (new File(item)).length(); 1764 1765 } 1766 catch (Exception ee) 1767 { 1768 //System.err.println(ee); 1769 //ignore and try the next 1770 } 1771 } 1772 1773 if (is == null) 1774 { 1775 return null; 1776 } 1777 1778 //System.out.println(" Valid InputStream for Selected Item: " + item); 1779 { 1780 boolean find = false; 1781 for (int i = 0; i < playlist_.size(); i++) 1782 { 1783 String foo = (String) (playlist_.get(i)); 1784 if (item.equals(foo)) 1785 { 1786 find = true; 1787 //System.out.println(" AND found it inthe playlist vector"); 1788 break; 1789 } 1790 } 1791 } 1792 1793 int i = 0; 1794 String s = null; 1795 String t = null; 1796 udp_port = -1; 1797 udp_baddress = null; 1798 while (urlc != null && true) 1799 { 1800 s = urlc.getHeaderField(i); 1801 t = urlc.getHeaderFieldKey(i); 1802 if (s == null) 1803 { 1804 break; 1805 } 1806 i++; 1807 if (t != null && t.equals("udp-port")) 1808 { 1809 try 1810 { 1811 udp_port = Integer.parseInt(s); 1812 } 1813 catch (Exception ee) 1814 { 1815 //System.err.println(ee); 1816 //ignore and try the next 1817 } 1818 } 1819 else if (t != null && t.equals("udp-broadcast-address")) 1820 { 1821 udp_baddress = s; 1822 } 1823 } 1824 return is; 1825 } 1826 1827 1828 /** 1829 * Description of the Method 1830 * 1831 * @param pls Description of the Parameter 1832 * @return Description of the Return Value 1833 */ 1834 String fetch_pls(String pls) 1835 { 1836 InputStream pstream = null; 1837 if (pls.startsWith("http://")) 1838 { 1839 try 1840 { 1841 URL url = null; 1842 url = new URL(pls); 1843 URLConnection urlc = url.openConnection(); 1844 pstream = urlc.getInputStream(); 1845 } 1846 catch (Exception ee) 1847 { 1848 System.err.println(ee); 1849 return null; 1850 } 1851 } 1852 if (pstream == null ) 1853 { 1854 try 1855 { 1856 pstream = new FileInputStream( //System.getProperty("user.dir") + 1857 //System.getProperty("file.separator") + 1858 pls); 1859 } 1860 catch (Exception ee) 1861 { 1862 System.err.println(ee); 1863 return null; 1864 } 1865 } 1866 1867 String line = null; 1868 while (true) 1869 { 1870 try 1871 { 1872 line = readline(pstream); 1873 } 1874 catch (Exception e) 1875 {} 1876 if (line == null) 1877 { 1878 break; 1879 } 1880 if (line.startsWith("File1=")) 1881 { 1882 byte[] foo = line.getBytes(); 1883 int i = 6; 1884 for (; i < foo.length; i++) 1885 { 1886 if (foo[i] == 0x0d) 1887 { 1888 break; 1889 } 1890 } 1891 return line.substring(6, i); 1892 } 1893 } 1894 return null; 1895 } 1896 1897 1898 /** 1899 * Description of the Method 1900 * 1901 * @param m3u Description of the Parameter 1902 * @return Description of the Return Value 1903 */ 1904 String fetch_m3u(String m3u) 1905 { 1906 InputStream pstream = null; 1907 if (m3u.startsWith("http://")) 1908 { 1909 try 1910 { 1911 URL url = null; 1912 url = new URL(m3u); 1913 URLConnection urlc = url.openConnection(); 1914 pstream = urlc.getInputStream(); 1915 } 1916 catch (Exception ee) 1917 { 1918 System.err.println(ee); 1919 return null; 1920 } 1921 } 1922 if (pstream == null) 1923 { 1924 try 1925 { 1926 pstream = new FileInputStream( //System.getProperty("user.dir") + 1927 //System.getProperty("file.separator") + 1928 m3u); 1929 } 1930 catch (Exception ee) 1931 { 1932 System.err.println(ee); 1933 return null; 1934 } 1935 } 1936 1937 String line = null; 1938 while (true) 1939 { 1940 try 1941 { 1942 line = readline(pstream); 1943 } 1944 catch (Exception e) 1945 {} 1946 if (line == null) 1947 { 1948 break; 1949 } 1950 return line; 1951 } 1952 return null; 1953 } 1954 1955 1956 /** Add a single tune paths to the playlist. 1957 * 1958 * @param tunePath is the path the the tune to add to the playlist 1959 **/ 1960 public void addToPlaylist(String tunePath) 1961 { 1962 System.out.println(" JOggPlayerListener: addToPlaylist("+tunePath+")"); 1963 playlist_.addElement(tunePath); 1964 } 1965 1966 1967 /** Add multiple tune paths to the playlist. 1968 * 1969 * @param tunePaths is the array of paths for the tunes to add to the playlist 1970 **/ 1971 public void addToPlaylist(String [] tunePaths) 1972 { 1973 System.out.println(" JOggPlayerListener: addToPlaylist( ["+tunePaths.length+"] )"); 1974 if(tunePaths.length>0) 1975 for(int i=0; i<tunePaths.length; i++) 1976 { 1977 System.out.println(" "+tunePaths[i]); 1978 playlist_.addElement(tunePaths[i]); 1979 } 1980 } 1981 1982 1983 /** Recursively Adds multiple directories of *.ogg files to the playlist. It scans all the *.ogg files in those dirs and adds them. 1984 * 1985 * @param dirPath is the directory path for the tunes to add to the playlist 1986 **/ 1987 public void addDirFilesToPlaylist(String dirPath) 1988 { 1989 addDirFilesToPlaylist(dirPath, true); 1990 } 1991 1992 1993 /** Recursively Adds multiple directories of *.ogg files to the playlist. It scans all the *.ogg files in the dirPath and adds them. 1994 * <br>It adds subdir filenames sorted alphabetically. 1995 * 1996 * @param dirPath is the directory path for the tunes to add to the playlist 1997 * @param recurseSubDirs recurseall sub-dirs while processing 1998 **/ 1999 public void addDirFilesToPlaylist(String dirPath, boolean recurseSubDirs) 2000 { 2001 String [] dirPaths = {dirPath}; 2002 addDirFilesToPlaylist(dirPaths, recurseSubDirs); 2003 } 2004 2005 2006 /** Recursively Adds multiple directories of *.ogg files to the playlist. It scans all the *.ogg files in those dirs and adds them. 2007 * <br>It adds them sorted alphabetically. 2008 * 2009 * @param dirPaths is the array of directory paths for the tunes to add to the playlist 2010 **/ 2011 public void addDirFilesToPlaylist(String [] dirPaths) 2012 { 2013 addDirFilesToPlaylist(dirPaths, true, true); 2014 } 2015 /** Adds multiple directories of *.ogg files to the playlist. It scans all the *.ogg files in those dirs and adds them. 2016 * <br>It adds them sorted alphabetically. 2017 * 2018 * @param dirPaths is the array of directory paths for the tunes to add to the playlist 2019 * @param recurseSubDirs choose to recurse subDirs for *.ogg files 2020 **/ 2021 public void addDirFilesToPlaylist(String [] dirPaths, boolean recurseSubDirs) 2022 { 2023 addDirFilesToPlaylist(dirPaths, recurseSubDirs, true); 2024 } 2025 2026 2027 /** Add multiple directories of *.ogg files to the playlist. It scans all the *.ogg files in those dirs and adds them. 2028 * 2029 * @param dirPaths is the array of directory paths for the tunes to add to the playlist 2030 * @param recurseSubDirs choose to recurse subDirs for *.ogg files 2031 * @param sortFilenames choose to sort the *.ogg files as they go into playlist_ 2032 **/ 2033 public void addDirFilesToPlaylist(String [] dirPaths, boolean recurseSubDirs, boolean sortFilenames) 2034 { 2035 if (debug_>1) System.out.print("\n JOggPlayerListener: addDirFilesToPlaylist( ["+dirPaths.length+"] )"); 2036 if (debug_>1) System.out.println(" "+Arrays.toString(dirPaths)); 2037 //boolean sortFilenames = true; 2038 Vector<String> filePaths = new Vector<String>(); 2039 if(dirPaths.length>0) 2040 { 2041 for(int i=0; i<dirPaths.length; i++) 2042 { 2043 File[] dirFiles = (new File(dirPaths[i])).listFiles(); 2044 if (debug_>1) System.out.print(" 0) dirFiles "); 2045 if (debug_>1) System.out.println(dirFiles); 2046 if(dirFiles!=null) 2047 { 2048 for (File currFile: dirFiles) 2049 { 2050 if (debug_>1) System.out.println(" 1) Checking "+currFile.getName()); 2051 if(currFile!=null && !"@eaDir".equals(currFile.getName()) ) //&& currFile.canRead()) 2052 { 2053 if (debug_>1) System.out.print(" 2) Checking "+currFile.getAbsolutePath()); 2054 if(!currFile.isDirectory() && currFile.getAbsolutePath().endsWith(".ogg")) // && currFile.canRead()) 2055 { 2056 if(sortFilenames) 2057 filePaths.addElement(currFile.getAbsolutePath()); 2058 else 2059 playlist_.addElement(currFile.getAbsolutePath()); 2060 if (debug_>1) System.out.println(" !!!ADDED!!! "); 2061 } 2062 else if (recurseSubDirs && currFile.isDirectory()) 2063 { 2064 addDirFilesToPlaylist(currFile.getAbsolutePath(), recurseSubDirs); 2065 } 2066 //else System.out.println("\n NOT adding "+currFile.getAbsolutePath()); 2067 } 2068 } 2069 if(sortFilenames) 2070 { 2071 String [] sortedList = new String[filePaths.size()]; 2072 for(int j=0;j<sortedList.length;j++)sortedList[j]=filePaths.get(j); 2073 ca.bc.webarts.widgets.Quick.sort(sortedList); 2074 for(int j=0;j<sortedList.length;j++)playlist_.add(sortedList[j]); 2075 } 2076 2077 } 2078 } 2079 } 2080 } 2081 2082 2083 /** Description of the Method */ 2084 public void clearPlaylist() 2085 { 2086 playlist_ = new Vector<String>(); 2087 currentPlaylistIndex_=-1; 2088 } 2089 2090 2091 /** 2092 * Converts the raw Vorbis data int music! This method does all the real work. 2093 * It uses the class oggVorbisBitStream and does its JCraft magic to convert that data to audio stream. 2094 * 2095 */ 2096 private void play_stream() 2097 { 2098 int last_channels = -1; 2099 int last_rate = -1; 2100 boolean chained = false; 2101 2102 init_jorbis(); 2103 2104 retry = RETRY; 2105 boolean stopSignal = false; 2106 2107 System.out.println("play_stream>"); 2108 2109 loop : 2110 while (!stopSignal && true)// loop on the song forever 2111 { //rely on the breaks to exit this loop 2112 clearPlaylistSignals(); // 1st time thru - start fresh so any new signals are for this tune. 2113 2114 int eos = 0; 2115 int index = oy.buffer(BUFSIZE); 2116 buffer = oy.data; 2117 try 2118 { 2119 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 2120 } 2121 catch (Exception e) 2122 { 2123 System.err.println(e); 2124 return; 2125 } 2126 oy.wrote(bytes); 2127 2128 if (chained) 2129 {// 2130 chained = false;// 2131 }// 2132 else 2133 {// 2134 if (oy.pageout(og) != 1) 2135 { 2136 if (bytes < BUFSIZE) 2137 { 2138 break; // done, so break out of while loop and close things up 2139 } 2140 System.err.println("Input does not appear to be an Ogg bitstream."); 2141 return; 2142 } 2143 }// 2144 os.init(og.serialno()); 2145 os.reset(); 2146 2147 vi.init(); 2148 vc.init(); 2149 2150 if (os.pagein(og) < 0) 2151 { 2152 // error; stream version mismatch perhaps 2153 System.err.println("Error reading first page of Ogg bitstream data."); 2154 return; 2155 } 2156 2157 retry = RETRY; 2158 2159 if (os.packetout(op) != 1) 2160 { 2161 // no page? must not be vorbis 2162 System.err.println("Error reading initial header packet."); 2163 break; 2164 // return; 2165 } 2166 2167 if (vi.synthesis_headerin(vc, op) < 0) 2168 { 2169 // error case; not a vorbis header 2170 System.err.println("This Ogg bitstream does not contain Vorbis audio data."); 2171 return; 2172 } 2173 2174 /* So Far So good on the stream, continue with */ 2175 /* Vorbis HEADERS */ 2176 int i = 0; 2177 while (i < 2) 2178 { 2179 while (i < 2) 2180 { 2181 int result = oy.pageout(og); 2182 if (result == 0) 2183 { 2184 break; 2185 }// Need more data 2186 if (result == 1) 2187 { 2188 os.pagein(og); 2189 while (i < 2) 2190 { 2191 result = os.packetout(op); 2192 if (result == 0) 2193 { 2194 break; 2195 } 2196 if (result == -1) 2197 { 2198 System.err.println("Corrupt secondary header. Exiting."); 2199 //return; 2200 break loop; 2201 } 2202 vi.synthesis_headerin(vc, op); 2203 i++; 2204 } 2205 } 2206 } 2207 2208 index = oy.buffer(BUFSIZE); 2209 buffer = oy.data; 2210 try 2211 { 2212 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 2213 } 2214 catch (Exception e) 2215 { 2216 System.err.println(e); 2217 return; 2218 } 2219 if (bytes == 0 && i < 2) 2220 { 2221 System.err.println("End of file before finding all Vorbis headers!"); 2222 return; 2223 } 2224 oy.wrote(bytes); 2225 } 2226 2227 /* So Far So good on the stream, continue with */ 2228 /* Vorbis user_comments */ 2229 { 2230 byte[][] ptr = vc.user_comments; 2231 String currComment = ""; 2232 String coverImage = ""; 2233 for (int j = 0; j < ptr.length; j++) 2234 { 2235 if (ptr[j] == null) 2236 { 2237 break; 2238 } 2239 currComment = new String(ptr[j], 0, ptr[j].length - 1); 2240 if(currComment.length()<"METADATA_BLOCK_PICTURE".length() || 2241 !"METADATA_BLOCK_PICTURE".equalsIgnoreCase(currComment.substring(0,"METADATA_BLOCK_PICTURE".length()) )) 2242 System.out.println("Comment: " +currComment ); 2243 else 2244 { 2245 coverImage = currComment; 2246 System.out.println("Comment: " +"METADATA_BLOCK_PICTURE="+"imageData..." ); 2247 } 2248 } 2249 System.out.println("Bitstream is " + vi.channels + " channel, " + vi.rate + "Hz"); 2250 if(vc!=null&& vc.vendor!=null) 2251 System.out.println("Encoded by: " + new String(vc.vendor, 0, vc.vendor.length - 1) + "\n"); 2252 } 2253 2254 /* So Far So good on the stream, continue with */ 2255 /* Vorbis Music Decoding */ 2256 convsize_ = BUFSIZE / vi.channels; 2257 2258 vd.synthesis_init(vi); 2259 vb.init(vd); 2260 2261 double[][][] _pcm = new double[1][][]; 2262 float[][][] _pcmf = new float[1][][]; 2263 int[] _index = new int[vi.channels]; 2264 2265 getOutputLine(vi.channels, vi.rate); 2266 2267 System.out.print(" Decoding "); 2268 2269 while (!stopSignal && eos == 0) 2270 { 2271 //clearPlaylistSignals(); // Each loop start fresh so any new signals are for this tune. 2272 while (!stopSignal && eos == 0) 2273 { 2274 int result = oy.pageout(og); 2275 if (result == 0) 2276 { 2277 break; 2278 }// need more data 2279 if (result == -1) 2280 { 2281 // missing or corrupt data at this page position 2282 System.err.println("Corrupt or missing data in bitstream; continuing..."); 2283 } 2284 else 2285 { 2286 // read a page in to process to pcm 2287 os.pagein(og); // og is a Page of data 2288 2289 if (og.granulepos() == 0) 2290 {// 2291 chained = true;// 2292 eos = 1;// 2293 break;// 2294 }// 2295 2296 while (true) 2297 { 2298 // process to pcm 2299 result = os.packetout(op); 2300 if (result == 0) 2301 { 2302 break; 2303 }// need more data 2304 if (result == -1) 2305 {// missing or corrupt data at this page position 2306 // no reason to complain; already complained above 2307 2308 System.err.println("no reason to complain; already complained above"); 2309 } 2310 else 2311 { 2312 // we have a packet. Decode it 2313 int samples; 2314 if (vb.synthesis(op) == 0) 2315 {// test for success! 2316 vd.synthesis_blockin(vb); 2317 } 2318 while ((samples = vd.synthesis_pcmout(_pcmf, _index)) > 0) 2319 { 2320 //System.out.print("."); 2321 double[][] pcm = _pcm[0]; 2322 float[][] pcmf = _pcmf[0]; 2323 boolean clipflag = false; 2324 int bout = (samples < convsize_ ? samples : convsize_); 2325 2326 // convert doubles to 16 bit signed ints (host order) and 2327 // interleave 2328 for (i = 0; i < vi.channels; i++) 2329 { 2330 int ptr = i * 2; 2331 //int ptr=i; 2332 int mono = _index[i]; 2333 for (int j = 0; j < bout; j++) 2334 { 2335 int val = (int) (pcmf[i][mono + j] * 32767.); 2336 if (val > 32767) 2337 { 2338 val = 32767; 2339 clipflag = true; 2340 } 2341 if (val < -32768) 2342 { 2343 val = -32768; 2344 clipflag = true; 2345 } 2346 if (val < 0) 2347 { 2348 val = val | 0x8000; 2349 } 2350 convbuffer_[ptr] = (byte) (val); 2351 convbuffer_[ptr + 1] = (byte) (val >>> 8); 2352 ptr += 2 * (vi.channels); 2353 } 2354 } 2355 outputLine.write(convbuffer_, 0, 2 * vi.channels * bout); 2356 vd.synthesis_read(bout); 2357 } 2358 2359 /* loop control lives here */ 2360 /* *********************** */ 2361 if(getLoopStopped()) 2362 { 2363 stopSignal = true; 2364 2365 break; 2366 } 2367 if(getSignalPreviousInPlaylist()) 2368 { 2369 //do something 2370 } 2371 if(getSignalNextInPlaylist()) 2372 { 2373 //do something 2374 } 2375 // Pause the stream 2376 while (getLoopPaused()) 2377 { 2378 ca.bc.webarts.widgets.Util.sleep(250); 2379 } 2380 } 2381 } 2382 if (og.eos() != 0) 2383 { 2384 eos = 1; 2385 } 2386 } 2387 //System.out.print(">>>"); 2388 2389 } // inner Decoding while loop 2390 //System.out.println("!"); 2391 2392 // Process last bit of data 2393 if (eos == 0) 2394 { 2395 index = oy.buffer(BUFSIZE); 2396 buffer = oy.data; 2397 try 2398 { 2399 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 2400 } 2401 catch (Exception e) 2402 { 2403 System.err.println(e); 2404 return; 2405 } 2406 if (bytes == -1) 2407 { 2408 //System.err.println("bytes==-1"); 2409 break; 2410 } 2411 oy.wrote(bytes); 2412 if (bytes == 0) 2413 { 2414 eos = 1; 2415 } 2416 } 2417 } // Decoding while loop 2418 System.out.println("DONE Decoding "); 2419 2420 // finish... Close up streams 2421 os.clear(); 2422 vb.clear(); 2423 vd.clear(); 2424 vi.clear(); 2425 } // main play loop 2426 2427 oy.clear(); 2428 2429 //System.out.println(" play_stream <"); 2430 //System.err.println(" ... Done."); 2431 2432 try 2433 { 2434 if (oggVorbisBitStream_ != null) 2435 { 2436 oggVorbisBitStream_.close(); 2437 } 2438 } 2439 catch (Exception e) 2440 {} 2441 } 2442 2443 2444 /** 2445 * Description of the Method 2446 * 2447 * @param me Description of the Parameter 2448 */ 2449 private void play_udp_stream(Thread me) 2450 { 2451 init_jorbis(); 2452 2453 boolean firstloop = true; 2454 2455 try 2456 { 2457 loop : 2458 while (true) 2459 { 2460 int eos = 0; 2461 int index = oy.buffer(BUFSIZE); 2462 buffer = oy.data; 2463 try 2464 { 2465 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 2466 } 2467 catch (Exception e) 2468 { 2469 System.err.println(e); 2470 return; 2471 } 2472 2473 oy.wrote(bytes); 2474 if (oy.pageout(og) != 1) 2475 { 2476// if(bytes<BUFSIZE)break; 2477 System.err.println("Input does not appear to be an Ogg bitstream."); 2478 return; 2479 } 2480 2481 os.init(og.serialno()); 2482 os.reset(); 2483 2484 vi.init(); 2485 vc.init(); 2486 if (os.pagein(og) < 0) 2487 { 2488 // error; stream version mismatch perhaps 2489 System.err.println("Error reading first page of Ogg bitstream data."); 2490 return; 2491 } 2492 2493 if (os.packetout(op) != 1) 2494 { 2495 // no page? must not be vorbis 2496 System.err.println("Error reading initial header packet."); 2497 // break; 2498 return; 2499 } 2500 2501 if (vi.synthesis_headerin(vc, op) < 0) 2502 { 2503 // error case; not a vorbis header 2504 System.err.println("This Ogg bitstream does not contain Vorbis audio data."); 2505 return; 2506 } 2507 2508 int i = 0; 2509 while (i < 2) 2510 { 2511 while (i < 2) 2512 { 2513 int result = oy.pageout(og); 2514 if (result == 0) 2515 { 2516 break; 2517 }// Need more data 2518 if (result == 1) 2519 { 2520 os.pagein(og); 2521 while (i < 2) 2522 { 2523 result = os.packetout(op); 2524 if (result == 0) 2525 { 2526 break; 2527 } 2528 if (result == -1) 2529 { 2530 System.err.println("Corrupt secondary header. Exiting."); 2531 //return; 2532 break loop; 2533 } 2534 vi.synthesis_headerin(vc, op); 2535 i++; 2536 } 2537 } 2538 } 2539 2540 if (i == 2) 2541 { 2542 break; 2543 } 2544 2545 index = oy.buffer(BUFSIZE); 2546 buffer = oy.data; 2547 try 2548 { 2549 bytes = oggVorbisBitStream_.read(buffer, index, BUFSIZE); 2550 } 2551 catch (Exception e) 2552 { 2553 System.err.println(e); 2554 return; 2555 } 2556 if (bytes == 0 && i < 2) 2557 { 2558 System.err.println("End of file before finding all Vorbis headers!"); 2559 return; 2560 } 2561 oy.wrote(bytes); 2562 } 2563 break; 2564 } 2565 } 2566 catch (Exception e) 2567 { 2568 } 2569 2570 try 2571 { 2572 oggVorbisBitStream_.close(); 2573 } 2574 catch (Exception e) 2575 {} 2576 2577 UDPIO io = null; 2578 try 2579 { 2580 io = new UDPIO(udp_port); 2581 } 2582 catch (Exception e) 2583 { 2584 return; 2585 } 2586 2587 oggVorbisBitStream_ = io; 2588 play_stream(); 2589 } 2590 2591 2592 /** 2593 * Description of the Method 2594 * 2595 * @param is Description of the Parameter 2596 * @return Description of the Return Value 2597 */ 2598 private String readline(InputStream is) 2599 { 2600 StringBuffer rtn = new StringBuffer(); 2601 int temp; 2602 do 2603 { 2604 try 2605 { 2606 temp = is.read(); 2607 } 2608 catch (Exception e) 2609 { 2610 return (null); 2611 } 2612 if (temp == -1) 2613 { 2614 return (null); 2615 } 2616 if (temp != 0 && temp != '\n') 2617 { 2618 rtn.append((char) temp); 2619 } 2620 } while (temp != '\n'); 2621 return (rtn.toString()); 2622 } 2623 2624 2625 /** 2626 * Description of the Class 2627 * 2628 * @author tgutwin 2629 */ 2630 class UDPIO extends InputStream 2631 { 2632 /** Description of the Field */ 2633 InetAddress address; 2634 /** Description of the Field */ 2635 DatagramSocket socket = null; 2636 /** Description of the Field */ 2637 DatagramPacket sndpacket; 2638 /** Description of the Field */ 2639 DatagramPacket recpacket; 2640 /** Description of the Field */ 2641 byte[] buf = new byte[1024]; 2642 //String host; 2643 /** Description of the Field */ 2644 int port; 2645 /** Description of the Field */ 2646 byte[] inbuffer = new byte[2048]; 2647 /** Description of the Field */ 2648 byte[] outbuffer = new byte[1024]; 2649 /** Description of the Field */ 2650 int instart = 0, inend = 0, outindex = 0; 2651 2652 2653 /** 2654 * Constructor for the UDPIO object 2655 * 2656 * @param port Description of the Parameter 2657 */ 2658 UDPIO(int port) 2659 { 2660 //this.host="192.168.1.2"; 2661 this.port = port; 2662 try 2663 { 2664 socket = new DatagramSocket(port); 2665 } 2666 catch (Exception e) 2667 { 2668 System.err.println(e); 2669 } 2670 recpacket = new DatagramPacket(buf, 1024); 2671// sndpacket=new DatagramPacket(outbuffer, 0, address, port); 2672 } 2673 2674 2675 /** 2676 * Description of the Method 2677 * 2678 * @exception java.io.IOException Description of the Exception 2679 */ 2680 public void close() 2681 throws java.io.IOException 2682 { 2683 socket.close(); 2684 } 2685 2686 2687 /** 2688 * Description of the Method 2689 * 2690 * @return Description of the Return Value 2691 * @exception java.io.IOException Description of the Exception 2692 */ 2693 public int read() 2694 throws java.io.IOException 2695 { 2696 return 0; 2697 } 2698 2699 2700 /** 2701 * Description of the Method 2702 * 2703 * @param array Description of the Parameter 2704 * @param begin Description of the Parameter 2705 * @param length Description of the Parameter 2706 * @return Description of the Return Value 2707 * @exception java.io.IOException Description of the Exception 2708 */ 2709 public int read(byte[] array, int begin, int length) 2710 throws java.io.IOException 2711 { 2712 return getByte(array, begin, length); 2713 } 2714 2715 2716 /** 2717 * Sets the timeout attribute of the UDPIO object 2718 * 2719 * @param i The new timeout value 2720 */ 2721 void setTimeout(int i) 2722 { 2723 try 2724 { 2725 socket.setSoTimeout(i); 2726 } 2727 catch (Exception e) 2728 { 2729 System.out.println(e); 2730 } 2731 } 2732 2733 2734 /** 2735 * Gets the byte attribute of the UDPIO object 2736 * 2737 * @return The byte value 2738 * @exception java.io.IOException Description of the Exception 2739 */ 2740 int getByte() 2741 throws java.io.IOException 2742 { 2743 if ((inend - instart) < 1) 2744 { 2745 read(1); 2746 } 2747 return inbuffer[instart++] & 0xff; 2748 } 2749 2750 2751 /** 2752 * Gets the byte attribute of the UDPIO object 2753 * 2754 * @param array Description of the Parameter 2755 * @return The byte value 2756 * @exception java.io.IOException Description of the Exception 2757 */ 2758 int getByte(byte[] array) 2759 throws java.io.IOException 2760 { 2761 return getByte(array, 0, array.length); 2762 } 2763 2764 2765 /** 2766 * Gets the byte attribute of the UDPIO object 2767 * 2768 * @param array Description of the Parameter 2769 * @param begin Description of the Parameter 2770 * @param length Description of the Parameter 2771 * @return The byte value 2772 * @exception java.io.IOException Description of the Exception 2773 */ 2774 int getByte(byte[] array, int begin, int length) 2775 throws java.io.IOException 2776 { 2777 int i = 0; 2778 int foo = begin; 2779 while (true) 2780 { 2781 if ((i = (inend - instart)) < length) 2782 { 2783 if (i != 0) 2784 { 2785 System.arraycopy(inbuffer, instart, array, begin, i); 2786 begin += i; 2787 length -= i; 2788 instart += i; 2789 } 2790 read(length); 2791 continue; 2792 } 2793 System.arraycopy(inbuffer, instart, array, begin, length); 2794 instart += length; 2795 break; 2796 } 2797 return begin + length - foo; 2798 } 2799 2800 2801 /** 2802 * Gets the short attribute of the UDPIO object 2803 * 2804 * @return The short value 2805 * @exception java.io.IOException Description of the Exception 2806 */ 2807 int getShort() 2808 throws java.io.IOException 2809 { 2810 if ((inend - instart) < 2) 2811 { 2812 read(2); 2813 } 2814 int s = 0; 2815 s = inbuffer[instart++] & 0xff; 2816 s = ((s << 8) & 0xffff) | (inbuffer[instart++] & 0xff); 2817 return s; 2818 } 2819 2820 2821 /** 2822 * Gets the int attribute of the UDPIO object 2823 * 2824 * @return The int value 2825 * @exception java.io.IOException Description of the Exception 2826 */ 2827 int getInt() 2828 throws java.io.IOException 2829 { 2830 if ((inend - instart) < 4) 2831 { 2832 read(4); 2833 } 2834 int i = 0; 2835 i = inbuffer[instart++] & 0xff; 2836 i = ((i << 8) & 0xffff) | (inbuffer[instart++] & 0xff); 2837 i = ((i << 8) & 0xffffff) | (inbuffer[instart++] & 0xff); 2838 i = (i << 8) | (inbuffer[instart++] & 0xff); 2839 return i; 2840 } 2841 2842 2843 /** 2844 * Gets the pad attribute of the UDPIO object 2845 * 2846 * @param n Description of the Parameter 2847 * @exception java.io.IOException Description of the Exception 2848 */ 2849 void getPad(int n) 2850 throws java.io.IOException 2851 { 2852 int i; 2853 while (n > 0) 2854 { 2855 if ((i = inend - instart) < n) 2856 { 2857 n -= i; 2858 instart += i; 2859 read(n); 2860 continue; 2861 } 2862 instart += n; 2863 break; 2864 } 2865 } 2866 2867 2868 /** 2869 * Description of the Method 2870 * 2871 * @param n Description of the Parameter 2872 * @exception java.io.IOException Description of the Exception 2873 */ 2874 void read(int n) 2875 throws java.io.IOException 2876 { 2877 if (n > inbuffer.length) 2878 { 2879 n = inbuffer.length; 2880 } 2881 instart = inend = 0; 2882 int i; 2883 while (true) 2884 { 2885 recpacket.setData(buf, 0, 1024); 2886 socket.receive(recpacket); 2887 2888 i = recpacket.getLength(); 2889 System.arraycopy(recpacket.getData(), 0, inbuffer, inend, i); 2890 if (i == -1) 2891 { 2892 throw new java.io.IOException(); 2893 } 2894 inend += i; 2895 break; 2896 } 2897 } 2898 } // innerclass UDPIO 2899 2900}// JOggPlayerListener 2901