2017-03-17 269 views
4

我的数据库有很多格式为base64的短音频。我想在按钮点击时播放音频。基本上,我写了这段代码,但它不起作用。 (如果可能的话,该文件最好不写入存储,因为这个过程有一个延迟)通过解码Base64播放音频

playButton.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 

     try{ 
      String url = "data:audio/mp3;base64,"+base64FormattedString; 
      MediaPlayer mediaPlayer = new MediaPlayer(); 
      mediaPlayer.setDataSource(url); 
      mediaPlayer.prepare(); 
      mediaPlayer.start(); 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 

    } 
}); 

而且堆栈跟踪是在这里:https://gist.github.com/AliAtes/aa46261aba3d755fbbd1eba300356a5f

+0

是什么'“数据:音频/ MP3; BASE64,“'? – pskink

+0

它是base64字符串的音频/ mp3文件的前缀。 base64FormattedString通常没有它。 – ATES

+0

我的意思是它不是'MediaPlayer'视图的有效数据源 - '“路径\t字符串:文件的路径或要播放的流的http/rtsp URL” – pskink

回答

3

有了您的API约束,您可以使用AudioTrack。此外,这很容易。

AudioTrack audioTrack = new AudioTrack(...); 

,并呼吁:

audioTrack.play(); 

然后,你的解码与AudioTrack您可以自API 3.

我们必须用音频样本的特殊性,以初始化您AudioTrack对象播放byte[]音频数据您的Base64数据:

byte[] data = Base64.decode(yourBase64AudioSample, Base64.DEFAULT); 

并把它放在audioTrack回放:

int iRes = audioTrack.write(data, 0, data.length); 

和TADAAA :)

...不要忘记之后播放释放

audioTrack.release(); 
+0

你的代码是完美的,它正在工作,但我没有适应我的mp3到'AudioTrack();'正确。我需要最后的帮助:)(这是MP3的所有信息:https://gist.github.com/AliAtes/be72817aa0ebea45acd6ef6840c279b1) – ATES

+0

明天我会看到。在播放之前,您可能必须解码MP3文件! – N0un

+0

经过一番研究,似乎'AudioTrack'只支持PCM(非压缩音频格式),而mp3则是压缩音频格式。解决方案是在播放前解码它。使用这个链接你有一个使用'JLayer'的例子:http://mindtherobot.com/blog/624/android-audio-play-an-mp3-file-on-an-audiotrack/ – N0un

1

您应该能够通过扩展MediaDataSource实现这一目标并以它作为参数调用setDataSource

也许尝试是这样的:在实施MediaDataSource

// first decode the data to bytes 
byte[] data = Base64.decode(base64FormattedString, Base64.DEFAULT); 
mediaPlayer.setDataSource(new MediaDataSource() { 
    @Override 
    public long getSize() { 
     return data.length; 
    } 

    @Override 
    public int readAt(long position, byte[] buffer, int offset, int size) { 
     int length = getSize(); 
     if (position >= length) return -1; // EOF 
     if (position + size > length) // requested more than available 
      size = length - position; // set size to maximum size possible 
             // at given position 

     System.arraycopy(data, (int) position, buffer, offset, size); 
     return size; 
    } 

    @Override 
    public synchronized void close() throws IOException { 

    } 
}); 

欲了解更多信息,你可以检查出this article

编辑:此方法需要23作为API级别。在23之前,似乎几乎不可能提供从byte[](或除URL或文件之外的任何内容)播放的数据。我发现的唯一的东西是this answer,它提供了与问题中所示相同的代码。

编辑2:N0un在他的评论和answer中指出,通过使用AudioTrack而不是MediaPlayer,API level 3是可能的。

+0

感谢您的代码,但'MediaDataSource' api等级为23.我的项目api为19,所以有可能您计划没有'MediaDataSource'的代码? – ATES

+1

我做了一些更多的研究,似乎不可能在没有'MediaDataSource'的情况下从'byte []'提供数据。我发现的唯一的东西是[这个答案](http://stackoverflow.com/a/39023706/5189673),但是因为它提供了相同的代码,所以它显然不适合你。如果你想坚持19作为你的API级别,你可以采用创建文件的方法(可能会提早创建文件,例如,当应用程序第一次启动时,并检查是否有助于延迟)。另一种选择是切换到23作为您的API级别。 – Leon

+0

是的,它可能是“23岁以前的API”。事实上,从API 3开始是可能的:)看到我的回答:这是我用于我的应用程序的方式(它播放通过使用此方法的网络接收的'byte []'数据,所以我确认它是有效的)。 – N0un