首页 文章

Android - 从 byte [1]播放 mp3

提问于
浏览
31

我有我的 mp3 文件在 byte 2,我想在我的设备上播放它类似于你如何播放文件:

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

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

6 回答

  • 73

    好的,多亏你们所有人,但我需要从 byte [1]播放 mp3,因为我从.NET webservice 那里得到了它(不希望在服务器上存储动态生成的 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 年多前写过这个答案 - 显然很多事情从那时起就发生了变化。请参阅 Justin 关于如何重用 MediaPlayer 实例的评论。此外,我不知道.deleteOnExit()现在是否适合你 - 随意建议改进,以便临时文件不会堆积。

  • 12

    我通过将我的 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());
            }
        }
    
  • 8

    启动 Android MarshMellow(版本代码 23),有新的 API 可以实现这一点。

    MediaPlayer.setDataSource(android.media.MediaDataSource)

    您可以提供 MediaDataSource 的自定义实现并包装一个字节[8]。下面给出的基本实现。

    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
        }
    }
    
  • 5

    不确定 bytearrays/bytestreams,但是如果你有来自服务的 URL,你可以尝试通过调用将数据源设置为网络 URI

    setDataSource(Context context, Uri uri)
    

    API 文档

  • 1

    错误的代码:

    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 演示..

  • 0

    如果您的目标是 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 上面的回答和本文

相关问题