1、服務器端:html
最近沒有系統學習的計劃,看了開源的YOYOPlayer(一個至關強大的播放器軟件,基於java編寫),內心癢癢,比較膚淺的學習下javasound。
javasound是比較小巧的底層api,引用網上的一幅 javasound體系結構圖:
javasound實現: 目前使用最多的是 jdk中javax.sound組件 (包括javax.sound.sampled 和 javax.sound.midi包) 和 開源的 Tritonus(http://www.tritonus.org/)組件
SPI:是Service Provider Interface(服務提供接口),它的做用是以插件的形式提供音頻擴展模塊。好比,javax.sound組件中,只支持au,mid,wav等少量音頻格式,其中不包括mp3。要想支持mp3格式,那麼就須要相應的×××和SPI。所幸的是,已經有相應的開源包。
javazoom(http://www.javazoom.net)下的jlayer,是mp3格式的解碼包。
javazoom下的mp3spi就是spi。
只要添加了相應的開源組建包,能夠在不修改任何一行代碼的狀況下,支持其餘音頻格式。這就是spi的魅力。
簡單介紹了javasound的體系結構,下面就介紹一個簡易的mp3播放器的實現(所謂簡易,就是沒有界面,除了能播放mp3等文件外,就啥都不能幹了 :) )
幾個步驟:
1)獲得音頻流:html5
AudioSystem.getAudioInputStream(input)java
2)獲得音頻格式:
linux
audioInputStream.getFormat()windows
3)初始化數據行信息
數據行信息包括(受數據行支持的音頻格式;其內部緩衝區的最小和最大大小 )
api
DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);安全
4)從混頻器得到源數據行SourceDataLine
接口提供將音頻數據寫入數據行的緩衝區中的方法。播放或混合音頻的應用程序應該以足夠快的速度將數據寫入源數據行,以防緩衝區下溢(排空),下溢可能致使單擊時音頻數據中出現可感知的間斷
服務器
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);網絡
5)將音頻數據寫入源數據行中ide
line.start();
int readLenth = 0;
while (readLenth != -1) {
readLenth = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
if (readLenth != -1) {
line.write(AUDIO_BUFER, 0, readLenth);
}
}
line.drain();
line.stop();
line.close();
下面提供完整的簡易mp3播放器代碼:
其中AudioPlayer僅僅是一個接口。
/**
* <pre>
* MP3播放器實現
* 線程不安全,沒有必要多個線程去啓動播放器
* </pre>
*
* @author Lee Jones
*/
public class Mp3Player implements AudioPlayer {
private static final Log log = LogFactory.getLog(Mp3Player.class);
private static final byte[] AUDIO_BUFER = new byte[4096];
private AudioInputStream audioStream;
private AudioFormat decodedFormat;
private AudioInputStream decodedAudioStream;
@Override
public void play(InputStream input) {
if (input == null) {
log.warn("input stream is null");
return;
}
try {
init(input);
play();
} catch (Exception e) {
log.error("play error:", e);
}
}
@Override
public void play(File file) {
if (file == null) {
log.warn("audio file is null");
return;
}
try {
play(new FileInputStream(file));
} catch (FileNotFoundException e) {
log.error("file to inputStream error:", e);
}
}
@Override
public void play(URL url) {
if (url == null) {
log.warn("url is null");
return;
}
try {
play(url.openStream());
} catch (IOException e) {
log.error("url open inputStream error:", e);
}
}
/**
* init
*
* @param input
* @throws UnsupportedAudioFileException
* @throws IOException
*/
protected void init(InputStream input) throws UnsupportedAudioFileException, IOException {
initAudioStream(input);
initDecodedFormat();
initDecodedAudioStream();
}
/**
* init audio input stream
*
* @param input:audio input stream
* @throws IOException
* @throws UnsupportedAudioFileException
*/
protected void initAudioStream(InputStream input) throws UnsupportedAudioFileException, IOException {
audioStream = AudioSystem.getAudioInputStream(input);
}
/**
* init decoded format
*
* @throws UnsupportedAudioFileException
* @throws IOException
*/
protected void initDecodedFormat() throws UnsupportedAudioFileException, IOException {
AudioFormat baseFormat = audioStream.getFormat();
decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
baseFormat.getChannels(), baseFormat.getChannels() * 2,
baseFormat.getSampleRate(), false);
}
/**
* init decoded audio stream
*/
protected void initDecodedAudioStream() {
decodedAudioStream = AudioSystem.getAudioInputStream(decodedFormat, audioStream);
}
/**
* get source data line
*
* @param input audio input stream
* @return
* @throws UnsupportedAudioFileException
* @throws IOException
* @throws LineUnavailableException
*/
protected SourceDataLine getSourceDataLine() throws UnsupportedAudioFileException, IOException,
LineUnavailableException {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
line.open(decodedFormat);
return line;
}
/**
* play audio
*
* @throws UnsupportedAudioFileException
* @throws IOException
* @throws LineUnavailableException
*/
protected void play() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
SourceDataLine line = getSourceDataLine();
line.start();
int readLenth = 0;
while (readLenth != -1) {
readLenth = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
if (readLenth != -1) {
line.write(AUDIO_BUFER, 0, readLenth);
}
}
line.drain();
line.stop();
line.close();
decodedAudioStream.close();
audioStream.close();
}
}
本身寫個main方法便可測試 啦啦啦......
public static void main(String[] args) {
Mp3Player mp3Player=new Mp3Player();
String sourcUrl="C:"+File.separator+"879_mp3.mp3";
File file=new File(sourcUrl);
mp3Player.play(file);
}
最後附上簡易播放器:見附件
啓動方式:linux用戶使用./mp3player.sh,windows用戶使用mp3player.bat啓動(須要說明的是,必須設置好JAVA_HOME和PATH,而且使用jdk5以上版本。由於啓動腳本中的指定classpath的方法須要jdk5版本以上才支持。若是是jdk1.4下的用戶,請修改啓動腳本)
lib目錄:是簡易播放器的lib包支持
log目錄:記錄log,若是有錯誤等狀況,可查看log。
conf目錄:由於沒有圖形界面,因此須要把播放的mp3文件路徑手工寫入。支持兩種形式,一個是本地mp3文件,另外一個是網絡mp3資源,分別寫入到local.txt和net.txt文件中。
好比
local.txt
/home/jones/data/music/misc/xin_nian_hao.mp3
/home/jones/data/music/misc/guo_ge.mp3
net.txt
http://lubai.com.cn/CGI-BIN/shuanxing.mp3
http://lubai.com.cn/CGI-BIN/shuanxing.mp3
2、客戶端:
http://translate.google.cn/translate_tts?ie=UTF-8&q=這是要發音的文本&tl=zh-CN&total=1&idx=0&textlen=2&client=t&prev=input
這個URL直接返回你要說的話的MP3文件。播放就能夠了。
html5:支持 <audio autoplay='true'><source src='<%=path%>/MP3/1.mp3' /></audio>