- 浏览: 12921342 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
sanrenxing_1:
GoEasy 实时推送支持IE6-IE11及大多数主流浏览器的 ...
WindowsPhone消息推送服务 -
张砚辉:
两侧照片绕Y轴旋转后有锯齿,请问锯齿解决方案,很长时间没解决
自定义带倒影和偏转的超炫Gallery -
knight_black_bob:
能不能把你自己的博客整理下分类下,写了这么多 ,都不知道怎么查 ...
Android_View,ViewGroup,Window之间的关系 -
jeasonyoung:
你这个代码实现在iOS8下应该是滑不动的
UISlider 滑块控件—IOS开发 -
wx_hello:
如果能写个可运行的java程序,不胜感激。。。
rs232串口通信原理
Android Audio代码分析5 - 函数getAudioSessionId
在我们学习AudioTrack对象的创建过程时,了解到,创建一个AudioTrack对象,必须指定一个SessionId,并与其他使用该SessionId的AudioTrack和MediaPlayer共享AudioEffect。
如果不指定SessionId,将会自动生成一个SessionId,AudioEffect会将该SessionId与新创建的AudioTrack对象关联起来。
别人可以通过getAudioSessionId函数取得该SessionId。
今天我们就看看getAudioSessionId函数。
在frameworks的代码中搜了一下,发现有两个地方实现了该函数,分别来说一下。
先说说在类MediaPlayer中的实现。
*****************************************源码*************************************************
int MediaPlayer::getAudioSessionId() { Mutex::Autolock _l(mLock); return mAudioSessionId; }
**********************************************************************************************
源码路径:
frameworks\base\media\libmedia\mediaplayer.cpp
###########################################说明################################################
代码很简单,只是将成员变量返回,没啥好说的。
那我们看看该成员变量是何时被赋值的。
找了下代码,发现有两个地方对该成员变量进行了赋值。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
一个在构造函数中。
MediaPlayer::MediaPlayer() { LOGV("constructor"); mListener = NULL; mCookie = NULL; mDuration = -1; mStreamType = AudioSystem::MUSIC; mCurrentPosition = -1; mSeekPosition = -1; mCurrentState = MEDIA_PLAYER_IDLE; mPrepareSync = false; mPrepareStatus = NO_ERROR; mLoop = false; mLeftVolume = 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() { // 看到了函数nextUniqueId,我们感觉到有点熟悉。 // 不错,在我们看函数AudioSystem::getOutputSamplingRate的时候,看到,在函数AudioFlinger::openOutput中有调过函数nextUniqueId ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ int AudioFlinger::nextUniqueId() { // 这是一个自增的操作 // 可见,SessionId最终是在AudioFlinger中维护的。 // 关于函数android_atomic_inc,可参考以下链接: // http://hi.baidu.com/obiwong/blog/item/5317a7d4c6e481cf50da4b1e.html return android_atomic_inc(&mNextUniqueId); } ---------------------------------------------------------------- return nextUniqueId(); } ---------------------------------------------------------------- return af->newAudioSessionId(); } ---------------------------------------------------------------- mAudioSessionId = AudioSystem::newAudioSessionId(); mSendLevel = 0; }
----------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
另一个给成员变量mAudioSessionId赋值的地方是在函数MediaPlayer::setAudioSessionId中。
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; }
函数MediaPlayer::setAudioSessionId在函数android_media_MediaPlayer_set_audio_session_id中被调用。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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); }
// 以前见到过类似的函数,肯定有某个地方把它set进去。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; }
函数setMediaPlayer在函数android_media_MediaPlayer_native_setup中被调用。
函数android_media_MediaPlayer_native_setup也是供java调用的。
对应的接口,在下面的一个列表中可以看到。
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { LOGV("native_setup"); // 在上面的代码中,SessionId的一个赋值的地方就是MediaPlayer的构造函数中。 // MediaPlayer对象就是在这儿被构造的。 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是一个代码量不多的类,其声明和实现如下: //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ref-counted object for callbacks class 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 events 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->NewGlobalRef(weak_thiz); } JNIMediaPlayerListener::~JNIMediaPlayerListener() { // remove global references JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteGlobalRef(mObject); env->DeleteGlobalRef(mClass); } void JNIMediaPlayerListener::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); } //---------------------------------------------------------------- //---------------------------------------------------------------- //---------------------------------------------------------------- sp<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->notify(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); } } } } //---------------------------------------------------------------- process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); }
根据以往的经验,函数android_media_MediaPlayer_set_audio_session_id应该是供java代码调用的。
果然。。。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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}, };
这些函数,应该都是java中的MediaPlayer类,通过JNI接口调用过来的。
----------------------------------------------------------------
----------------------------------------------------------------
----------------------------------------------------------------
###############################################################################################
文章开头有说到,函数getAudioSessionId函数的实现有两个地方。
另外一个是在类Client(class Client : public BnMediaPlayer),
类MediaPlayerService(class MediaPlayerService : public BnMediaPlayerService)的一个内部类
*****************************************源码*************************************************
int getAudioSessionId() { return mAudioSessionId; }
**********************************************************************************************
源码路径:
frameworks\base\media\libmediaplayerservice\MediaPlayerService.h
###########################################说明################################################
只有类Client的构造函数中,有对成员变量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(notify, this); #endif } // Client对象在函数MediaPlayerService::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; } //---------------------------------------------------------------- //----------------------------------------------------------------
###############################################################################################
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&总结&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
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对象进行操作了。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
相关推荐
Demo Importing the Library Add to build.gradle: dependencies { ...} Library is available in jcenter repository How to use Refer to the sample project on how to use visualizer or refer to WIKI docs. ...
project( ' :react-native-android-audio-streaming-aac ' ) . projectDir = new File (settingsDir, ' ../node_modules/react-native-android-audio-streaming-aac ' ) android/app/build.gradle .. . ...
audio 播放器 在vue-audio-better上增加图标名称和大小 非工程化项目使用,绑定vue.js全局使用
DroidPhone的ANDROID-AUDIO-SYSTEM系列,写的极好,我把它整理成文档了,原帖:http://blog.csdn.net/droidphone,感谢作者的辛勤劳作和无私奉献。
Google Assistant SDK for devices - Android Things This sample shows how to call the Google Assistant Service from Android Things using gRPC. It records a spoken request from the connected microphones,...
red5-server - Red5 server core Red5 is an Open Source Flash Server written in Java that supports: Streaming Video (FLV, F4V, MP4, 3GP) Streaming Audio (MP3, F4A, M4A, AAC) Recording Client ...
android-sun-jarsign-support-1.1.jar
It has been tested with Android MediaCodec encoder to send H264 (avc) video and with Android MediaRecorder to send AAC audio via RTMP to a server. RFCs This implementation uses the RTMP 3 protocol ...
android audio 框架流程分析图
In addition, includes a patched MP4Parser Java library for wrapping AAC files in an MP4 container to produce M4A audio files playable by Google Chrome and Apple QuickTime. This project is set up as a ...
数据库安装时补丁包, rpm -ihv zlib-devel-1.2.3-3.i386.rpm rpm -ihv freetype-devel-2.2.1-21.el5_3.i386.rpm ...rpm -ihv audiofile-devel-0.2.6-5.i386.rpm rpm -ihv esound-devel-0.2.36-3.i386.rpm
webrtc-audio-processing-0.3.1在arm平台的测试程序,含测试用的pcm文件。
Implementation of the missing feature in Android SDK: audio recorder with a pause. Based on mp4parser. Latest sample build Import Grab the latest version from Bintray: repositories { jcenter() } ...
FolioReader-Android is an ePub reader and parser framework written in Java. Features [x] Custom Fonts [x] Custom Text Size [x] Themes / Day mode / Night mode [x] Text Highlighting [x] List / Edit / ...
XMOS-Stereo-USB-Audio-Class2-Driver-3033_v4.13.0公板
浏览器实现滤波源代码web-audio-image-filtering-master
Jitsi for Android is an Android port of the Jitsi project: The most feature-rich communicator with support for encrypted audio/video, chat and presence over SIP and XMPP. Usage with IntelliJ Make ...
simpleaudio-1.0.4-cp310-cp310-win_amd64
This plugin allows you to stream audio and video in a fullscreen, native player on iOS and Android. 1.0.0 Works with Cordova 3.x 1.0.1 Works with Cordova >= 4.0 Installation cordova plugin add ...
> for Android. Please see this page for the iOS counterpart. The Art Institute of Chicago app is your personal, pocket-sized guide to our collection. The mobile experience offers high-quality audio ...