2010-03-29 18 views
1

我必须在应用程序中创建一个自定义媒体播放器,支持mp3和wav文件。我在没有定制数据源的情况下阅读了我无法查找的文档或获取媒体文件的时间。黑莓上的自定义数据源播放器

我检查了演示在JDE 4.6,但我还有问题......我不能得到持续,它会返回更多的则预期,所以我敢肯定,我搞砸了的东西,而我修改了代码阅读从文件系统本地mp3文件。

有人可以告诉我我做错了什么吗? (我可以听到mp3,所以玩家可以从头到尾正确播放)

我必须支持操作系统> = 4.6。

这是我修改的数据源:

/* LimitedRateStreaminSource.java 
* 
* Copyright © 1998-2009 Research In Motion Ltd. 
* 
* Note: For the sake of simplicity, this sample application may not leverage 
* resource bundles and resource strings. However, it is STRONGLY recommended 
* that application developers make use of the localization features available 
* within the BlackBerry development platform to ensure a seamless application 
* experience across a variety of languages and geographies. 
* For more information on localizing your application, please refer to the 
* BlackBerry Java Development Environment Development Guide associated with 
* this release. 
*/ 

package com.halcyon.tawkwidget.model; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 

import javax.microedition.io.Connector; 
import javax.microedition.io.file.FileConnection; 
import javax.microedition.media.Control; 
import javax.microedition.media.protocol.ContentDescriptor; 
import javax.microedition.media.protocol.DataSource; 
import javax.microedition.media.protocol.SourceStream; 

import net.rim.device.api.io.SharedInputStream; 

/** 
* The data source used by the BufferedPlayback's media player. 
*/ 
public final class LimitedRateStreamingSource extends DataSource 
{ 
    /** The max size to be read from the stream at one time. */ 
    private static final int READ_CHUNK = 512; // bytes 

    /** A reference to the field which displays the load status. */ 
    //private TextField _loadStatusField; 

    /** A reference to the field which displays the player status. */ 
    //private TextField _playStatusField; 

    /** 
    * The minimum number of bytes that must be buffered before the media file 
    * will begin playing. 
    */ 
    private int _startBuffer = 200000; 

    /** The maximum size (in bytes) of a single read. */ 
    private int _readLimit = 32000; 

    /** 
    * The minimum forward byte buffer which must be maintained in order for 
    * the video to keep playing. If the forward buffer falls below this 
    * number, the playback will pause until the buffer increases. 
    */ 
    private int _pauseBytes = 64000; 

    /** 
    * The minimum forward byte buffer required to resume 
    * playback after a pause. 
    */ 
    private int _resumeBytes = 128000; 

    /** The stream connection over which media content is passed. */ 
    //private ContentConnection _contentConnection; 

    private FileConnection _fileConnection; 

    /** An input stream shared between several readers. */ 
    private SharedInputStream _readAhead; 

    /** A stream to the buffered resource. */ 
    private LimitedRateSourceStream _feedToPlayer; 

    /** The MIME type of the remote media file. */ 
    private String _forcedContentType; 

    /** A counter for the total number of buffered bytes */ 
    private volatile int _totalRead; 

    /** A flag used to tell the connection thread to stop */ 
    private volatile boolean _stop; 

    /** 
    * A flag used to indicate that the initial buffering is complete. In 
    * other words, that the current buffer is larger than the defined start 
    * buffer size. 
    */ 
    private volatile boolean _bufferingComplete; 

    /** A flag used to indicate that the remote file download is complete. */ 
    private volatile boolean _downloadComplete; 

    /** The thread which retrieves the remote media file. */ 
    private ConnectionThread _loaderThread; 

    /** The local save file into which the remote file is written. */ 
    private FileConnection _saveFile; 

    /** A stream for the local save file. */ 
    private OutputStream _saveStream; 

    /** 
    * Constructor. 
    * @param locator The locator that describes the DataSource. 
    */ 
    public LimitedRateStreamingSource(String locator) 
    { 
     super(locator); 
    } 

