2011-12-29 18 views
18

EDIT:Android MediaPlayer hoạt động tốt trong Tuỳ chỉnh ứng dụng Streaming audio lên đến Android 2.1 nhưng không có trong các phiên bản cao hơn

Android 2.2 MediaPlayer is working fine with one SHOUTcast URL but not with the other one

tôi cần phải chơi tập tin âm thanh từ các URL bên ngoài (dòng Shoutcast). Hiện tại, các tệp âm thanh được tải xuống từng bước & được phát ngay sau khi chúng tôi nhận đủ âm thanh trong bộ nhớ tạm thời cục bộ của điện thoại. tôi đang sử dụng số StreamingMediaPlayer class.

Kiểm tra đoạn mã này:

private MediaPlayer createMediaPlayer(File mediaFile) 
      throws IOException { 
     MediaPlayer mPlayer = new MediaPlayer(); 
     //example of mediaFile =/data/data/package/cache/playingMedia0.dat 
     FileInputStream fis = new FileInputStream(mediaFile); 
     mPlayer.setDataSource(fis.getFD()); 
     mPlayer.prepare(); 
     return mPlayer; 
    } 

tình trạng hiện tại:

1- Nó hoạt động tốt từ Android 1,6-2,1 nhưng không có trong các phiên bản cao hơn như Android 2.2.

2- "mPlayer.setDataSource (fis.getFD())" là dòng đưa ra lỗi.

3- lỗi là "Không thể để tạo media player"

Giải pháp khác thử:

tôi đã cố gắng bên dưới giải pháp thay thế nhưng không làm việc cho đến nay.

Android 2.2 MediaPlayer is working fine with one SHOUTcast URL but not with the other one

gì tôi đang tìm kiếm?

Mục tiêu của tôi là có một mã an toàn có thể hoạt động trên Android 2.1 & cao hơn.

Vấn đề này cũng sẽ được thảo luận ở đây:

1- Inconsistent 2.2 Media Player Behavior

2- android code for streaming shoutcast stream breaks in 2.2

3- Vấn đề này cũng được thảo luận trong nhiều câu hỏi trên trang web này, nhưng tôi thấy câu trả lời không đâu.

4- markmail.org

LogCat dấu vết:

Unable to to create media player 
Error copying buffered conent. 
java.lang.NullPointerException 
com.ms.iradio.StreamingMediaPlayer.startMediaPlayer(StreamingMediaPlayer.java:251) 
com.ms.iradio.StreamingMediaPlayer.access$2(StreamingMediaPlayer.java:221) 
com.ms.iradio.StreamingMediaPlayer$2.run(StreamingMediaPlayer.java:204) 
android.os.Handler.handleCallback(Handler.java:587) 
android.os.Handler.dispatchMessage(Handler.java:92) 
android.os.Looper.loop(Looper.java:123) 
android.app.ActivityThread.main(ActivityThread.java:3683) 
java.lang.reflect.Method.invokeNative(Native Method) 
java.lang.reflect.Method.invoke(Method.java:507) 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
dalvik.system.NativeStart.main(Native Method) 
+1

Có lẽ liên kết này sẽ trả lời câu hỏi của bạn và nếu không, vui lòng gửi một dấu vết cho lỗi bạn nhận được: http://stackoverflow.com/questions/3834548/android-code-for-streaming-shoutcast- stream-breaks-in-2-2 – leanne

Trả lời

3

Lớp StreamingMediaPlayer đang sử dụng một kỹ thuật đôi đệm để có được xung quanh những hạn chế trong trước 1.2-phiên bản của Android. Tất cả các phiên bản sản xuất của hệ điều hành Android đã bao gồm một MediaPlayer hỗ trợ streaming media (1). Tôi khuyên bạn nên làm điều đó hơn là sử dụng kỹ thuật đệm đôi này để giải quyết vấn đề.

Hệ điều hành Android 2.2 thay thế mã trình phát phương tiện cũ bằng trình phát FrightCast có thể hoạt động khác trong trường hợp này.

