/********************************************************************************************
* author:conowen@大钟
* E-mail:conowen@hotmail.com
* http://blog.csdn.net/conowen
* 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。
********************************************************************************************/
1、Android AudioTrack简介
在Android中播放声音可以用MediaPlayer和AudioTrack两种方案的,但是两种方案是有很大区别的,MediaPlayer可以播放多种格式的声音文件,例如MP3,AAC,WAV,OGG,MIDI等。而AudioTrack只能播放PCM数据流。
事实上,两种本质上是没啥区别的,MediaPlayer在播放音频时,在framework层还是会创建AudioTrack,把解码后的PCM数流传递给AudioTrack,最后由AudioFlinger进行混音,传递音频给硬件播放出来。利用AudioTrack播放只是跳过Mediaplayer的解码部分而已。Mediaplayer的解码核心部分是基于OpenCORE 来实现的,支持通用的音视频和图像格式,codec使用的是OpenMAX接口来进行扩展。因此使用audiotrack播放mp3文件的话,要自己加入一个音频解码器,如libmad。否则只能播放PCM数据,如大多数WAV格式的音频文件。
参考上一篇博文。
http://blog.csdn.net/conowen/article/details/7727145
2、使用Mediaplayer的不足
MediaPlayer提供了5个setDataSource方法,如其中一个,虽然可以设置文件流起始地址与文件流长度。
public void setDataSource(FileDescriptor fd, long offset, long length)
Sets the data source (FileDescriptor) to use. The FileDescriptor must be seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility to close the file descriptor. It is safe to do so as soon as this call returns.
Parameters
fd
the FileDescriptor for the file you want to play |
offset
the offset into the file where the data to be played starts, in bytes |
length
the length in bytes of the data to be played |
|
但是对于实时地播放加密过的音频文件却是束手无策。虽然对于一些加密过的音频文件,可以采用Audiotrack与Libmad结合的方式解决。
3、简单Demo程序
下面提供一个Audiotrack播放mp3的demo,mp3没有经过加密的,解码部分是由libmad完成。(若是要播放加密音频文件,可以操作的libmad解码文件流即可。)
直接贴代码,代码的大意已经在注释说明了。


