android getAudioSessionId()函数的介绍

在我们学习AudioTrack对象的创建过程时,了解到,创建一个AudioTrack对象,必须指定一个SessionId,并与其他使用该SessionId的AudioTrack和MediaPlayer共享AudioEffect。
如果不指定SessionId,将会自动生成一个SessionId,AudioEffect会将该SessionId与新创建的AudioTrack对象关联起来。
别人可以通过getAudioSessionId函数取得该SessionId。
今天我们就看看getAudioSessionId函数。

在frameworks的代码中搜了一下,发现有两个地方实现了该函数,分别来说一下。

先说说在类MediaPlayer中的实现。
*****************************************源码*************************************************

[cpp]  view plain  copy
  1. int MediaPlayer::getAudioSessionId()  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     return mAudioSessionId;  
  5. }  


**********************************************************************************************
源码路径:
frameworks\base\media\libmedia\mediaplayer.cpp

###########################################说明################################################
代码很简单,只是将成员变量返回,没啥好说的。
那我们看看该成员变量是何时被赋值的。

找了下代码,发现有两个地方对该成员变量进行了赋值。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
一个在构造函数中。

[cpp]  view plain  copy
  1. MediaPlayer::MediaPlayer()  
  2. {  
  3.     LOGV("constructor");  
  4.     mListener = NULL;  
  5.     mCookie = NULL;  
  6.     mDuration = -1;  
  7.     mStreamType = AudioSystem::MUSIC;  
  8.     mCurrentPosition = -1;  
  9.     mSeekPosition = -1;  
  10.     mCurrentState = MEDIA_PLAYER_IDLE;  
  11.     mPrepareSync = false;  
  12.     mPrepareStatus = NO_ERROR;  
  13.     mLoop = false;  
  14.     mLeftVolume = mRightVolume = 1.0;  
  15.     mVideoWidth = mVideoHeight = 0;  
  16.     mLockThreadId = 0;  
  17. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  18. int AudioSystem::newAudioSessionId() {  
  19.     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();  
  20.     if (af == 0) return 0;  
  21. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  22. int AudioFlinger::newAudioSessionId()  
  23. {  
  24. // 看到了函数nextUniqueId,我们感觉到有点熟悉。  
  25. // 不错,在我们看函数AudioSystem::getOutputSamplingRate的时候,看到,在函数AudioFlinger::openOutput中有调过函数nextUniqueId  
  26. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  27. int AudioFlinger::nextUniqueId()  
  28. {  
  29. // 这是一个自增的操作  
  30. // 可见,SessionId最终是在AudioFlinger中维护的。  
  31. // 关于函数android_atomic_inc,可参考以下链接:  
  32. // http://hi.baidu.com/obiwong/blog/item/5317a7d4c6e481cf50da4b1e.html  
  33.     return android_atomic_inc(&mNextUniqueId);  
  34. }  
  35. ----------------------------------------------------------------  
  36.     return nextUniqueId();  
  37. }  
  38. ----------------------------------------------------------------  
  39.     return af->newAudioSessionId();  
  40. }  
  41. ----------------------------------------------------------------  
  42.     mAudioSessionId = AudioSystem::newAudioSessionId();  
  43.     mSendLevel = 0;  
  44. }  


----------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
另一个给成员变量mAudioSessionId赋值的地方是在函数MediaPlayer::setAudioSessionId中。

[cpp]  view plain  copy
  1. status_t MediaPlayer::setAudioSessionId(int sessionId)  
  2. {  
  3.     LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);  
  4.     Mutex::Autolock _l(mLock);  
  5.     if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {  
  6.         LOGE("setAudioSessionId called in state %d", mCurrentState);  
  7.         return INVALID_OPERATION;  
  8.     }  
  9.     if (sessionId < 0) {  
  10.         return BAD_VALUE;  
  11.     }  
  12.     mAudioSessionId = sessionId;  
  13.     return NO_ERROR;  
  14. }  


函数MediaPlayer::setAudioSessionId在函数android_media_MediaPlayer_set_audio_session_id中被调用。

[cpp]  view plain  copy
  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  2. static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz, jint sessionId) {  
  3.     LOGV("set_session_id(): %d", sessionId);  
  4. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  5. static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)  
  6. {  
  7.     Mutex::Autolock l(sLock);  
  8.     MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);  
  9.     return sp<MediaPlayer>(p);  
  10. }  


// 以前见到过类似的函数,肯定有某个地方把它set进去。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[cpp]  view plain  copy
  1. static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)  
  2. {  
  3.     Mutex::Autolock l(sLock);  
  4.     sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);  
  5.     if (player.get()) {  
  6.         player->incStrong(thiz);  
  7.     }  
  8.     if (old != 0) {  
  9.         old->decStrong(thiz);  
  10.     }  
  11.     env->SetIntField(thiz, fields.context, (int)player.get());  
  12.     return old;  
  13. }  