Số dòng trong ngăn xếp ngăn xếp của bạn không ánh xạ tới tệp bạn liên kết đến, vì vậy tôi cho rằng có một phiên bản khác mà bạn đang thực sự sử dụng.Tôi sẽ đoán rằng NullPointerException đang được báo cáo bởi MediaPlayer nhưng không phải FileInputStream cũng không phải trả lại FileDescriptor có thể là null.

(1) Trước phiên bản 2.2, trình phát đa phương tiện sẽ không nhận ra dòng ShoutCast có tiêu đề phiên bản "ICY/1.1" trong phản hồi. Bằng cách tạo proxy thay thế bằng "HTTP/1.1", bạn có thể giải quyết vấn đề đó. Xem ví dụ StreamProxy class here.

+0

1- Tôi đang sử dụng StreamingMediaPlayer chỉ những thay đổi nhỏ đã được thực hiện cho nó. 2- npr lớp StreamProxy đòi hỏi rất nhiều các lớp khác (ví dụ npr tin tức), tôi đã thử nó để sử dụng nó nhưng không thể thành công để làm điều đó một cách chính xác. –

+0

Hmm ... theo dõi ngăn xếp hiển thị dòng 251 trong #startMediaPlayer nhưng trong nguồn được liên kết có dòng là #transferBufferToMediaPlayer. Ngoài ra, StreamProxy từ nguồn NPR không yêu cầu gì từ nguồn NPR, nhưng rất nhiều thứ có trong nguồn Android. [Xem tại đây] (http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/PlaybackService.java#347) cho ví dụ triển khai hoặc [test] (http://code.google.com/p/npr-android-app/source/browse/Npr_Test/src/org/npr/android/news/StreamProxyTest.java). – jwadsack

+0

Rất cảm ơn. tôi sẽ thử nó vào thứ hai. Vui lòng kiểm tra câu hỏi này: http://stackoverflow.com/questions/8681550/android-2-2-mediaplayer-is-working-fine-with-one-shoutcast-url-but-not-with-the –

5

Vấn đề là loại nội dung "âm thanh/aacp" trực tuyến không được hỗ trợ trực tiếp. Một số thư viện giải mã có thể được sử dụng để chơi "aacp", vui lòng xem các giải pháp dưới đây:

Freeware Advanced Audio (AAC) Decoder for Android

How to use this library?

Consider legal issues while using it.

[T] ông dự http://code.google.com/p/aacplayer-android/ được cấp phép dưới GPL, vì vậy bạn có thể tạo các ứng dụng thương mại trên đầu trang của nó, nhưng bạn cần phải fullfill GPL - chủ yếu là nó có nghĩa là để xuất bản mã của bạn như tốt. Nếu bạn sử dụng dự án thứ hai http://code.google.com/p/aacdecoder-android/, thì bạn không cần phải xuất bản mã của mình (thư viện được cấp phép theo LGPL).

+0

giúp tôi tại http://stackoverflow.com/questions/16264225/andriod-shoutcast-internet-radio này -filenotfoundexception – String

1

tôi đang sử dụng mã này và chạy phiên bản 2.2 lên phiên bản cao hơn để phát trực tuyến đã tải xuống.

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.URL; 
import java.net.URLConnection; 

import android.content.Context; 
import android.media.MediaPlayer; 
import android.os.Environment; 
import android.os.Handler; 
import android.util.Log; 
import android.view.View; 
import android.widget.Button; 
import android.widget.ImageButton; 
import android.widget.ProgressBar; 
import android.widget.TextView; 


public class StreamingMediaPlayer { 
private static final int INTIAL_KB_BUFFER = 96*10;//assume 96kbps*10secs/8bits per byte 

private TextView textStreamed; 

private ImageButton playButton; 

private ProgressBar progressBar; 
ProgressBar pb; 
int audiofiletime=0; 
private long mediaLengthInSeconds; 
private int totalKbRead = 0; 
int totalsize=0; 
int numread; 
int totalBytesRead = 0; 
private final Handler handler = new Handler(); 
private MediaPlayer mediaPlayer; 
private File downloadingMediaFile; 
private boolean isInterrupted; 
private Context context; 
private int counter = 0; 

public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton playButton, Button streamButton,ProgressBar progressBar,ProgressBar pb) 
{ 
    this.context = context; 
    this.textStreamed = textStreamed; 
    this.playButton = playButton; 
    this.progressBar = progressBar; 
    this.pb=pb; 
} 

