以下为笔记,如有错误请指正。
基于android-9.0.0_r46(aosp)
创建一个简单的APK,播放本地音乐。
使用MediaPlayer播放一个Audio
if (mPlayer == null) {
mPlayer = MediaPlayer.create(getContext(), R.raw.lang);
}
mPlayer.start();
create方式不需要prepare
APK中使用 MediaPlayer.create(…) 创建player示例,所以进入MediaPlayer分析:
/frameworks/base/media/java/android/media/MediaPlayer.java
通过log发现调用的是:
public static MediaPlayer create(Context context, int resid) {
int s = AudioSystem.newAudioSessionId();
return create(context, resid, null, s > 0 ? s : 0);
}
上文中函数int s = AudioSystem.newAudioSessionId();
,通过 base/media/java/android/media/AudioSystem.java 中的public static native int newAudioSessionId();
调用 base/core/jni/android_media_AudioSystem.cpp 中的newAudioSessionId
函数。
继续往下:
public static MediaPlayer create(Context context, int resid, AudioAttributes audioAttributes, int audioSessionId) {
try {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
if (afd == null) return null;
MediaPlayer mp = new MediaPlayer();
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
mp.setAudioAttributes(aa);
mp.setAudioSessionId(audioSessionId);
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
mp.prepare();
return mp;
}
...
return null;
}
其中有初始化对象MediaPlayer mp = new MediaPlayer()
动作:
public MediaPlayer() {
super(new AudioAttributes.Builder().build(),
AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
mTimeProvider = new TimeProvider(this);
mOpenSubtitleSources = new Vector<InputStream>();
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
native_setup(new WeakReference<MediaPlayer>(this)); // native 方法
baseRegisterPlayer();
}
既然natvie_setup() 是 native方法,那么肯定有.so库的加载:
static {
System.loadLibrary("media_jni");
native_init();
}
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
查资料得知,System.loadLibrary("…") 的时候会调用 JNI_OnLoad() 函数:
参考:
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (register_android_media_ImageWriter(env) != JNI_OK) {
ALOGE("ERROR: ImageWriter native registration failed");
goto bail;
}
...... //initialize
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
继续往下走会调用native_init()方法:
{"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in MediaPlayer, which won't run until the
// first time an instance of this class is used.
static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
jclass clazz;
...... // Initialization of some variables
gBufferingParamsFields.init(env);
// Modular DRM
FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
if (clazz) {
GET_METHOD_ID(gStateExceptionFields.init, clazz, "" , "(ILjava/lang/String;)V");
gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
env->DeleteLocalRef(clazz);
} else {
ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
"get clazz android/media/MediaDrm$MediaDrmStateException");
}
gPlaybackParamsFields.init(env);
gSyncParamsFields.init(env);
gVolumeShaperFields.init(env);
}
native_init运行完成,回到 native_setup(…) 中:
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
sp<MediaPlayer> mp = new MediaPlayer();
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
// create new listener and give it to MediaPlayer
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);
}
其中初始化MediaPlayer对象 sp mp = new MediaPlayer(); 调用的是:
/frameworks/av/media/libmedia/mediaplayer.cpp
MediaPlayer::MediaPlayer()
{
ALOGV("constructor");
mListener = NULL;
mCookie = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
mAudioAttributesParcel = NULL;
mCurrentPosition = -1;
mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mCurrentState = MEDIA_PLAYER_IDLE;
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
mSendLevel = 0;
mRetransmitEndpointValid = false;
}
至此,初始化动作基本完成。
回到MediaPlayer.create函数中,调用了 mp.setDataSource(…),即:
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
_setDataSource(fd, offset, length); //是个native方法
}
private native void _setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException;
然后在 android_media_MediaPlayer.cpp :
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
......
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
...
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
ALOGV("setDataSourceFD: fd %d", fd);
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
调用了 mp->setDataSource(fd, offset, length),根据参数:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
由 const sp
可知,MediaPlayer和MediaPlayerService是C/S架构。后面再分析MediaPlayerService。
参考:Audio笔记之MediaPlayerService:setDataSource
继续分析MediaPlayer::setDataSource会发现其调用了player->setDataSource(fd, offset, length),其中player就是通过MediaPlayerService获取的实例:sp
,根据参数:
status_t setDataSource(int fd, int64_t offset, int64_t length) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeFileDescriptor(fd);
data.writeInt64(offset);
data.writeInt64(length);
remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
return reply.readInt32();
}
处理完成后,返回到 android_media_MediaPlayer_setDataSourceFD 中的 process_media_player_call(…) 函数中,process_media_player_call根据返回结果进行适当的处理(暂未详细分析)。
至此,setDataSource基本分析完成。
接下来分析 mp.prepare();
,即:
public static MediaPlayer create(Context context, int resid, AudioAttributes audioAttributes, int audioSessionId) {
try {
......
mp.prepare();
......
}
...
}
public void prepare() throws IOException, IllegalStateException {
_prepare();
scanInternalSubtitleTracks();
// DrmInfo, if any, has been resolved by now.
synchronized (mDrmLock) {
mDrmInfoResolved = true;
}
}
private native void _prepare() throws IOException, IllegalStateException;
static void
android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
// android_media_MediaPlayer_native_setup()中有setMediaPlayer的动作
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
// Handle the case where the display surface was set before the mp was
// initialized. We try again to make it stick.
sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
mp->setVideoSurfaceTexture(st);
process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
}
类似setDataSource,通过MediaPlayerService完成prepare的相关动作。
至此,prepare基本分析完成。
接下来分析APK中的mPlayer.start();
。
// frameworks/base/media/java/android/media/MediaPlayer.java
public void start() throws IllegalStateException {
//FIXME use lambda to pass startImpl to superclass
final int delay = getStartDelayMs();
if (delay == 0) {
startImpl();
} else {
new Thread() {
public void run() {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
baseSetStartDelayMs(0);
try {
startImpl();
} catch (IllegalStateException e) {
// fail silently for a state exception when it is happening after
// a delayed start, as the player state could have changed between the
// call to start() and the execution of startImpl()
}
}
}.start();
}
}
private void startImpl() {
baseStart();
stayAwake(true);
_start();
}
private native void _start() throws IllegalStateException;
// frameworks/base/media/jni/android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
ALOGV("start");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}
// frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::start()
{
ALOGV("start");
status_t ret = NO_ERROR;
Mutex::Autolock _l(mLock);
mLockThreadId = getThreadId();
if (mCurrentState & MEDIA_PLAYER_STARTED) {
ret = NO_ERROR;
} else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
mPlayer->setLooping(mLoop);
mPlayer->setVolume(mLeftVolume, mRightVolume);
mPlayer->setAuxEffectSendLevel(mSendLevel);
mCurrentState = MEDIA_PLAYER_STARTED;
ret = mPlayer->start();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
} else {
if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
ALOGV("playback completed immediately following start()");
}
}
} else {
ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
ret = INVALID_OPERATION;
}
mLockThreadId = 0;
return ret;
}
// frameworks/av/media/libmedia/IMediaPlayer.cpp
status_t start()
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
remote()->transact(START, data, &reply);
return reply.readInt32();
}