函数setMediaPlayer在函数android_media_MediaPlayer_native_setup中被调用。
函数android_media_MediaPlayer_native_setup也是供java调用的。
对应的接口,在下面的一个列表中可以看到。
[cpp]  view plain  copy
  1. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  2. static void  
  3. android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)  
  4. {  
  5.     LOGV("native_setup");  
  6.  // 在上面的代码中,SessionId的一个赋值的地方就是MediaPlayer的构造函数中。  
  7.  // MediaPlayer对象就是在这儿被构造的。  
  8.     sp<MediaPlayer> mp = new MediaPlayer();  
  9.     if (mp == NULL) {  
  10.         jniThrowException(env, "java/lang/RuntimeException""Out of memory");  
  11.         return;  
  12.     }  
  13.     // create new listener and give it to MediaPlayer  
  14.  // JNIMediaPlayerListener是一个代码量不多的类,其声明和实现如下:  
  15. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  16. // ref-counted object for callbacks  
  17. class JNIMediaPlayerListener: public MediaPlayerListener  
  18. {  
  19. public:  
  20.     JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);  
  21.     ~JNIMediaPlayerListener();  
  22.     void notify(int msg, int ext1, int ext2);  
  23. private:  
  24.     JNIMediaPlayerListener();  
  25.     jclass      mClass;     // Reference to MediaPlayer class  
  26.     jobject     mObject;    // Weak ref to MediaPlayer Java object to call on  
  27. };  
  28. JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)  
  29. {  
  30.     // Hold onto the MediaPlayer class for use in calling the static method  
  31.     // that posts events to the application thread.  
  32.     jclass clazz = env->GetObjectClass(thiz);  
  33.     if (clazz == NULL) {  
  34.         LOGE("Can't find android/media/MediaPlayer");  
  35.         jniThrowException(env, "java/lang/Exception", NULL);  
  36.         return;  
  37.     }  
  38.     mClass = (jclass)env->NewGlobalRef(clazz);  
  39.     // We use a weak reference so the MediaPlayer object can be garbage collected.  
  40.     // The reference is only used as a proxy for callbacks.  
  41.     mObject  = env->NewGlobalRef(weak_thiz);  
  42. }  
  43. JNIMediaPlayerListener::~JNIMediaPlayerListener()  
  44. {  
  45.     // remove global references  
  46.     JNIEnv *env = AndroidRuntime::getJNIEnv();  
  47.     env->DeleteGlobalRef(mObject);  
  48.     env->DeleteGlobalRef(mClass);  
  49. }  
  50. void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)  
  51. {  
  52.     JNIEnv *env = AndroidRuntime::getJNIEnv();  
  53.     env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);  
  54. }  
  55. //----------------------------------------------------------------  
  56.     sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);  
  57.     mp->setListener(listener);  
  58.     // Stow our new C++ MediaPlayer in an opaque field in the Java object.  
  59.     setMediaPlayer(env, thiz, mp);  
  60. }  
  61. //----------------------------------------------------------------  
  62. //----------------------------------------------------------------  
  63. //----------------------------------------------------------------  
  64.     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);  
  65.     if (mp == NULL ) {  
  66.         jniThrowException(env, "java/lang/IllegalStateException", NULL);  
  67.         return;  
  68.     }  
  69. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  70. // If exception is NULL and opStatus is not OK, this method sends an error  
  71. // event to the client application; otherwise, if exception is not NULL and  
  72. // opStatus is not OK, this method throws the given exception to the client  
  73. // application.  
  74. static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)  
  75. {  
  76.     if (exception == NULL) {  // Don't throw exception. Instead, send an event.  
  77.         if (opStatus != (status_t) OK) {  
  78.             sp<MediaPlayer> mp = getMediaPlayer(env, thiz);  
  79.             if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);  
  80.         }  
  81.     } else {  // Throw exception!  
  82.         if ( opStatus == (status_t) INVALID_OPERATION ) {  
  83.             jniThrowException(env, "java/lang/IllegalStateException", NULL);  
  84.         } else if ( opStatus != (status_t) OK ) {  
  85.             if (strlen(message) > 230) {  
  86.                // if the message is too long, don't bother displaying the status code  
  87.                jniThrowException( env, exception, message);  
  88.             } else {  
  89.                char msg[256];  
  90.                 // append the status code to the message  
  91.                sprintf(msg, "%s: status=0x%X", message, opStatus);  
  92.                jniThrowException( env, exception, msg);  
  93.             }  
  94.         }  
  95.     }  
  96. }  
  97. //----------------------------------------------------------------  
  98.     process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );  
  99. }  


