web-dev-qa-db-ja.com

Android-byte []からmp3を再生

Byte [](サービスからダウンロード)にmp3ファイルがあり、ファイルを再生する方法と同じようにデバイスで再生したいと思います。

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();

しかし、私はそれを行う方法を見つけることができないようです。ファイルを電話に保存してから再生してもかまいません。ファイルを再生、またはダウンロードして再生するにはどうすればよいですか?

32
nikib3ro

皆さん、ありがとうございます。ただし、byte []からmp3を再生する必要がありました。これは.NET Webサービスから取得するためです(動的に生成されたmp3をサーバーに保存したくない)。

最後に-シンプルなmp3を再生するための「落とし穴」がいくつかあります...これが必要な人のためのコードです:

private MediaPlayer mediaPlayer = new MediaPlayer();
private void playMp3(byte[] mp3SoundByteArray) {
    try {
        // create temp file that will hold byte array
        File tempMp3 = File.createTempFile("kurchina", "mp3", getCacheDir());
        tempMp3.deleteOnExit();
        FileOutputStream fos = new FileOutputStream(tempMp3);
        fos.write(mp3SoundByteArray);
        fos.close();

        // resetting mediaplayer instance to evade problems
        mediaPlayer.reset();

        // In case you run into issues with threading consider new instance like:
        // MediaPlayer mediaPlayer = new MediaPlayer();                     

        // Tried passing path directly, but kept getting 
        // "Prepare failed.: status=0x1"
        // so using file descriptor instead
        FileInputStream fis = new FileInputStream(tempMp3);
        mediaPlayer.setDataSource(fis.getFD());

        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException ex) {
        String s = ex.toString();
        ex.printStackTrace();
    }
}

編集:私は4年以上前にこの答えを書いてきました-それから明らかに多くのことが変わっています。 MediaPlayerインスタンスを再利用する方法に関するJustinのコメントを参照してください。また、.deleteOnExit()が今あなたのために働くかどうかはわかりません-一時ファイルが積み重ならないように改善を提案してください。

73
nikib3ro

MP3ファイルをBase64としてエンコードし(Restful APIサービスからエンコードされたデータを既に受信しています)、URLオブジェクトを作成することで簡単なソリューションを見つけました。 Android 4.1でテストしました。

public void PlayAudio(String base64EncodedString){
        try
        {
            String url = "data:audio/mp3;base64,"+base64EncodedString; 
            MediaPlayer mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(url);
            mediaPlayer.prepare();
            mediaPlayer.start();
        }
        catch(Exception ex){
            System.out.print(ex.getMessage());
        }
    }
14
Max Vargas

Android MarshMellow(バージョンコード23)から、これを可能にする新しいAPIがあります。

MediaPlayer.setDataSource(Android.media.MediaDataSource)

MediaDataSourceのカスタム実装を提供し、byte []をラップできます。以下に示す基本的な実装。

import Android.annotation.TargetApi;
import Android.media.MediaDataSource;
import Android.os.Build;
import Java.io.IOException;


@TargetApi(Build.VERSION_CODES.M)
public class ByteArrayMediaDataSource extends MediaDataSource {

    private final byte[] data;

    public ByteArrayMediaDataSource(byte []data) {
        assert data != null;
        this.data = data;
    }
    @Override
    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
        System.arraycopy(data, (int)position, buffer, offset, size);
        return size;
    }

    @Override
    public long getSize() throws IOException {
        return data.length;
    }

    @Override
    public void close() throws IOException {
        // Nothing to do here
    }
}
10
krishnakumarp

Bytearrays/bytestreamsについてはわかりませんが、サービスからのURLがある場合は、次を呼び出してネットワークURIにデータソースを設定してみてください。

setDataSource(Context context, Uri uri)

APIドキュメント を参照してください。

5
Yoni Samlan

不正なコード:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.prepare();
 mp.start();

正しいコード:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.setOnpreparedListener(this);
 mp.prepare();

//Implement OnPreparedListener 
OnPrepared() {
    mp.start();
 }

aPIデモを参照してください。

1
subbarao

API 23以降をターゲットとする場合、次のようなクラスを作成します

class MyMediaDataSource(val data: ByteArray) : MediaDataSource() {

override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int {

    if (position >= data.size) return -1 // -1 indicates EOF 

    val endPosition: Int = (position + size).toInt()
    var size2: Int = size
    if (endPosition > data.size)
        size2 -= endPosition - data.size

    System.arraycopy(data, position.toInt(), buffer, offset, size2)
    return size2
}

override fun getSize(): Long {
    return data.size.toLong()
}

override fun close() {}

}

そして、このように使用します

val mediaSource = MyMediaDataSource(byteArray)
MediaPlayer().apply {
    setAudioStreamType(AudioManager.STREAM_MUSIC)
    setDataSource(mediaSource)
    setOnCompletionListener { release() }
    prepareAsync()
    setOnPreparedListener { start() }
}

上記のkrishnakumarpの回答と この記事

1
Dan Alboteanu