/** 
* Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available. 
*/ 
public void startStreaming(final String mediaUrl) throws IOException { 


    //this.mediaLengthInSeconds = 100; 


    Runnable r = new Runnable() { 
     public void run() { 
      try { 
       downloadAudioIncrement(mediaUrl); 
      } catch (IOException e) { 
       Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e); 
       return; 
      } 
     } 
    }; 
    new Thread(r).start(); 
} 

/** 
* Download the url stream to a temporary location and then call the setDataSource 
* for that local file 
*/ 
@SuppressWarnings({ "resource", "unused" }) 
public void downloadAudioIncrement(String mediaUrl) throws IOException { 

    URLConnection cn = new URL(mediaUrl).openConnection(); 
    cn.connect(); 
    InputStream stream = cn.getInputStream(); 
    if (stream == null) { 
     Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl); 
    } 

    ///////////////////save sdcard/////////////// 
    File direct = new File(Environment.getExternalStorageDirectory()+"/punya"); 

    if(!direct.exists()) { 
     if(direct.mkdir()); //directory is created; 
    } 

    String[] files=mediaUrl.split("/"); 

    String fileName=files[files.length-1]; 
    fileName = fileName.replace(".m4a", ".rdo"); 


    //create a new file, to save the downloaded file 

    File file = new File(direct,fileName); 

    @SuppressWarnings("resource") 
    FileOutputStream fileOutput = new FileOutputStream(file); 

    ///////////////////end///////////////// 

    totalsize=cn.getContentLength(); 

    //mediaLengthInKb = 10000; 

    downloadingMediaFile = new File(context.getCacheDir(),fileName); 

    if (downloadingMediaFile.exists()) { 
     downloadingMediaFile.delete(); 
    } 

    FileOutputStream out = new FileOutputStream(downloadingMediaFile); 
    byte buf[] = new byte[16384]; 
    int incrementalBytesRead = 0; 
    do { 
     numread = stream.read(buf); 
     if (numread <= 0) 
      break; 
     out.write(buf, 0, numread); 
     fileOutput.write(buf, 0, numread); 
     totalBytesRead += numread; 
     incrementalBytesRead += numread; 
     totalKbRead = totalBytesRead/1000; 
     // pb.setMax(100); 
     // pb.setProgress(totalKbRead); 

     testMediaBuffer(); 
     fireDataLoadUpdate(); 
    } while (validateNotInterrupted()); 
    stream.close(); 
    if (validateNotInterrupted()) { 
     fireDataFullyLoaded(); 
    } 
} 

private boolean validateNotInterrupted() { 
    if (isInterrupted) { 
     if (mediaPlayer != null) { 
      mediaPlayer.pause(); 
      //mediaPlayer.release(); 
     } 
     return false; 
    } else { 
     return true; 
    } 
} 


/** 
* Test whether we need to transfer buffered data to the MediaPlayer. 
* Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler. 
*/ 
private void testMediaBuffer() { 
    Runnable updater = new Runnable() { 
     public void run() { 
      if (mediaPlayer == null) { 
       // Only create the MediaPlayer once we have the minimum buffered data 
       if (totalKbRead >= INTIAL_KB_BUFFER) { 
        try { 
         startMediaPlayer(); 
        } catch (Exception e) { 
         Log.e(getClass().getName(), "Error copying buffered conent.", e);    
        } 
       } 
      } else if (mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000){ 
       // NOTE: The media player has stopped at the end so transfer any existing buffered data 
       // We test for < 1second of data because the media player can stop when there is still 
       // a few milliseconds of data left to play 
       transferBufferToMediaPlayer(); 
      } 
     } 
    }; 
    handler.post(updater); 
} 

private void startMediaPlayer() { 
    try { 
     //File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".m4a"); 

     //moveFile(downloadingMediaFile,bufferedFile); 

     // Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath()); 
     // Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+""); 

     mediaPlayer = createMediaPlayer(downloadingMediaFile); 

     //mediaPlayer.start(); 
     startPlayProgressUpdater();   
     //playButton.setEnabled(true); 
     playButton.setVisibility(View.VISIBLE); 
    } catch (IOException e) { 
     Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e); 
     return; 
    } 
} 

