stone2083

java mp3播放器

最近没有系统学习的计划,看了开源的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)得到音频流:
AudioSystem.getAudioInputStream(input)
2)得到音频格式:
audioInputStream.getFormat()
3)初始化数据行信息
数据行信息包括(受数据行支持的音频格式;其内部缓冲区的最小和最大大小 )
DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);
4)从混频器获得源数据行
SourceDataLine 接口提供将音频数据写入数据行的缓冲区中的方法。播放或混合音频的应用程序应该以足够快的速度将数据写入源数据行,以防缓冲区下溢(排空),下溢可能导致单击时音频数据中出现可感知的间断
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
5)将音频数据写入源数据行中
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();
    }
}


最后附上简易播放器:
easy mp3 player

启动方式: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

因多媒体方向非自己的工作方向,所以了解的相当肤浅。有兴趣的朋友请多多指教。

posted on 2008-02-17 21:19 stone2083 阅读(5843) 评论(6)  编辑  收藏 所属分类: java

Feedback

# re: java mp3播放器 2009-04-28 17:32 wscool

谢谢啊,虽然简单但对初学者是非常有帮助的……  回复  更多评论   

# re: java mp3播放器 2011-05-15 20:45 zechou

必须加支持MP3的SPI?  回复  更多评论   

# re: java mp3播放器 2011-05-16 12:55 stone2083

@zechou
是的。需要第三方服务提供。  回复  更多评论   

# re: java mp3播放器 2011-11-12 21:49 fangtest

你的这个给力 谢谢楼主  回复  更多评论   

# re: java mp3播放器 2014-12-15 19:08 lousongtao

楼主能不能研究下, 如何调整播放MP3的速度, 我搞了一天也没搞懂  回复  更多评论   

# re: java mp3播放器 2014-12-16 13:17 stone2083

@lousongtao
音频文件是将模拟信号采样转成的数字信号. 把每一秒钟所采样的数目称为采样频率或采率. 也就是说, 声音的速度是一定的,取决于模拟信号.
比特率 = 每秒采样数量 (hz) × 位深(bit) × 声道数量
位速是指在一个数据流中每秒钟能通过的信息量

从理论上说, 增加位速, 就可以实现快速播放的效果.
至于api上怎么使用, 我也不知道, 你可以顺着这个思路,再看看.
  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: