Android Audio Code Analysis 5-function getaudiosessionid

Source: Internet
Author: User

 

When learning how to create an audiotrack object, we learned that to create an audiotrack object, you must specify a sessionid and share the audioeffect with other audiotrack and mediaplayer that use the sessionid.
If sessionid is not specified, a sessionid is automatically generated. audioeffect associates the sessionid with the newly created audiotrack object.
You can use the getaudiosessionid function to obtain the sessionid.
Today, let's take a look at the getaudiosessionid function.

I searched in the frameworks code and found that this function was implemented in two places. Let's talk about it separately.

First, let's talk about the implementation in the mediaplayer class.
**************************************** * Source Code ************************************** ***********

int MediaPlayer::getAudioSessionId(){    Mutex::Autolock _l(mLock);    return mAudioSessionId;}

**************************************** **************************************** **************
Source code path:
Frameworks \ base \ media \ libmedia \ mediaplayer. cpp

######################################## ### Description #################################### ############
The code is very simple. It just returns the member variables.
Let's see when the member variable is assigned a value.

I found the code and found that the member variable was assigned a value in two places.

++ ++
One is in the constructor.

Mediaplayer: mediaplayer () {logv ("constructor"); mlistener = NULL; mcookie = NULL; mduration =-1; mstreamtype = audiosystem: Music; mcurrentposition =-1; mseekposition =-1; mcurrentstate = success; mpreparesync = false; mpreparestatus = no_error; mloop = false; priority = mrightvolume = 1.0; mvideowidth = mvideoheight = 0; mlockthreadid = 0; ++ ++ ++ Int audiosystem: newaudiosessionid () {const sp <iaudioflinger> & AF = audiosystem:: get_audio_flinger (); If (AF = 0) return 0; ++ ++ int audioflinger:: newaudiosessionid () {// you can see the nextuniqueid function. // Good. When we look at the function audiosystem: getoutputsamplingrate, we can see that the function audioflinger :: in openoutput, the call function nextuniqueid ++ ++ int audioflinger:: nextuniqueid () {// This is an auto-increment operation // visible, and sessionid is eventually maintained in audioflinger. // For the android_atomic_inc function, see the following link: // http://hi.baidu.com/obiwong/blog/item/5317a7d4c6e481cf50da4b1e.html return android_atomic_inc (& mnextuniqueid);} returns return nextuniqueid ();} returns return af-> newaudiosessionid ();} ---------------------------------------------------------------- maudiosessionid = audiosystem: newaudiosessionid (); msendlevel = 0 ;}

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

++ ++
Another value for the member variable maudiosessionid is in the mediaplayer: setaudiosessionid function.

status_t MediaPlayer::setAudioSessionId(int sessionId){    LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);    Mutex::Autolock _l(mLock);    if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {        LOGE("setAudioSessionId called in state %d", mCurrentState);        return INVALID_OPERATION;    }    if (sessionId < 0) {        return BAD_VALUE;    }    mAudioSessionId = sessionId;    return NO_ERROR;}

The mediaplayer: setaudiosessionid function is called in the android_media_mediaplayer_set_audio_session_id function.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz, jint sessionId) {    LOGV("set_session_id(): %d", sessionId);++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz){    Mutex::Autolock l(sLock);    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);    return sp<MediaPlayer>(p);}

// A similar function has been seen before, and it must be set somewhere.
++ ++

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player){    Mutex::Autolock l(sLock);    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);    if (player.get()) {        player->incStrong(thiz);    }    if (old != 0) {        old->decStrong(thiz);    }    env->SetIntField(thiz, fields.context, (int)player.get());    return old;}

The setmediaplayer function is called in the android_media_mediaplayer_native_setup function.
The android_media_mediaplayer_native_setup function is also called by Java.
The corresponding interface can be seen in the following list.

// ++ ++ Static voidandroid_media_mediaplayer_native_setup (jnienv * ENV, jobject thiz, jobject weak_this) {logv ("native_setup"); // In the code above, a value assigned by sessionid is in the mediaplayer constructor. // The mediaplayer object is constructed here. 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 // jnimediaplayerlistener is a class with a small amount of Code. Its declaration and implementation are as follows: // ++ ++ // ref-counted object for callbacksclass jnimediaplayerlistener: public mediaplayerlistener {public: Jnimediaplayerlistener (jnienv * ENV, jobject thiz, jobject weak_thiz );~ Jnimediaplayerlistener (); void notify (int msg, int ext1, int ext2); Private: jnimediaplayerlistener (); jclass mclass; // reference to mediaplayer class jobject mobject; // weak ref to mediaplayer Java object to call on}; jnimediaplayerlistener: jnimediaplayerlistener (jnienv * ENV, jobject thiz, jobject weak_thiz) {// hold onto the mediaplayer class for use in calling the static method // that posts EV Ents to the application thread. jclass clazz = env-> getobjectclass (thiz); If (clazz = NULL) {LogE ("can't find Android/Media/mediaplayer"); jnithrowexception (ENV, "Java/lang/exception", null); return;} mclass = (jclass) ENV-> newglobalref (clazz ); // We use a weak reference so the mediaplayer object can be garbage collected. // The reference is only used as a proxy for callbacks. mobject = env-> New Globalref (weak_thiz);} jnimediaplayerlistener ::~ Revoke () {// remove global references jnienv * Env = androidruntime: getjnienv (); env-> deleteglobalref (mobject); env-> deleteglobalref (mclass);} void limit:: Notify (int msg, int ext1, int ext2) {jnienv * Env = androidruntime: getjnienv (); env-> callstaticvoidmethod (mclass, fields. post_event, mobject, MSG, ext1, ext2, 0 );}//------------------------------------------------- --------------- 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);} // -------------------------------------------------------------- // else );}//----------------------------------------------------------------//----------------------------------------------------------------//--------------------------------- Javassp <mediaplayer> MP = getmediaplayer (ENV, thiz); If (MP = NULL) {jnithrowexception (ENV, "Java/lang/illegalstateexception", null); return ;} // ++ ++ // If exception is null and opstatus is not OK, this method sends an error // event to the client application; otherwise, if exception is not null and // opstatus Is not OK, this method throws the given exception to the client // application. static void process_media_player_call (jnienv * ENV, jobject thiz, status_t opstatus, const char * exception, const char * message) {If (exception = NULL) {// don't throw exception. instead, send an event. if (opstatus! = (Status_t) OK) {sp <mediaplayer> MP = getmediaplayer (ENV, thiz); If (MP! = 0) MP-> Policy (media_error, opstatus, 0) ;}} else {// throw exception! If (opstatus = (status_t) invalid_operation) {jnithrowexception (ENV, "Java/lang/illegalstateexception", null);} else if (opstatus! = (Status_t) OK) {If (strlen (Message)> 230) {// if the message is too long, don't bother displaying the status code jnithrowexception (ENV, exception, message);} else {char MSG [256]; // append the status code to the Message sprintf (MSG, "% s: Status = 0x % x", message, opstatus); jnithrowexception (ENV, exception, MSG) ;}}// define process_media_player_call (ENV, thiz, MP-> setaudiosessionid (sessionid), null, null );}