    /** 
    * Open a connection to the locator. 
    * @throws IOException 
    */ 
    public void connect() throws IOException 
    { 
     //Open the connection to the remote file. 

    _fileConnection = (FileConnection)Connector.open(getLocator(), 
      Connector.READ); 
     //Cache a reference to the locator. 
     String locator = getLocator(); 

     //Report status. 
     System.out.println("Loading: " + locator); 
     //System.out.println("Size: " + _contentConnection.getLength()); 
     System.out.println("Size: " + _fileConnection.totalSize()); 

     //The name of the remote file begins after the last forward slash. 
     int filenameStart = locator.lastIndexOf('/'); 

     //The file name ends at the first instance of a semicolon. 
     int paramStart = locator.indexOf(';'); 

     //If there is no semicolon, the file name ends at the end of the line. 
     if (paramStart < 0) 
     { 
      paramStart = locator.length(); 
     } 

     //Extract the file name. 
     String filename = locator.substring(filenameStart, paramStart); 
     System.out.println("Filename: " + filename); 

     //Open a local save file with the same name as the remote file. 
     _saveFile = (FileConnection) Connector.open("file:///SDCard"+ 
      "/blackberry/music" + filename, Connector.READ_WRITE); 

     //If the file doesn't already exist, create it. 
     if (!_saveFile.exists()) 
     { 
      _saveFile.create(); 
     } 
     System.out.println("---------- 1"); 
     //Open the file for writing. 
     _saveFile.setReadable(true); 

     //Open a shared input stream to the local save file to 
     //allow many simultaneous readers. 
     SharedInputStream fileStream = SharedInputStream.getSharedInputStream(
      _saveFile.openInputStream()); 

     //Begin reading at the beginning of the file. 
     fileStream.setCurrentPosition(0); 
     System.out.println("---------- 2"); 
     //If the local file is smaller than the remote file... 
     if (_saveFile.fileSize() < _fileConnection.totalSize()) 
     { 
     System.out.println("---------- 3"); 
      //Did not get the entire file, set the system to try again. 
      _saveFile.setWritable(true); 
      System.out.println("---------- 4"); 
      //A non-null save stream is used as a flag later to indicate that 
      //the file download was incomplete. 
      _saveStream = _saveFile.openOutputStream(); 
      System.out.println("---------- 5"); 
      //Use a new shared input stream for buffered reading. 
      _readAhead = SharedInputStream.getSharedInputStream(
       _fileConnection.openInputStream()); 
      System.out.println("---------- 6"); 
     } 
     else 
     { 
      //The download is complete. 
     System.out.println("---------- 7"); 
     _downloadComplete = true; 

      //We can use the initial input stream to read the buffered media. 
      _readAhead = fileStream; 
      System.out.println("---------- 8"); 
      //We can close the remote connection. 
      _fileConnection.close(); 
      System.out.println("---------- 9"); 
     } 

     if (_forcedContentType != null) 
     { 
      //Use the user-defined content type if it is set. 
     System.out.println("---------- 10"); 
      _feedToPlayer = new LimitedRateSourceStream(_readAhead, 
       _forcedContentType); 
      System.out.println("---------- 11"); 
     } 
     else 
     { 
     System.out.println("---------- 12"); 
      //Otherwise, use the MIME types of the remote file. 
      // _feedToPlayer = new LimitedRateSourceStream(_readAhead, 
        _fileConnection)); 
     } 
     System.out.println("---------- 13"); 
    } 

    /** 
    * Destroy and close all existing connections. 
    */ 
    public void disconnect() { 
     try 
     { 
      if (_saveStream != null) 
      { 
       //Destroy the stream to the local save file. 
       _saveStream.close(); 
       _saveStream = null; 
      } 

      //Close the local save file. 
      _saveFile.close(); 

      if (_readAhead != null) 
      { 
       //Close the reader stream. 
       _readAhead.close(); 
       _readAhead = null; 
      } 

      //Close the remote file connection. 
      _fileConnection.close(); 

      //Close the stream to the player. 
      _feedToPlayer.close(); 
     } 
     catch (Exception e) 
     { 
      System.err.println(e.getMessage()); 
     } 
    } 

    /** 
    * Returns the content type of the remote file. 
    * @return The content type of the remote file. 
    */ 
    public String getContentType() 
    { 
     return _feedToPlayer.getContentDescriptor().getContentType(); 
    } 

    /** 
    * Returns a stream to the buffered resource. 
    * @return A stream to the buffered resource. 
    */ 
    public SourceStream[] getStreams() 
    { 
     return new SourceStream[] { _feedToPlayer }; 
    } 

    /** 
    * Starts the connection thread used to download the remote file. 
    */ 
    public void start() throws IOException 
    { 
     //If the save stream is null, we have already completely downloaded 
     //the file. 
     if (_saveStream != null) 
     { 
      //Open the connection thread to finish downloading the file. 
      _loaderThread = new ConnectionThread(); 
      _loaderThread.start(); 
     } 
    } 

    /** 
    * Stop the connection thread. 
    */ 
    public void stop() throws IOException 
    { 
     //Set the boolean flag to stop the thread. 
     _stop = true; 
    } 

    /** 
    * @see javax.microedition.media.Controllable#getControl(String) 
    */ 
    public Control getControl(String controlType) 
    { 
     // No implemented Controls. 
     return null; 
    } 

    /** 
    * @see javax.microedition.media.Controllable#getControls() 
    */ 
    public Control[] getControls() 
    { 
     // No implemented Controls. 
     return null; 
    } 

    /** 
    * Force the lower level stream to a given content type. Must be called 
    * before the connect function in order to work. 
    * @param contentType The content type to use. 
    */ 
    public void setContentType(String contentType) 
    { 
     _forcedContentType = contentType; 
    } 

    /** 
    * A stream to the buffered media resource. 
    */ 
    private final class LimitedRateSourceStream implements SourceStream 
    { 
     /** A stream to the local copy of the remote resource. */ 
     private SharedInputStream _baseSharedStream; 

     /** Describes the content type of the media file. */ 
     private ContentDescriptor _contentDescriptor; 

     /** 
     * Constructor. Creates a LimitedRateSourceStream from 
     * the given InputStream. 
     * @param inputStream The input stream used to create a new reader. 
     * @param contentType The content type of the remote file. 
     */ 
     LimitedRateSourceStream(InputStream inputStream, String contentType) 
     { 
     System.out.println("[LimitedRateSoruceStream]---------- 1"); 
      _baseSharedStream = SharedInputStream.getSharedInputStream(
       inputStream); 
      System.out.println("[LimitedRateSoruceStream]---------- 2"); 
      _contentDescriptor = new ContentDescriptor(contentType); 
      System.out.println("[LimitedRateSoruceStream]---------- 3"); 
     } 

     /** 
     * Returns the content descriptor for this stream. 
     * @return The content descriptor for this stream. 
     */ 
     public ContentDescriptor getContentDescriptor() 
     { 
      return _contentDescriptor; 
     } 

     /** 
     * Returns the length provided by the connection. 
     * @return long The length provided by the connection. 
     */ 
     public long getContentLength() 
     { 
      return _fileConnection.totalSize(); 
     } 

     /** 
     * Returns the seek type of the stream. 
     */ 
     public int getSeekType() 
     { 
     return RANDOM_ACCESSIBLE; 
      //return SEEKABLE_TO_START; 
     } 

     /** 
     * Returns the maximum size (in bytes) of a single read. 
     */ 
     public int getTransferSize() 
     { 
      return _readLimit; 
     } 

     /** 
     * Writes bytes from the buffer into a byte array for playback. 
     * @param bytes The buffer into which the data is read. 
     * @param off The start offset in array b at which the data is written. 
     * @param len The maximum number of bytes to read. 
     * @return the total number of bytes read into the buffer, or -1 if 
     * there is no more data because the end of the stream has been reached. 
     * @throws IOException 
     */ 
     public int read(byte[] bytes, int off, int len) throws IOException 
     { 
     System.out.println("[LimitedRateSoruceStream]---------- 5"); 
      System.out.println("Read Request for: " + len + " bytes"); 

      //Limit bytes read to our readLimit. 
      int readLength = len; 
      System.out.println("[LimitedRateSoruceStream]---------- 6"); 
      if (readLength > getReadLimit()) 
      { 
       readLength = getReadLimit(); 
      } 

      //The number of available byes in the buffer. 
      int available; 

      //A boolean flag indicating that the thread should pause 
      //until the buffer has increased sufficiently. 
      boolean paused = false; 
      System.out.println("[LimitedRateSoruceStream]---------- 7"); 
      for (;;) 
      { 
       available = _baseSharedStream.available(); 

       System.out.println("[LimitedRateSoruceStream]---------- 8"); 
       if (_downloadComplete) 
       { 
        //Ignore all restrictions if downloading is complete. 
        System.out.println("Complete, Reading: " + len + 
         " - Available: " + available); 
        return _baseSharedStream.read(bytes, off, len); 
       } 
       else if(_bufferingComplete) 
       { 
        if (paused && available > getResumeBytes()) 
        { 
         //If the video is paused due to buffering, but the 
         //number of available byes is sufficiently high, 
         //resume playback of the media. 
         System.out.println("Resuming - Available: " + 
          available); 
         paused = false; 
         return _baseSharedStream.read(bytes, off, readLength); 
        } 
        else if(!paused && (available > getPauseBytes() || 
         available > readLength)) 
        { 
         //We have enough information for this media playback. 

         if (available < getPauseBytes()) 
         { 
          //If the buffer is now insufficient, set the 
          //pause flag. 
          paused = true; 
         } 

         System.out.println("Reading: " + readLength + 
          " - Available: " + available); 
         return _baseSharedStream.read(bytes, off, readLength); 
        } 
        else if(!paused) 
        { 
         //Set pause until loaded enough to resume. 
         paused = true; 
        } 
       } 
       else 
       { 
        //We are not ready to start yet, try sleeping to allow the 
        //buffer to increase. 
        try 
        { 
         Thread.sleep(500); 
        } 
        catch (Exception e) 
        { 
         System.err.println(e.getMessage()); 
        } 
       } 
      } 
     } 

     /** 
     * @see javax.microedition.media.protocol.SourceStream#seek(long) 
     */ 
     public long seek(long where) throws IOException 
     { 
      _baseSharedStream.setCurrentPosition((int) where); 
      return _baseSharedStream.getCurrentPosition(); 
     } 

     /** 
     * @see javax.microedition.media.protocol.SourceStream#tell() 
     */ 
     public long tell() 
     { 
      return _baseSharedStream.getCurrentPosition(); 
     } 

     /** 
     * Close the stream. 
     * @throws IOException 
     */ 
     void close() throws IOException 
     { 
      _baseSharedStream.close(); 
     } 

     /** 
     * @see javax.microedition.media.Controllable#getControl(String) 
     */ 
     public Control getControl(String controlType) 
     { 
      // No implemented controls. 
      return null; 
     } 

     /** 
     * @see javax.microedition.media.Controllable#getControls() 
     */ 
     public Control[] getControls() 
     { 
      // No implemented controls. 
      return null; 
     } 
    } 

    /** 
    * A thread which downloads the remote file and writes it to the local file. 
    */ 
    private final class ConnectionThread extends Thread 
    { 
     /** 
     * Download the remote media file, then write it to the local 
     * file. 
     * @see java.lang.Thread#run() 
     */ 
     public void run() 
     { 
      try 
      { 
       byte[] data = new byte[READ_CHUNK]; 
       int len = 0; 

       //Until we reach the end of the file. 
       while (-1 != (len = _readAhead.read(data))) 
       { 
        _totalRead += len; 

        if (!_bufferingComplete && _totalRead > getStartBuffer()) 
        { 
         //We have enough of a buffer to begin playback. 
         _bufferingComplete = true; 
         System.out.println("Initial Buffering Complete"); 
        } 

        if (_stop) 
        { 
         //Stop reading. 
         return; 
        } 

       } 

       System.out.println("Downloading Complete"); 
       System.out.println("Total Read: " + _totalRead); 

       //If the downloaded data is not the same size 
       //as the remote file, something is wrong. 
       if (_totalRead != _fileConnection.totalSize()) 
       { 
        System.err.println("* Unable to Download entire file *"); 
       } 

       _downloadComplete = true; 
       _readAhead.setCurrentPosition(0); 

       //Write downloaded data to the local file. 
       while (-1 != (len = _readAhead.read(data))) 
       { 
        _saveStream.write(data); 
       } 

      } 
      catch (Exception e) 
      { 
       System.err.println(e.toString()); 
      } 
     } 
    } 

    /** 
    * Gets the minimum forward byte buffer which must be maintained in 
    * order for the video to keep playing. 
    * @return The pause byte buffer. 
    */ 
    int getPauseBytes() 
    { 
     return _pauseBytes; 
    } 

    /** 
    * Sets the minimum forward buffer which must be maintained in order 
    * for the video to keep playing. 
    * @param pauseBytes The new pause byte buffer. 
    */ 
    void setPauseBytes(int pauseBytes) 
    { 
     _pauseBytes = pauseBytes; 
    } 

    /** 
    * Gets the maximum size (in bytes) of a single read. 
    * @return The maximum size (in bytes) of a single read. 
    */ 
    int getReadLimit() 
    { 
     return _readLimit; 
    } 

    /** 
    * Sets the maximum size (in bytes) of a single read. 
    * @param readLimit The new maximum size (in bytes) of a single read. 
    */ 
    void setReadLimit(int readLimit) 
    { 
     _readLimit = readLimit; 
    } 

    /** 
    * Gets the minimum forward byte buffer required to resume 
    * playback after a pause. 
    * @return The resume byte buffer. 
    */ 
    int getResumeBytes() 
    { 
     return _resumeBytes; 
    } 

    /** 
    * Sets the minimum forward byte buffer required to resume 
    * playback after a pause. 
    * @param resumeBytes The new resume byte buffer. 
    */ 
    void setResumeBytes(int resumeBytes) 
    { 
     _resumeBytes = resumeBytes; 
    } 

    /** 
    * Gets the minimum number of bytes that must be buffered before the 
    * media file will begin playing. 
    * @return The start byte buffer. 
    */ 
    int getStartBuffer() 
    { 
     return _startBuffer; 
    } 

    /** 
    * Sets the minimum number of bytes that must be buffered before the 
    * media file will begin playing. 
    * @param startBuffer The new start byte buffer. 
    */ 
    void setStartBuffer(int startBuffer) 
    { 
     _startBuffer = startBuffer; 
    } 
} 