private MediaPlayer createMediaPlayer(File mediaFile) 
     throws IOException { 
    MediaPlayer mPlayer = new MediaPlayer(); 
    mPlayer.setOnErrorListener(
      new MediaPlayer.OnErrorListener() { 
       public boolean onError(MediaPlayer mp, int what, int extra) { 
        Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")"); 
        return false; 
       } 
      }); 

    FileInputStream fis = new FileInputStream(mediaFile); 
    mPlayer.setDataSource(fis.getFD()); 
    mPlayer.prepare(); 
    return mPlayer; 
} 

/** 
* Transfer buffered data to the MediaPlayer. 
* NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so 
* this method should always be called using a Handler. 
*/ 
private void transferBufferToMediaPlayer() { 
    try { 

     boolean wasPlaying = mediaPlayer.isPlaying(); 
     int curPosition = mediaPlayer.getCurrentPosition(); 

     File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".m4a"); 
     File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".m4a"); 

     bufferedFile.deleteOnExit(); 
     moveFile(downloadingMediaFile,bufferedFile); 

     //mediaPlayer.pause(); 
     mediaPlayer.release(); 

     mediaPlayer = createMediaPlayer(bufferedFile); 
     mediaPlayer.seekTo(curPosition); 

     boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000; 
     if (wasPlaying || atEndOfFile){ 
      mediaPlayer.start(); 
     } 

     oldBufferedFile.delete(); 

    }catch (Exception e) { 
     Log.e(getClass().getName(), "Error updating to newly loaded content.", e);     
    } 
} 

private void fireDataLoadUpdate() { 
    Runnable updater = new Runnable() { 
     public void run() { 

      //float loadProgress = ((float)totalBytesRead/(float)mediaLengthInKb); 
      //float per = ((float)numread/mediaLengthInKb) * 100; 
      float per = ((float)totalBytesRead/totalsize) * 100; 
      textStreamed.setText((totalKbRead + " Kb (" + (int)per + "%)")); 
      progressBar.setSecondaryProgress((int)(per)); 
      pb.setSecondaryProgress((int)(per)); 

     } 
    }; 
    handler.post(updater); 
} 

private void fireDataFullyLoaded() { 
    Runnable updater = new Runnable() { 
     public void run() { 
      transferBufferToMediaPlayer(); 

      downloadingMediaFile.delete(); 
      textStreamed.setText(("Download completed")); 

     } 
    }; 
    handler.post(updater); 
} 

public MediaPlayer getMediaPlayer() { 
    return mediaPlayer; 
} 

public void startPlayProgressUpdater() { 
    audiofiletime =mediaPlayer.getDuration(); 
    float progress = (((float)mediaPlayer.getCurrentPosition()/ audiofiletime) * 100); 
    progressBar.setProgress((int)(progress)); 
    //pb.setProgress((int)(progress*100)); 

    if (mediaPlayer.isPlaying()) { 
     Runnable notification = new Runnable() { 
      public void run() { 
       startPlayProgressUpdater(); 
      } 
     }; 
     handler.postDelayed(notification,1000); 
    } 
}  

public void interrupt() { 
    playButton.setEnabled(false); 
    isInterrupted = true; 
    validateNotInterrupted(); 
} 

/** 
* Move the file in oldLocation to newLocation. 
*/ 
public void moveFile(File oldLocation, File newLocation) 
     throws IOException { 

    if (oldLocation.exists()) { 
     BufferedInputStream reader = new BufferedInputStream(new FileInputStream(oldLocation)); 
     BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(newLocation, false)); 
     try { 
      byte[] buff = new byte[5461]; 
      int numChars; 
      while ((numChars = reader.read( buff, 0, buff.length)) != -1) { 
       writer.write(buff, 0, numChars); 
      } 
     } catch(IOException ex) { 
      throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath()); 
     } finally { 
      try { 
       if (reader != null){      
        writer.close(); 
        reader.close(); 
       } 
      } catch(IOException ex){ 
       Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath()); 
      } 
     } 
    } else { 
     throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath()); 
    } 
} 
}