Based on past experience, the android_media_mediaplayer_set_audio_session_id function should be called by Java code.
Sure enough...
++ ++

static JNINativeMethod gMethods[] = {    {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},    {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},    {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},    {"_setVideoSurface",    "()V",                              (void *)android_media_MediaPlayer_setVideoSurface},    {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},    {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},    {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},    {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},    {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},    {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},    {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},    {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},    {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},    {"setAudioStreamType",  "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},    {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},    {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},    {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},    {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},    {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},    {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},    {"native_suspend_resume", "(Z)I",                           (void *)android_media_MediaPlayer_native_suspend_resume},    {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},    {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},    {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},    {"setAudioEffect",      "(III)V",                           (void *)android_media_MediaPlayer_setAudioEffect},    {"setAudioEqualizer",   "(Z)V",                             (void *)android_media_MediaPlayer_setAudioEqualizer},    {"captureCurrentFrame", "()Landroid/graphics/Bitmap;",      (void *)android_media_MediaPlayer_captureCurrentFrame},    {"setVideoCrop",      "(IIII)V",                           (void *)android_media_MediaPlayer_setVideoCrop},    {"getTrackCount",       "()I",                              (void *)android_media_MediaPlayer_getTrackCount},    {"getTrackName",        "(I)Ljava/lang/String;",            (void *)android_media_MediaPlayer_getTrackName},    {"getDefaultTrack",     "()I",                              (void *)android_media_MediaPlayer_getDefaultTrack},    {"selectTrack",         "(I)V",                             (void *)android_media_MediaPlayer_selectTrack},};

These functions should all be called by the mediaplayer class in Java through the JNI interface.
----------------------------------------------------------------
----------------------------------------------------------------
----------------------------------------------------------------
######################################## ######################################## ###############

As mentioned at the beginning of this article, the implementation of the getaudiosessionid function has two points.
The other is in the class client (class client: Public bnmediaplayer ),
An internal class of the class mediaplayerservice (class mediaplayerservice: Public bnmediaplayerservice)
**************************************** * Source Code ************************************** ***********

int             getAudioSessionId() { return mAudioSessionId; }

**************************************** **************************************** **************
Source code path:
Frameworks \ base \ media \ libmediaplayerservice \ mediaplayerservice. h

######################################## ### Description #################################### ############
Only the constructors of the client class assign values to the member variable maudiosessionid.

// ++ ++ Mediaplayerservice:: Client: client (const sp <mediaplayerservice> & service, pid_t PID, int32_t connid, const sp <imediaplayerclient> & client, int audiosessionid) {logv ("client (% d) constructor ", connid); MPID = PID; mconnid = connid; mservice = service; mclient = client; mloop = false; mstatus = no_init; maudiosessionid = audiosessionid; # If callback_antagonizer logd ("create antagonizer"); mantagonizer = new antagonizer (Y, this); # endif} // The client object is in the mediaplayerservice function :: created in create // ++ ++ sp <imediaplayer> mediaplayerservice:: Create (pid_t PID, const sp <imediaplayerclient> & client, const char * URL, const keyedvector <string8, string8> * headers, int audiosessionid) {int32_t Connid = android_atomic_inc (& mnextconnid); sp <client> C = new client (this, PID, connid, client, audiosessionid); logv ("create new client (% d) from PID % d, url = % s, connid = % d, audiosessionid = % d ", connid, PID, URL, connid, audiosessionid); If (no_error! = C-> setdatasource (URL, headers) {C. clear (); Return C ;}wp <client> W = C; mutex: autolock lock (mlock); mclients. add (w); Return C;} // samples ;}//----------------------------------------------------------------//----------------------------------------------------------------

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

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& & Summary &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&
1. sessionid
A session is a session. Each session is identified by a unique ID. The ID is ultimately managed in audioflinger.
A session can be shared by multiple audiotrack objects and mediaplayer.
The audiotrack and mediaplayer that share a session share the same audioeffect.
 
2. Call native functions in Java
Of course, the call is implemented through JNI. Here we will talk about how to use objects in native after JNI is called.
First, a native object will be created through functions such as native_setup and saved to the Java side through the setintfield function.
When needed, call the getintfield function to obtain the native object, and then perform operations on the native object.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.