并以这种方式我用它:

LimitedRateStreamingSource source = new          
    LimitedRateStreamingSource("file:///SDCard/music3.mp3"); 
source.setContentType("audio/mpeg"); 
mediaPlayer = javax.microedition.media.Manager.createPlayer(source); 
mediaPlayer.addPlayerListener(this); 
mediaPlayer.realize(); 
mediaPlayer.prefetch(); 

开始后,我用mediaPlayer.getDuration返回让周围24:22(在inbuild媒体说黑莓手机中的播放器说文件长度是4:05)

我试图获得听众的持续时间,不幸的是它返回了大约64分钟,所以我确信s omething不是datasoruce内部良好....

代码转换

String getElapsedTimeMinutesSeconds(long elapsedTime) { 
    long Seconds=(elapsedTime/1000)%60; 
    long Minutes=(elapsedTime/(1000*60))%60; 
    long Hours=(elapsedTime/(1000*60*60))%24; 
    return ""+Minutes + ":"+Seconds; 
} 
+0

请发表您的代码,从getDuration()的值转换成你的号码“24:22” - 这可能是有在代码中的错误。 – 2010-03-29 06:59:07

+0

public String getElapsedTimeMinutesSeconds(long elapsedTime){ \t \t long Seconds =(elapsedTime/1000)%60; \t \t长分钟=(elapsedTime /(1000 * 60))%60; \t \t长时间=(elapsedTime /(1000 * 60 * 60))%24; \t \t return“”+ Minutes +“:”+ Seconds; \t} 这里是代码,无论如何也许它不是很好,但我厌倦了与在线转换器转换太多我从媒体播放器getDuration()得到它是definitly不好..所以我搞砸了某个地方else – Alex 2010-03-30 10:33:05

+0

@Alex getDuration()以毫秒为单位返回...不在毫秒内,这是你的错误 – 2012-06-19 11:19:00

回答

1

Player.setMediaTime()和Player.getMediaTime()都指在时间微秒,不毫秒。因此,要得到逝去的秒数,则需要乘以1000000而不只是1000