在 java 中播放 Base64 编码的音频文件
Play Base64 encoded audio file in java
----解决方案--------
public class SimpleWavPlayer {
public final static String encoded = "base64 encoded binary that
I previously parsed and outputted then copied here";
public static void main(String[] args)
throws IOException,
InterruptedException,
LineUnavailableException,
UnsupportedAudioFileException {
byte[] decoded = DatatypeConverter.parseBase64Binary(encoded);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
// Wait for clip to finish.
final CountDownLatch latch = new CountDownLatch(1);
song.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
event.getLine().close();
latch.countDown();
}
}
});
latch.await();
}
}
----原题--------
我有一个包含 base64 编码的 mp3 文件的字符串。我想解码那个文件然后播放它。
File file = new File("song.wav");
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
byte[] decoded = Base64.decode(encoded, 0);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(/*what do i do here?*/);
Clip song = /*what do i do here?*/;
song.start;
我现在已经准备好字节数组了。我如何使用这个解码的字节数组来使用 clip 或 audioinputstr
播放音乐
--------编辑 1------------
我用两种不同的做事方式更新了代码。编译和运行,我可以查看编码后的字符串,但是没有声音。而不是使用 FileUtils.readFileToByteArray();我将 Path 和 Paths.get 与 File.readAllBytes() 结合使用。我无法让 FileUtils 工作,因为它要我使用 apacha 库,而我不想使用第 3 方库。我也不知道这是否是重要信息,但我正在使用 pulseaudio 的 archlinux 安装。这是代码。感谢迄今为止的所有帮助。请原谅我懒惰的异常处理。
import java.io.OutputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
//import java.io.*;
//import java.util.Base64.*;
import javax.xml.bind.DatatypeConverter;
import javax.sound.sampled.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import sun.audio.*;
import java.io.*;
public class wavestring {
public static void main(String[] args){
Path path = Paths.get("/home/me/Documents/audiototext/yo.wav");
byte[] bytes = null;
try{
bytes = Files.readAllBytes(path);
}catch(IOException e){
System.out.print("Idk man, something happened man");
}
String encoded = DatatypeConverter.printBase64Binary(bytes);
System.out.println(encoded);
byte[] decoded = DatatypeConverter.parseBase64Binary(encoded);
// Convert byte array to inputStream
InputStream is = new ByteArrayInputStream(decoded);
// // Get AudioInputStream from InputStream
AudioInputStream audioIn = null;
try{
audioIn = AudioSystem.getAudioInputStream(is);
}catch(UnsupportedAudioFileException u){
System.out.println("Well bruh...something happened");
}catch(IOException e){
System.out.println("brooooo");
}
// // Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
/*
//METHOD 3
AudioInputStream audioIn = null;
try{
audioIn = AudioSystem.getAudioInputStream(is);
}catch(UnsupportedAudioFileException u){
System.out.println("Well bruh...something happened");
}catch(IOException e){
System.out.println("brooooo");
}
// // Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
Clip song = null;
try{
song = AudioSystem.getClip();
song.open(audioIn);
}catch(LineUnavailableException l){
}catch(IOException e){
}
song.start();
*/
//METHOD 2
SourceDataLine source_line = null;
try{
source_line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(SourceDataLine.class, format));
source_line.open(format);
}catch(LineUnavailableException l){
System.out.println("yooooooo");
}
byte[] buffer = new byte[524288];
int bytes_read = 0;
while(true){
try{
bytes_read = audioIn.read(buffer);
}catch(IOException e){
System.out.println("idk man");
}
if(bytes_read < 0)
break;
source_line.write(buffer, 0, bytes_read);
}
try{
audioIn.close();
}catch(IOException e){
System.out.println("yooooooooooo man");
}
source_line.drain();
source_line.close();
//METHOD 1
/*DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip song = null;
try{
song = (Clip) AudioSystem.getLine(info);
}catch(LineUnavailableException l){
System.out.println("We were so close but something happened man");
}
song.start();*/
}
}
未经测试,但您可以将其用作指南:
File file = new File("song.wav");
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
byte[] decoded = Base64.decode(encoded, 0);
// Convert byte array to inputStream
InputStream is = new ByteArrayInputStream(decoded);
// Get AudioInputStream from InputStream
AudioInputStream audioIn = AudioSystem.getAudioInputStream(is);
// Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip song = (Clip) AudioSystem.getLine(info);
song.start();
部分基于此:link
您所有问题的答案都在文档中。
首先,让我们看一下documentation for AudioSystem。有五种 getAudioInputStream
方法。两个采用显式 AudioFormat 参数,这些参数不适用于播放 .wav 文件。其余三个方法分别采用 File、InputStream 和 URL。
既然你已经有了一个字节数组,最好的选择是将字节包装在一个ByteArrayInputStream中。现在我们有了一个 InputStream,我们可以将其传递给 getAudioInputStream 方法。
如果您想知道如何获取 Clip 对象,文档再次成为您最好的朋友。如果你去 documentation for Clip, and look at the very top of the page, you'll see a navigation row with several links, including a "USE" link. Follow that link, and you will get a list of all methods in the Java SE API which return a Clip or take a Clip as an argument.
刚好这是一个短名单:截至Java8,只有两个方法,都是静态的,可以return一个Clip。一个采用零参数,而另一个采用显式 Mixer.Info。通常情况下,您只是想通过默认的 Mixer 播放声音,因此只需使用零参数 getClip() 方法来获取新的 Clip。
现在你有了一个剪辑,但它还没有与你的 AudioInputStream 相关联。文档再次为我们提供了帮助。 documentation for AudioSystem.getClip() 状态:
The returned clip must be opened with the open(AudioFormat)
or open(AudioInputStream)
method.
因此,如果我们再次 return 到 Clip documentation,我们会看到两个 open
方法(截至 Java 8)。其中之一将 AudioInputStream 作为其唯一参数。这就是您要使用的那个。
最后,您似乎已经知道,您必须通过调用其继承的 start() 方法来启动剪辑。
现在我们有足够的信息来编写代码了:
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
更新: 以上应该可以播放声音了。这是我为测试它而编写的完整程序:
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.util.concurrent.CountDownLatch;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class SimpleWavPlayer {
public static void main(String[] args)
throws IOException,
InterruptedException,
LineUnavailableException,
UnsupportedAudioFileException {
for (String arg : args) {
Path file = Paths.get(arg);
byte[] decoded = Files.readAllBytes(file);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
// Wait for clip to finish.
final CountDownLatch latch = new CountDownLatch(1);
song.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
event.getLine().close();
latch.countDown();
}
}
});
latch.await();
}
}
}
(代码主要取自 this answer)
要在将文件读入内存后获得 AudioInputStream
,您可以使用:
AudioInputStream audio_in = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
或者,您可以直接从文件中读取。如果文件很大,这可以节省内存(通过不将所有文件一次存储在内存中)。 AudioSystem
有一个方便的方法:
AudioInputStream audio_in = AudioSystem.getAudioInputStream(file);
一旦你有一个 AudioInputStream 可以让你从文件中读取音频,你需要一个 SourceDataLine
让你通过扬声器播放音频。
AudioFormat audio_format = audio_in.getFormat();
SourceDataLine source_line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(SourceDataLine.class, audio_format));
source_line.open(audio_format);
然后您可以从文件中读取音频,并将其发送到扬声器,直到到达文件末尾:
byte[] buffer = new byte[65536]; // the exact size doesn't matter too much; I chose 64 KiB
while(true) {
int bytes_read = audio_in.read(buffer);
if(bytes_read < 0)
break; // end of file reached
source_line.write(buffer, 0, bytes_read);
}
注意SourceDataLine
只会缓冲一定量的数据;一旦缓冲区已满,尝试写入更多数据将阻塞(即让您的程序等待),直到播放完已写入的数据。这意味着上面的循环只有在文件的大部分内容播放完毕后才会结束。
完成后,剩下的就是清理:
audio_in.close();
source_line.drain();
source_line.close();
SourceDataLine.drain
等待线路缓冲的任何数据完成播放。如果不调用,关闭SourceDataLine后文件会立即停止播放,可能会导致最后几秒被截断。
----解决方案--------
public class SimpleWavPlayer {
public final static String encoded = "base64 encoded binary that
I previously parsed and outputted then copied here";
public static void main(String[] args)
throws IOException,
InterruptedException,
LineUnavailableException,
UnsupportedAudioFileException {
byte[] decoded = DatatypeConverter.parseBase64Binary(encoded);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
// Wait for clip to finish.
final CountDownLatch latch = new CountDownLatch(1);
song.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
event.getLine().close();
latch.countDown();
}
}
});
latch.await();
}
}
----原题--------
我有一个包含 base64 编码的 mp3 文件的字符串。我想解码那个文件然后播放它。
File file = new File("song.wav");
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
byte[] decoded = Base64.decode(encoded, 0);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(/*what do i do here?*/);
Clip song = /*what do i do here?*/;
song.start;
我现在已经准备好字节数组了。我如何使用这个解码的字节数组来使用 clip 或 audioinputstr
播放音乐--------编辑 1------------
我用两种不同的做事方式更新了代码。编译和运行,我可以查看编码后的字符串,但是没有声音。而不是使用 FileUtils.readFileToByteArray();我将 Path 和 Paths.get 与 File.readAllBytes() 结合使用。我无法让 FileUtils 工作,因为它要我使用 apacha 库,而我不想使用第 3 方库。我也不知道这是否是重要信息,但我正在使用 pulseaudio 的 archlinux 安装。这是代码。感谢迄今为止的所有帮助。请原谅我懒惰的异常处理。
import java.io.OutputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
//import java.io.*;
//import java.util.Base64.*;
import javax.xml.bind.DatatypeConverter;
import javax.sound.sampled.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import sun.audio.*;
import java.io.*;
public class wavestring {
public static void main(String[] args){
Path path = Paths.get("/home/me/Documents/audiototext/yo.wav");
byte[] bytes = null;
try{
bytes = Files.readAllBytes(path);
}catch(IOException e){
System.out.print("Idk man, something happened man");
}
String encoded = DatatypeConverter.printBase64Binary(bytes);
System.out.println(encoded);
byte[] decoded = DatatypeConverter.parseBase64Binary(encoded);
// Convert byte array to inputStream
InputStream is = new ByteArrayInputStream(decoded);
// // Get AudioInputStream from InputStream
AudioInputStream audioIn = null;
try{
audioIn = AudioSystem.getAudioInputStream(is);
}catch(UnsupportedAudioFileException u){
System.out.println("Well bruh...something happened");
}catch(IOException e){
System.out.println("brooooo");
}
// // Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
/*
//METHOD 3
AudioInputStream audioIn = null;
try{
audioIn = AudioSystem.getAudioInputStream(is);
}catch(UnsupportedAudioFileException u){
System.out.println("Well bruh...something happened");
}catch(IOException e){
System.out.println("brooooo");
}
// // Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
Clip song = null;
try{
song = AudioSystem.getClip();
song.open(audioIn);
}catch(LineUnavailableException l){
}catch(IOException e){
}
song.start();
*/
//METHOD 2
SourceDataLine source_line = null;
try{
source_line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(SourceDataLine.class, format));
source_line.open(format);
}catch(LineUnavailableException l){
System.out.println("yooooooo");
}
byte[] buffer = new byte[524288];
int bytes_read = 0;
while(true){
try{
bytes_read = audioIn.read(buffer);
}catch(IOException e){
System.out.println("idk man");
}
if(bytes_read < 0)
break;
source_line.write(buffer, 0, bytes_read);
}
try{
audioIn.close();
}catch(IOException e){
System.out.println("yooooooooooo man");
}
source_line.drain();
source_line.close();
//METHOD 1
/*DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip song = null;
try{
song = (Clip) AudioSystem.getLine(info);
}catch(LineUnavailableException l){
System.out.println("We were so close but something happened man");
}
song.start();*/
}
}
未经测试,但您可以将其用作指南:
File file = new File("song.wav");
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
byte[] decoded = Base64.decode(encoded, 0);
// Convert byte array to inputStream
InputStream is = new ByteArrayInputStream(decoded);
// Get AudioInputStream from InputStream
AudioInputStream audioIn = AudioSystem.getAudioInputStream(is);
// Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioIn.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip song = (Clip) AudioSystem.getLine(info);
song.start();
部分基于此:link
您所有问题的答案都在文档中。
首先,让我们看一下documentation for AudioSystem。有五种 getAudioInputStream
方法。两个采用显式 AudioFormat 参数,这些参数不适用于播放 .wav 文件。其余三个方法分别采用 File、InputStream 和 URL。
既然你已经有了一个字节数组,最好的选择是将字节包装在一个ByteArrayInputStream中。现在我们有了一个 InputStream,我们可以将其传递给 getAudioInputStream 方法。
如果您想知道如何获取 Clip 对象,文档再次成为您最好的朋友。如果你去 documentation for Clip, and look at the very top of the page, you'll see a navigation row with several links, including a "USE" link. Follow that link, and you will get a list of all methods in the Java SE API which return a Clip or take a Clip as an argument.
刚好这是一个短名单:截至Java8,只有两个方法,都是静态的,可以return一个Clip。一个采用零参数,而另一个采用显式 Mixer.Info。通常情况下,您只是想通过默认的 Mixer 播放声音,因此只需使用零参数 getClip() 方法来获取新的 Clip。
现在你有了一个剪辑,但它还没有与你的 AudioInputStream 相关联。文档再次为我们提供了帮助。 documentation for AudioSystem.getClip() 状态:
The returned clip must be opened with the
open(AudioFormat)
oropen(AudioInputStream)
method.
因此,如果我们再次 return 到 Clip documentation,我们会看到两个 open
方法(截至 Java 8)。其中之一将 AudioInputStream 作为其唯一参数。这就是您要使用的那个。
最后,您似乎已经知道,您必须通过调用其继承的 start() 方法来启动剪辑。
现在我们有足够的信息来编写代码了:
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
更新: 以上应该可以播放声音了。这是我为测试它而编写的完整程序:
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.util.concurrent.CountDownLatch;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class SimpleWavPlayer {
public static void main(String[] args)
throws IOException,
InterruptedException,
LineUnavailableException,
UnsupportedAudioFileException {
for (String arg : args) {
Path file = Paths.get(arg);
byte[] decoded = Files.readAllBytes(file);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(
new ByteArrayInputStream(decoded));
Clip song = AudioSystem.getClip();
song.open(audioIn);
song.start();
// Wait for clip to finish.
final CountDownLatch latch = new CountDownLatch(1);
song.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(LineEvent.Type.STOP)) {
event.getLine().close();
latch.countDown();
}
}
});
latch.await();
}
}
}
(代码主要取自 this answer)
要在将文件读入内存后获得 AudioInputStream
,您可以使用:
AudioInputStream audio_in = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
或者,您可以直接从文件中读取。如果文件很大,这可以节省内存(通过不将所有文件一次存储在内存中)。 AudioSystem
有一个方便的方法:
AudioInputStream audio_in = AudioSystem.getAudioInputStream(file);
一旦你有一个 AudioInputStream 可以让你从文件中读取音频,你需要一个 SourceDataLine
让你通过扬声器播放音频。
AudioFormat audio_format = audio_in.getFormat();
SourceDataLine source_line = (SourceDataLine) AudioSystem.getLine(new DataLine.Info(SourceDataLine.class, audio_format));
source_line.open(audio_format);
然后您可以从文件中读取音频,并将其发送到扬声器,直到到达文件末尾:
byte[] buffer = new byte[65536]; // the exact size doesn't matter too much; I chose 64 KiB
while(true) {
int bytes_read = audio_in.read(buffer);
if(bytes_read < 0)
break; // end of file reached
source_line.write(buffer, 0, bytes_read);
}
注意SourceDataLine
只会缓冲一定量的数据;一旦缓冲区已满,尝试写入更多数据将阻塞(即让您的程序等待),直到播放完已写入的数据。这意味着上面的循环只有在文件的大部分内容播放完毕后才会结束。
完成后,剩下的就是清理:
audio_in.close();
source_line.drain();
source_line.close();
SourceDataLine.drain
等待线路缓冲的任何数据完成播放。如果不调用,关闭SourceDataLine后文件会立即停止播放,可能会导致最后几秒被截断。