web-dev-qa-db-ja.com

Android MediaPlayerは、カスタムオーディオストリーミングアプリケーションでAndroid 2.1までは正常に動作しますが、それ以降のバージョンでは動作しません

編集:

Android 2.2 MediaPlayerは、一方のSHOUTcast URLでは正常に動作しますが、もう一方のURLでは動作しません

外部URL(shoutcastストリーム)からオーディオファイルを再生する必要があります。現在、オーディオファイルは段階的にダウンロードされ、電話のローカル一時ストレージに十分なオーディオが入るとすぐに再生されます。 StreamingMediaPlayerクラス を使用しています。

このコードを確認してください。

    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;
    }

現在のステータス:

1- Android 1.6から2.1までは正常に動作しますが、Android 2.2などの上位バージョンでは動作しません。

2-「mPlayer.setDataSource(fis.getFD())」はエラーをスローする行です。

3-エラーは「メディアプレーヤーを作成できません」です

他の解決策を試しました:

私は以下の代替ソリューションを試しましたが、今のところ何も機能しませんでした。

Android 2.2 MediaPlayerは、一方のSHOUTcast URLでは正常に動作しますが、もう一方のURLでは動作しません

私が探しているものは?

私の目標は、Android 2.1以降で動作するコードの平和を実現することです。

この問題についてもここで説明します:

1- 一貫性のない2.2メディアプレーヤーの動作

2- 2.2でshoutcastストリームブレークをストリーミングするためのAndroidコード

3-この問題は、このサイトの多くの質問でも議論されていますが、どこにも答えが見つかりませんでした。

4- markmail.org

LogCatトレース:

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)
19
Yaqub Ahmad

StreamingMediaPlayerクラスは、ダブルバッファリング技術を使用して、Androidの1.2より前のリリースの制限を回避しています。 Android OSのすべての製品リリースにはストリーミングメディアをサポートするMediaPlayerが含まれています(1)。この問題を回避するためにこのダブルバッファリング手法を使用するのではなく、これを行うことをお勧めします。

Android OS 2.2は、古いメディアプレーヤーコードをFrightCastプレーヤーに置き換えました。この場合、おそらく動作が異なります。

スタックトレースの行番号は、リンク先のファイルにマップされていないため、実際に使用しているバージョンが異なると思います。 NullPointerExceptionMediaPlayerによって報告されていると推測しますが、FileInputStreamも返されるFileDescriptornullにすることはできません。 。

(1)バージョン2.2より前では、メディアプレーヤーは応答に「ICY /1.1」バージョンヘッダーが含まれるShoutCastストリームを認識しませんでした。これを「HTTP/1.1」に置き換えるプロキシを作成することで、それを解決できます。例については、 ここではStreamProxyクラス を参照してください。

3
jwadsack

問題は、コンテンツタイプ「audio/aacp」ストリーミングが直接サポートされていないことです。一部のデコードライブラリを使用して「aacp」を再生できます。以下の解決策を参照してください。

Android用Freeware Advanced Audio(AAC)デコーダー

このライブラリの使い方は?

使用中に法的な問題を検討してください

[T]彼のプロジェクト http://code.google.com/p/aacplayer-Android/ はGPLの下でライセンスされているので、その上に商用アプリを作成できますが、 GPL-主にそれはあなたのコードも公開することを意味します。 2番目のプロジェクトを使用する場合 http://code.google.com/p/aacdecoder-Android/ 、コードを公開する必要はありません(ライブラリはLGPLの下でライセンスされています)。

5
Yaqub Ahmad

私はこのコードを使用しており、ダウンロードしたストリーミング用に2.2から上位バージョンまで実行しています。

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() );
    }
}
}
1
Punya