PlayerMakerThread.java
上传用户:liming6160
上传日期:2022-06-07
资源大小:785k
文件大小:12k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  *    Copyright (C) 2001 - 2007 Mobicom-Kavkaz, Inc
  3.  *    MFRadio - stream radio client for Java 2 Micro Edition
  4.  *    
  5.  *    Visit the project page at: http://mfradio.sourceforge.net
  6.  *
  7.  *    This program is free software; you can redistribute it and/or modify
  8.  *    it under the terms of the GNU General Public License as published by
  9.  *    the Free Software Foundation; either version 2 of the License, or
  10.  *    (at your option) any later version.
  11.  *
  12.  *    This program is distributed in the hope that it will be useful,
  13.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *    GNU General Public License for more details.
  16.  *
  17.  *    You should have received a copy of the GNU General Public License
  18.  *    along with this program; if not, write to the Free Software
  19.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *    Java (TM) and all Java (TM)-based marks are a trademark or 
  22.  *    registered trademark of Sun Microsystems, Inc, in the United States 
  23.  *    and other countries.
  24.  */
  25. package ru.mobicomk.mfradio.controller;
  26. import java.io.ByteArrayInputStream;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.util.Hashtable;
  30. import javax.microedition.media.MediaException;
  31. import javax.microedition.media.Player;
  32. import javax.microedition.media.PlayerListener;
  33. import ru.mobicomk.mfradio.Constants;
  34. import ru.mobicomk.mfradio.iface.PlayerQueue;
  35. import ru.mobicomk.mfradio.util.BooleanFlag;
  36. import ru.mobicomk.mfradio.util.Dloader;
  37. import ru.mobicomk.mfradio.util.Locale;
  38. import ru.mobicomk.mfradio.util.PlayerFactory;
  39. /**
  40.  * Player maker thread class.
  41.  * <p>Download next chunk of the audio stream data and makes new instance of a 
  42.  * Player object. Then append it to the Player's queue.</p>
  43.  *
  44.  * @author  Roman Bondarenko
  45.  * @see Dloader
  46.  * @see UIController
  47.  * @see PlayerQueue
  48.  */
  49. class PlayerMakerThread extends Thread {
  50.     
  51.     /**
  52.      * Controller must setting up this flag to <b>true</b> for stop thread
  53.      * execution.
  54.      */
  55.     BooleanFlag StopFlag;
  56.     
  57.     //private static final int BUFFER_SIZE = 12288; // 2sec/48kbps
  58.     //private static final int BUFFER_SIZE = 24576; // 4sec/48kbps
  59.     private static final int BUFFER_SIZE = 49152; // 8sec/48kbps
  60.     
  61.     private static final int OFFSET_SIZE = 0/*512*/; // 1/6sec@24kbps
  62.         // set OFFSET_SIZE > 0 if you want to make Players with overlapped
  63.     
  64.     private byte[] buffer_ ;
  65.     
  66.     private Hashtable headers_;
  67.     private String streamType_;
  68.     private UIController controller_;
  69.     private Dloader dloader_;
  70.     private PlayerListener listener_;
  71.     private PlayerQueue queue_;
  72.     
  73.     
  74.     /**
  75.      * Creates a new instance of PlayerMakerThread
  76.      * @param controller Application controller object.
  77.      */
  78.     public PlayerMakerThread(UIController controller){
  79.         controller_ = controller;
  80.         headers_ = null;
  81.     }
  82.     
  83.     /**
  84.      * Stop thread helper.
  85.      */
  86.     public void stop() {
  87.         StopFlag.set();
  88.         if (dloader_ != null) {
  89.             dloader_.StopFlag.set();
  90.         }
  91.     }
  92.     
  93.     /**
  94.      * Thread entry point.
  95.      * @see java.lang.Thread
  96.      * @see java.lang.Thread#run
  97.      */
  98.     public void run() {
  99.         //controller_.log("maker >> start work!");
  100.         
  101.         int readed = 0;
  102.         int startOffset = 0;
  103.         InputStream is = null;
  104.         Player p = null;
  105.         int noDataStep = 0;
  106.         int noConnectionStep = 0;
  107.         boolean threadIsBreaked = false;
  108.         final Locale locale = controller_.getLocale();
  109.         
  110.         try {
  111.             while (!StopFlag.value()) {
  112.                 
  113.                 // read data
  114.                 controller_.progressMessage(locale.getString(Constants.STR_Prefetching));
  115.                 //controller_.log("maker >> try to read data...");
  116.                 
  117.                 if (startOffset > 0) {
  118.                     is = new ByteArrayInputStream(buffer_, readed - startOffset, startOffset);
  119.                     is.read(buffer_, 0, startOffset);
  120.                 }
  121.                 
  122.                 readed = dloader_.read(buffer_, startOffset);  // exception
  123.                 
  124.                 if (StopFlag.value()) {
  125.                     break;
  126.                 }
  127.                 
  128.                 if (readed < 1){
  129.                     controller_.progressMessage(locale.getString(Constants.STR_Try_again));
  130.                     //controller_.log("maker >> no data readed! go next step.");
  131.                     Thread.yield();
  132.                     //Thread.sleep(500);
  133.                     noDataStep++;
  134.                     startOffset = 0;
  135.                     if (noDataStep > 5) {
  136.                         //controller_.log("maker >> " + noDataStep + " step(s) without data... goodbye!");
  137.                         break; 
  138.                     }
  139.                     if (noDataStep == 3) {
  140.                         try {
  141.                             //controller_.log("maker >> " + noDataStep + " step(s) without data... try to reconnect.");
  142.                             controller_.progressMessage(locale.getString(Constants.STR_Reconnecting));
  143.                             if (!dloader_.reconnect()) {
  144.                                 controller_.progressMessage(locale.getString(Constants.STR_Cant_connect));
  145.                                 break; // stop this thread
  146.                             }
  147.                         } catch (InterruptedException ex) {
  148.                             //controller_.log("maker (reconnect) >> InterruptedException >> " + ex.getMessage());
  149.                             break; // stop this thread
  150.                         }
  151.                     }
  152.                     continue; // try again
  153.                 }
  154.                 
  155.                 try {
  156.                     //controller_.log("maker >> data readed (size: "+readed+")");
  157.                     noDataStep = 0;
  158.                     is = new ByteArrayInputStream(buffer_, 0, readed + startOffset);
  159.                     //controller_.log("maker >> try to make player...");
  160.                     p = PlayerFactory.createPlayer(is, streamType_, listener_);
  161.                     
  162.                     //controller_.log("maker >> player is created!");
  163.                     queue_.pushTail(p);
  164.                     startOffset = OFFSET_SIZE; //3072; // 24kbps - 1 sec
  165.                     //controller_.log("maker >> OK! player in queue");
  166.                     
  167.                 } catch (Exception ex) {
  168.                     //controller_.log("maker >> " + ex.toString());
  169.                     closeInputStream(is);
  170.                     if (p != null) {
  171.                         p.close();
  172.                         p = null;
  173.                     }
  174.                 }
  175.             }
  176.         } catch (InterruptedException ex) {
  177.             //controller_.log("maker >> " + ex.toString());
  178.             StopFlag.set();
  179.         } catch (Exception ex) {
  180.             //controller_.log("maker >> " + ex.toString());
  181.         }
  182.         
  183.         closeInputStream(is);
  184.         
  185.         dloader_.disconnect();
  186.         dloader_ = null;
  187.         buffer_ = null;
  188.         
  189.         System.gc();
  190.         
  191.         if (!StopFlag.value()) {
  192.             StopFlag.set();
  193.             controller_.makerIsInterrupted(); // thread is breaked by exception!
  194.         } else {
  195.             controller_.makerIsStopped();
  196.         }
  197.         //controller_.log("maker >> finish work!");
  198.     }
  199.     
  200.     private void closeInputStream(InputStream is) {
  201.         if (is != null) {
  202.             try {
  203.                 is.close();
  204.                 is = null;
  205.             } catch (IOException ioex) {
  206.                 //controller_.log("closeInputStream >> IOException >> " + ioex.getMessage());
  207.             }
  208.         }
  209.         headers_ = null;
  210.     }
  211.     
  212.     /**
  213.      * Second level initialization.
  214.      * @param url URL of the audio stream.
  215.      * @param queue Player queue object.
  216.      * @param listener Player listener object.
  217.      * @throws java.lang.Exception if any error (IO, HTTP responce code not
  218.      * equals 200, unsupported stream format).
  219.      */
  220.     public void init(String url, PlayerQueue queue, PlayerListener listener)
  221.     throws Exception {
  222.         
  223.         try {
  224.             controller_.updateProgress();
  225.             final Locale locale = controller_.getLocale();
  226.             
  227.             StopFlag = new BooleanFlag(false);
  228.             listener_ = listener;
  229.             queue_ = queue;
  230.             
  231.             controller_.updateProgress();
  232.             dloader_ = new Dloader(controller_);
  233.             
  234.             controller_.progressMessage(locale.getString(Constants.STR_Connecting));
  235.             controller_.updateProgress();
  236.             
  237.             // connect
  238.             if (!dloader_.connect(url)) {
  239.                 throw new IOException(locale.getString(Constants.STR_Cant_connect));
  240.             }
  241.             
  242.             // read responce code
  243.             String[] resp = dloader_.readResponseCode();
  244.             if (!"200".equals(resp[1])) {
  245.                 throw new IOException(locale.getString(Constants.STR_HTTP_response_code) + resp[1] + " " + resp[2]);
  246.             }
  247.             
  248.             // read headers for streamType
  249.             headers_ = dloader_.readHeaders();
  250.             
  251.             if (headers_.containsKey("content-type")) {
  252.                 streamType_ = (String) headers_.get("content-type");
  253.             } else {
  254.                 if (url.endsWith(".mp3")) {
  255.                     streamType_ = "audio/mp3";
  256.                 } else if (url.endsWith(".wav")) {
  257.                     streamType_ = "audio/x-wav";
  258.                 } else {
  259.                     streamType_ = "audio/mpeg"; // default type
  260.                     //throw new MediaException("Unknown audio type!");
  261.                 }
  262.             }
  263.             
  264.             // check for supported type
  265.             if (!isSupported("http", streamType_)) {
  266.                 if (streamType_.equals("audio/mpeg") || streamType_.equals("audio/mp3")) {
  267.                     if (isSupported("http", "audio/mpeg3")) {
  268.                         streamType_ = "audio/mpeg3";
  269.                     } else {
  270.                         throw new MediaException(locale.getString(Constants.STR_Unsupported_content_type_BEGIN
  271.                             + streamType_ + locale.getString(Constants.STR_Unsupported_content_type_END)));
  272.                     }
  273.                 } else if (streamType_.equals("audio/mpeg3")) {
  274.                     if (isSupported("http", "audio/mpeg")) {
  275.                         streamType_ = "audio/mpeg";
  276.                     } else if (isSupported("http", "audio/mp3")) {
  277.                         streamType_ = "audio/mp3";
  278.                     } else {
  279.                         throw new MediaException(locale.getString(Constants.STR_Unsupported_content_type_BEGIN
  280.                             + streamType_ + locale.getString(Constants.STR_Unsupported_content_type_END)));
  281.                     }
  282.                 } else {
  283.                     throw new MediaException(locale.getString(Constants.STR_Unsupported_content_type_BEGIN
  284.                         + streamType_ + locale.getString(Constants.STR_Unsupported_content_type_END)));
  285.                 }
  286.             }
  287.             
  288.             //if (url.startsWith("http://test.local")) {
  289.             //    buffer_ = new byte[90000];
  290.             //} else {
  291.             buffer_ = new byte[BUFFER_SIZE];
  292.             //}
  293.         } catch (Exception ex) {
  294.             //controller_.progressMessage("interrupt - 2.1");
  295.             dloader_.disconnect();
  296.             dloader_ = null;
  297.             throw ex;
  298.         }
  299.     }
  300.     
  301.     /**
  302.      * HTTP responce headers accessor.
  303.      * @return HTTP responce headers hash table.
  304.      */
  305.     public Hashtable getHeaders() {
  306.         return headers_;
  307.     }
  308.     
  309.     /*
  310.      *
  311.      */
  312.     private static boolean isSupported(String proto, String streamType) {
  313.         boolean isSupported = false;
  314.         String[] protocols = javax.microedition.media.Manager.getSupportedProtocols(streamType);
  315.         for (int i=0; i < protocols.length; i++) {
  316.             if (protocols[i].toLowerCase().equals(proto)) {
  317.                 isSupported = true;
  318.                 break;
  319.             }
  320.         }
  321.         return isSupported;
  322.     }
  323. }