Android - 从字节播放 mp3[]

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1972027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:59:44  来源:igfitidea点击:

Android - Playing mp3 from byte[]

androidbytearraymp3audio-player

提问by nikib3ro

I have my mp3 file in byte[] (downloaded from an service) and I would like to play it on my device similar to how you can play files:

我在 byte[] 中有我的 mp3 文件(从服务下载),我想在我的设备上播放它,类似于播放文件的方式:

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

But I can't seem to find a way to do it. I wouldn't mind saving file to phone and then playing it. How can I play the file, or download then play it?

但我似乎找不到办法做到这一点。我不介意将文件保存到手机然后播放。如何播放文件,或下载然后播放?

回答by nikib3ro

OK, thanks to all of you but I needed to play mp3 from byte[] as I get that from .NET webservice (don't wish to store dynamically generated mp3s on server).

好的,谢谢大家,但我需要从 byte[] 播放 mp3,因为我从 .NET webservice 得到它(不想在服务器上存储动态生成的 mp3)。

In the end - there are number of "gotchas" to play simple mp3... here is code for anyone who needs it:

最后 - 有许多“问题”可以播放简单的 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();
    }
}

EDIT:I've wrote this answer more than 4 years ago - obviously lots of things have changed since then. See Justin's comment on how to reuse MediaPlayer instance. Also, I don't know if .deleteOnExit() will work for you now - feel free to suggest improvement so that temp files do not pile up.

编辑:我在 4 年前写了这个答案 - 显然从那时起很多事情都发生了变化。请参阅 Justin 关于如何重用 MediaPlayer 实例的评论。另外,我不知道 .deleteOnExit() 现在是否适合您 - 请随时提出改进建议,以免临时文件堆积。

回答by Max Vargas

I found an easy solution by encoding my MP3 file as Base64 (I already receive the data encoded from a Restful API service), and then creating a URL object. I tested it in Android 4.1.

我找到了一个简单的解决方案,将我的 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());
        }
    }

回答by krishnakumarp

Starting Android MarshMellow (Version Code 23), there is new API that will make this possible.

从 Android MarshMellow(版本代码 23)开始,有新的 API 使这成为可能。

MediaPlayer.setDataSource(android.media.MediaDataSource)

MediaPlayer.setDataSource(android.media.MediaDataSource)

You can provide a custom implementation of MediaDataSource and wrap a byte[]. A basic implementation given below.

您可以提供 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
    }
}

回答by Yoni Samlan

Not sure about bytearrays/bytestreams, but if you have a URL from the service, you can try setting the data source to a network URI by calling

不确定字节数组/字节流,但如果您有来自服务的 URL,则可以尝试通过调用将数据源设置为网络 URI

setDataSource(Context context, Uri uri)

See the API docs.

请参阅API 文档

回答by Dan Alboteanu

If you target API 23 and above, create a class like this

如果您的目标是 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() {}

}

and use like this

并像这样使用

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

credits to krishnakumarp's answer above and to this article

归功于上面 krishnakumarp 的回答和这篇文章

回答by subbarao

wrong code:

错误代码:

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

CORRECT CODE:

正确的代码:

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

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

see API Demos ..

见 API 演示 ..