根据以往的经验,函数android_media_MediaPlayer_set_audio_session_id应该是供java代码调用的。
果然。。。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[cpp]  view plain  copy
  1. static JNINativeMethod gMethods[] = {  
  2.     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},  
  3.     {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},  
  4.     {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},  
  5.     {"_setVideoSurface",    "()V",                              (void *)android_media_MediaPlayer_setVideoSurface},  
  6.     {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},  
  7.     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},  
  8.     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},  
  9.     {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},  
  10.     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},  
  11.     {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},  
  12.     {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},  
  13.     {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},  
  14.     {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},  
  15.     {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},  
  16.     {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},  
  17.     {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},  
  18.     {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},  
  19.     {"setAudioStreamType",  "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},  
  20.     {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},  
  21.     {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},  
  22.     {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},  
  23.     {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},  
  24.     {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},  
  25.     {"native_setMetadataFilter""(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},  
  26.     {"native_getMetadata""(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},  
  27.     {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},  
  28.     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},  
  29.     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},  
  30.     {"native_suspend_resume""(Z)I",                           (void *)android_media_MediaPlayer_native_suspend_resume},  
  31.     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},  
  32.     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},  
  33.     {"setAuxEffectSendLevel""(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},  
  34.     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},  
  35.     {"setAudioEffect",      "(III)V",                           (void *)android_media_MediaPlayer_setAudioEffect},  
  36.     {"setAudioEqualizer",   "(Z)V",                             (void *)android_media_MediaPlayer_setAudioEqualizer},  
  37.     {"captureCurrentFrame""()Landroid/graphics/Bitmap;",      (void *)android_media_MediaPlayer_captureCurrentFrame},  
  38.     {"setVideoCrop",      "(IIII)V",                           (void *)android_media_MediaPlayer_setVideoCrop},  
  39.     {"getTrackCount",       "()I",                              (void *)android_media_MediaPlayer_getTrackCount},  
  40.     {"getTrackName",        "(I)Ljava/lang/String;",            (void *)android_media_MediaPlayer_getTrackName},  
  41.     {"getDefaultTrack",     "()I",                              (void *)android_media_MediaPlayer_getDefaultTrack},  
  42.     {"selectTrack",         "(I)V",                             (void *)android_media_MediaPlayer_selectTrack},  
  43. };  


这些函数,应该都是java中的MediaPlayer类,通过JNI接口调用过来的。
----------------------------------------------------------------
----------------------------------------------------------------
----------------------------------------------------------------
###############################################################################################

文章开头有说到,函数getAudioSessionId函数的实现有两个地方。
另外一个是在类Client(class Client : public BnMediaPlayer),
类MediaPlayerService(class MediaPlayerService : public BnMediaPlayerService)的一个内部类
*****************************************源码*************************************************

[cpp]  view plain  copy
  1. int             getAudioSessionId() { return mAudioSessionId; }  


**********************************************************************************************
源码路径:
frameworks\base\media\libmediaplayerservice\MediaPlayerService.h

###########################################说明################################################
只有类Client的构造函数中,有对成员变量mAudioSessionId赋值

[cpp]  view plain  copy
  1. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  2. MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid,  
  3.         int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId)  
  4. {  
  5.     LOGV("Client(%d) constructor", connId);  
  6.     mPid = pid;  
  7.     mConnId = connId;  
  8.     mService = service;  
  9.     mClient = client;  
  10.     mLoop = false;  
  11.     mStatus = NO_INIT;  
  12.     mAudioSessionId = audioSessionId;  
  13. #if CALLBACK_ANTAGONIZER  
  14.     LOGD("create Antagonizer");  
  15.     mAntagonizer = new Antagonizer(notify, this);  
  16. #endif  
  17. }  
  18. // Client对象在函数MediaPlayerService::create中被创建  
  19. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
  20. sp<IMediaPlayer> MediaPlayerService::create(  
  21.         pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,  
  22.         const KeyedVector<String8, String8> *headers, int audioSessionId)  
  23. {  
  24.     int32_t connId = android_atomic_inc(&mNextConnId);  
  25.     sp<Client> c = new Client(this, pid, connId, client, audioSessionId);  
  26.     LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",  
  27.             connId, pid, url, connId, audioSessionId);  
  28.     if (NO_ERROR != c->setDataSource(url, headers))  
  29.     {  
  30.         c.clear();  
  31.         return c;  
  32.     }  
  33.     wp<Client> w = c;  
  34.     Mutex::Autolock lock(mLock);  
  35.     mClients.add(w);  
  36.     return c;  
  37. }  
  38. //----------------------------------------------------------------  
  39. //----------------------------------------------------------------  


###############################################################################################

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&总结&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
1、关于SessionId
    一个Session就是一个会话。每个会话都有一个独一无二的Id来标识。该Id的最终管理在AudioFlinger中。
 一个会话可以被多个AudioTrack对象和MediaPlayer共用。
 共用一个Session的AudioTrack和MediaPlayer共享相同的AudioEffect。
 
2、关于java中调用native中的函数
    调用的实现当然是通过JNI。此处要说的是,通过JNI调用过来之后,如何使用native中的对象。
    首先会通过native_setup之类的函数创建一个native对象,并通过函数SetIntField保存到java侧。
 需要使用的时候调用函数GetIntField便可获取native对象,之后就可以对native对象进行操作了。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值