1. AudioTrack
1.1 App调用AudioTrack播放音乐
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class AudioPlayerActivity extends AppCompatActivity {
private AudioTrack audioTrack;
private byte[] audioData;
private int bufferSize;
private boolean isPlaying = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_player);
Button playButton = findViewById(R.id.btn_play_audio);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isPlaying) {
isPlaying = true;
playAudio();
} else {
stopAudio();
}
}
});
int sampleRate = 44100; // 采样率
int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; // 立体声输出
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16 位 PCM 编码
① bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
② audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
channelConfig, audioFormat, bufferSize, AudioTrack.MODE_STREAM);
}
private void playAudio() {
try {
File mp3File = new File(Environment.getExternalStorageDirectory(), "sample.mp3");
FileInputStream fileInputStream = new FileInputStream(mp3File);
int length = (int) mp3File.length();
audioData = new byte[length];
fileInputStream.read(audioData, 0, length);
fileInputStream.close();
③ audioTrack.play();
④ audioTrack.write(audioData, 0, length);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Failed to play audio", Toast.LENGTH_SHORT).show();
}
}
private void stopAudio() {
if (isPlaying) {
isPlaying = false;
⑤ audioTrack.stop();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
stopAudio();
⑥ audioTrack.release();
}
}
1.2 AudioTrack.getMinBufferSize()
根据“frameworks/av/services/audiopolicy/common/include/policy.h”中定义,API调用的采样率的范围是400~192000;
1.3 new AudioTrack
AudioTrack的构造用了“建造者模式”的方法,创建了一个AudioTrack实例;
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode, int sessionId)
throws IllegalArgumentException {
// mState already == STATE_UNINITIALIZED
this((new AudioAttributes.Builder())
.setLegacyStreamType(streamType)
.build(),
(new AudioFormat.Builder())
.setChannelMask(channelConfig)
.setEncoding(audioFormat)
.setSampleRate(sampleRateInHz)
.build(),
bufferSizeInBytes,
mode, sessionId);
deprecateStreamTypeForPlayback(streamType, "AudioTrack", "AudioTrack()");
}
1.4 AudioTrack.play()
1.5 AudioTrack.write()
1.6 Audio.stop()
1.7 Audio.release()
2. AudioFlinger
AudioFling和AudioPolicy服务常住于audioserver程序中。
// frameworks/av/media/audioserver/main_audioserver.cpp
int main(int argc __unused, char **argv)
{
// 省略部分代码;
#if 1
// FIXME See bug 165702394 and bug 168511485
const bool doLog = false;
#else
bool doLog = (bool) property_get_bool("ro.test_harness", 0);
#endif
pid_t childPid;
if (doLog && (childPid = fork()) != 0) {
// 省略父进程部分代码;
} else { // 子进程代码;
android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
ProcessState::self()->startThreadPool();
const auto af = sp<AudioFlinger>::make();
const auto afAdapter = sp<AudioFlingerServerAdapter>::make(af);
ALOGD("%s: AudioFlinger created", __func__);
const auto aps = sp<AudioPolicyService>::make();
ALOGD("%s: AudioPolicy created", __func__);
// Start initialization of internally managed audio objects such as Device Effects.
aps->onAudioSystemReady();
// 将 AudioFlinger和AudioPolicy注册到ServiceManager中
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
sm->addService(String16(AudioPolicyService::getServiceName()), aps,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
// 省略部分代码
IPCThreadState::self()->joinThreadPool();
}
}
AudioFlinger涉及的Hal层音频设备交互的接口为DeviceHalInterface,代码位于:frameworks/av/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
(后面再关注这个重点问题)
3. MediaPlayer
MediaPlayer 类可用于控制音频/视频文件和流的播放。MediaPlayer 不是线程安全的,播放器实例的创建和所有访问都应在同一线程上进行。如果要注册回调,线程必须有一个 Looper。
3.1 MediaPlayer()
static {
System.loadLibrary("media_jni");
native_init();
}
这个地方主要是初始化android_media_MediaPlayer.cpp中的相关内容,同步把MediaPlayer.java中与native层的相关回调接口绑定;
private MediaPlayer(Context context, int sessionId) {
// 省略部分代码;
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
try (ScopedParcelState attributionSourceState = attributionSource.asScopedParcelState()) {
native_setup(new WeakReference<>(this), attributionSourceState.getParcel(),
resolvePlaybackSessionId(context, sessionId));
}
baseRegisterPlayer(getAudioSessionId());
}
// 接口位于: frameworks/base/media/java/android/media/PlayerBase.java
/**
* Call from derived class when instantiation / initialization is successful
*/
protected void baseRegisterPlayer(int sessionId) {
try {
// 调用的是AudioService中的trackPlayer()接口
mPlayerIId = getService().trackPlayer(
new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this),
sessionId));
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
}
}
从native层实例化MediaPlayer对象,并注册native层的监听函数;
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jAttributionSource,
jint jAudioSessionId)
{
ALOGV("native_setup");
Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
android::content::AttributionSourceState attributionSource;
attributionSource.readFromParcel(parcel);
/**
* @brief 创建native层的MediaPlayer实例;
* 文件位于: frameworks/av/media/libmedia/mediaplayer.cpp
*/
sp<MediaPlayer> mp = sp<MediaPlayer>::make(
attributionSource, static_cast<audio_session_t>(jAudioSessionId));
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
/**
* @brief create new listener and give it to MediaPlayer
* thiz: jni层的android_media_MediaPlayer
* weak_this: java层的MediaPlayer实例;
* 回调函数: virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
*/
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
setMediaPlayer(env, thiz, mp);
}
3.2 MediaPlayer::create()