@LibmadActivity.java
/*
* author:conowen
* date:2012.7.29
*/
package com.conowen.libmad;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class LibmadActivity extends Activity {
private Thread mThread;
private short[] audioBuffer;
private AudioTrack mAudioTrack;
private Button btnPlay, btnPauseButton;
private int samplerate;
private int mAudioMinBufSize;
private int ret;
private NativeMP3Decoder MP3Decoder;
private boolean mThreadFlag;
private String filePath = "/sdcard/test.mp3";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnPlay = (Button) findViewById(R.id.buttonPlay);
btnPauseButton = (Button) findViewById(R.id.buttonPause);
MP3Decoder = new NativeMP3Decoder();
ret = MP3Decoder.initAudioPlayer(filePath, 0);
if (ret == -1) {
Log.i("conowen", "Couldn't open file '" + filePath + "'");
} else {
mThreadFlag = true;
initAudioPlayer();
audioBuffer = new short[1024 * 1024];
mThread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (mThreadFlag) {
if (mAudioTrack.getPlayState() != AudioTrack.PLAYSTATE_PAUSED) {
// ****从libmad处获取data******/
MP3Decoder.getAudioBuf(audioBuffer,
mAudioMinBufSize);
mAudioTrack.write(audioBuffer, 0, mAudioMinBufSize);
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
});
mThread.start();
}
btnPlay.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (ret == -1) {
Log.i("conowen", "Couldn't open file '" + filePath + "'");
Toast.makeText(getApplicationContext(),
"Couldn't open file '" + filePath + "'",
Toast.LENGTH_SHORT).show();
} else {
if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_STOPPED) {
//mThreadFlag = true;// 音频线程开始
mAudioTrack.play();
// mThread.start();
} else if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
//mThreadFlag = true;// 音频线程开始
mAudioTrack.play();
} else {
Toast.makeText(getApplicationContext(),
"Already in play", Toast.LENGTH_SHORT).show();
}
}
}
});
btnPauseButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (ret == -1) {
Log.i("conowen", "Couldn't open file '" + filePath + "'");
Toast.makeText(getApplicationContext(),
"Couldn't open file '" + filePath + "'",
Toast.LENGTH_SHORT).show();
} else {
if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
mAudioTrack.pause();
} else {
Toast.makeText(getApplicationContext(), "Already stop",
Toast.LENGTH_SHORT).show();
}
}
}
});
}
private void initAudioPlayer() {
// TODO Auto-generated method stub
samplerate = MP3Decoder.getAudioSamplerate();
System.out.println("samplerate = " + samplerate);
samplerate = samplerate / 2;
// 声音文件一秒钟buffer的大小
mAudioMinBufSize = AudioTrack.getMinBufferSize(samplerate,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, // 指定在流的类型
// STREAM_ALARM:警告声
// STREAM_MUSCI:音乐声,例如music等
// STREAM_RING:铃声
// STREAM_SYSTEM:系统声音
// STREAM_VOCIE_CALL:电话声音
samplerate,// 设置音频数据的采样率
AudioFormat.CHANNEL_CONFIGURATION_STEREO,// 设置输出声道为双声道立体声
AudioFormat.ENCODING_PCM_16BIT,// 设置音频数据块是8位还是16位
mAudioMinBufSize, AudioTrack.MODE_STREAM);// 设置模式类型,在这里设置为流类型
// AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。
// STREAM方式表示由用户通过write方式把数据一次一次得写到audiotrack中。
// 这种方式的缺点就是JAVA层和Native层不断地交换数据,效率损失较大。
// 而STATIC方式表示是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,
// 后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。
// 这种方法对于铃声等体积较小的文件比较合适。
}
static {
System.loadLibrary("mad");
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mAudioTrack.stop();
mAudioTrack.release();// 关闭并释放资源
mThreadFlag = false;// 音频线程暂停
MP3Decoder.closeAduioFile();
}
}
@NativeMP3Decoder.java
package com.conowen.libmad;
public class NativeMP3Decoder {
private int ret;
public NativeMP3Decoder() {
}
public native int initAudioPlayer(String file,int StartAddr);
public native int getAudioBuf(short[] audioBuffer, int numSamples);
public native void closeAduioFile();
public native int getAudioSamplerate();
}
@main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="AudioTrack"
/>
<Button
android:id = "@+id/buttonPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PLAY"
/>
<Button
android:id = "@+id/buttonPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PAUSE"
/>
</LinearLayout>
分享到:
相关推荐
本文将深入探讨Android多媒体开发的高级编程技术,并基于提供的资源——"Android多媒体开发高级编程及源码",来解析相关知识点。 1. **Android多媒体框架** Android系统提供了一个强大的多媒体框架,包括...
1. **Android多媒体框架**:MP3播放器的核心是Android的多媒体框架,包括`MediaPlayer`类,用于播放音频文件。开发者需要理解如何初始化`MediaPlayer`,加载MP3文件,控制播放(如播放、暂停、停止、跳转)以及处理...
在Android平台上,开发一款音乐播放应用需要深入理解操作系统与多媒体框架的交互,以及Android SDK提供的相关API。这个"Android源码——音乐播放源码.zip"压缩包可能包含了一个完整的音乐播放器项目的源代码,这对于...
1. **Android多媒体框架**: - **MediaPlayer**:Android提供的基本音频播放组件,用于播放音频文件。它可以处理各种音频格式,包括MP3。开发者需要熟练配置MediaPlayer,设置播放、暂停、停止等操作,并监听播放...
在安卓平台上,开发一款能处理视音频播放的应用是一项常见的任务,而深入理解源码是提升开发者技能的关键。这个“安卓Android源码——安卓视音频播放测试工程”压缩包提供了宝贵的资源,帮助开发者学习如何在Android...
这个压缩包“安卓Android源码——安卓视音频播放测试工程.zip”包含了用于测试和学习的源码,特别针对音视频播放的功能。以下是对该工程中可能涉及的知识点的详细解释: 1. **MediaPlayer类**:Android系统提供的...
本资源"安卓Android源码——语音压缩,android开发语音功能较多使用的时候,压缩大小50%"提供了一种实现语音压缩的方法,主要目标是减小音频文件的大小,以优化存储和传输效率。下面将详细讨论与这个主题相关的知识...
MSD音乐播放器利用了AudioTrack类进行音频播放,通过MediaPlayer或ExoPlayer组件来管理音频资源。 3. **音频解码** 音频文件通常需要解码才能在设备上播放。MSD音乐播放器可能使用了Android的MediaCodec服务,支持...
这个Android源码项目是一个MP3播放器,特别之处在于它具备了卡拉OK字幕功能,这对于...以上是针对该MP3播放器源码项目的主要技术点,通过学习和实践这些知识点,开发者可以提升在Android平台上的多媒体应用开发能力。
5. **多媒体文件的分类和管理**:软件可能需要对铃声进行分类,比如按类型(音乐、通知、闹钟)或者按文件格式(MP3、AAC等)。这可能涉及到文件系统的操作,以及对音频元数据的解析。 6. **通知与意图(Intent)**...
这个压缩包“安卓Android源码——rockplayer播放器源码.zip”提供了RockPlayer的部分源代码,这对于开发者来说是一份宝贵的资源,可以深入理解Android多媒体播放器的实现原理,提升自己的开发技能。 首先,让我们...
通过分析这个仿QQ音乐播放器的源码,开发者可以了解到Android音频播放的最佳实践,提升对Android多媒体处理、服务管理、UI设计等多方面的能力。同时,这也是一个很好的学习如何集成第三方库(如音乐流服务API)和...
通过分析这个源码,开发者可以学习如何集成上述功能,理解Android多媒体编程的细节,以及如何构建一个高效、用户友好的音乐播放应用。此外,对于有经验的开发者,源码还可以作为扩展功能的起点,如添加在线音乐流、...
【标题】: "安卓Android源码——改进10-yannihui(音乐播放器).zip" 涵盖了Android应用程序开发中的多个关键知识点,主要集中在音乐播放器的实现上。这个项目可能是一个由开发者yannihui改进的音乐播放器应用,用于...
在安卓(Android)平台上,开发一个视音频播放测试工程涉及到许多关键知识点,这些知识点涵盖了操作系统、多媒体处理、软件架构等多个领域。在这个“安卓Andriod源码——安卓视音频播放测试工程”中,我们可以深入...
"tewilove-faplayer"项目是一个基于Android平台的音频播放器源码,它为我们提供了一个研究和学习Android多媒体处理的实例。接下来,我们将围绕这个项目展开讨论,深入探讨Android源码的相关知识点。 1. **多媒体...
- **多媒体文件解析**:查看 Apollo 如何读取和解析 MP3、AAC 等不同格式的音频文件。 - **权限管理**:学习如何处理播放、存储和网络访问相关的 Android 权限。 4. **优化与扩展** - 音频缓存策略:提高加载...
这份源码集合涵盖了音频、视频播放、录制以及图像处理等多个方面,对于想要深入学习Android多媒体开发的程序员来说,是一份宝贵的参考资料。 1. 音频处理 在MultiMediaSamples中,音频相关的示例展示了如何使用...
在Android中,AudioTrack API用于播放音频数据,而AudioRecord API则用于录制。这些API允许开发者进行低级别的音频操作,如调整音量、添加特效、实时混音等。项目中的音频示例可能包含了如何创建播放器和录音机,...
本文将深入探讨一个基于Android平台的架子鼓模拟器——“drums”,它利用Java编程语言实现了一个功能完善的鼓模拟器,为用户提供了一种新颖且便捷的音乐创作方式。 1. **Android 音乐应用开发基础** 在Android平台...