本篇是上一篇的彩蛋篇
正确找到H264编码之间,进行的代码追踪工作。其中将linphone启动的来龙去脉走了一遍,给人印象深刻。所以贴到这里,进行一下纪念。
为什么有的有H264编码,有的没有H264编码呢?追踪一下
界面显示SettingsFragment.java
用到的地方–下载篇章,没有什么卵用
LinphoneCoreFactory.java
说明
这里是一个接口, 专门用于创建OpenH264DownloadHelper使用
代码
/**
* Must be calling after the LinphoneCore creation
* @return a new OpenH264DownloadHelper
*/
abstract public OpenH264DownloadHelper createOpenH264DownloadHelper();
LinphoneCoreFactoryImpl.java
说明
这里主要是创建了一个OpenH264DownloadHelper对象
代码
@Override
public OpenH264DownloadHelper createOpenH264DownloadHelper() {
if (fcontext == null) {
new LinphoneCoreException("Cannot create OpenH264DownloadHelper");
return null;//exception
}
return new OpenH264DownloadHelper(fcontext);
}
private boolean loadingDownloadedOpenH264(Context context) {
File file = new File(context.getFilesDir() + "/../lib/libmsopenh264.so");
if (!file.exists()) {
Log.i("LinphoneCoreFactoryImpl", " libmsopenh264 not found, we disable the download of Openh264");
return false;
}
OpenH264DownloadHelper downloadHelper = new OpenH264DownloadHelper(context);
if (downloadHelper.isCodecFound()) {
Log.i("LinphoneCoreFactoryImpl", " Loading OpenH264 downloaded plugin:" + downloadHelper.getFullPathLib());
System.load(downloadHelper.getFullPathLib());
} else {
Log.i("LinphoneCoreFactoryImpl", " Cannot load OpenH264 downloaded plugin");
}
return true;
}
OpenH264DownloadHelper.java
public class OpenH264DownloadHelper {
private OpenH264DownloadHelperListener openH264DownloadHelperListener;
private ArrayList<Object> userData;
private String fileDirection;
private String nameLib;
private String urlDownload;
private String nameFileDownload;
private String licenseMessage;
/**
* Default values
* nameLib = "libopenh264-1.5.so"
* urlDownload = "http://ciscobinary.openh264.org/libopenh264-1.5.0-android19.so.bz2"
* nameFileDownload = "libopenh264-1.5.0-android19.so.bz2"
*/
public OpenH264DownloadHelper(Context context) {
userData = new ArrayList<Object>();
licenseMessage = "OpenH264 Video Codec provided by Cisco Systems, Inc.";
nameLib = "libopenh264.so";
urlDownload = "http://ciscobinary.openh264.org/libopenh264-1.5.0-android19.so.bz2";
nameFileDownload = "libopenh264-1.5.0-android19.so.bz2";
if(context.getFilesDir() != null) {
fileDirection = context.getFilesDir().toString();
}
}
/**
* Set OpenH264DownloadHelperListener
* @param h264Listener
*/
public void setOpenH264HelperListener(OpenH264DownloadHelperListener h264Listener) {
openH264DownloadHelperListener = h264Listener;
}
/**
* @return OpenH264DownloadHelperListener
*/
public OpenH264DownloadHelperListener getOpenH264DownloadHelperListener() {
return openH264DownloadHelperListener;
}
/**
* @param index of object in UserData list
* @constraints (index >= 0 && index < userData.size())
* @return object if constraints are met
*/
public Object getUserData(int index) {
if (index < 0 || index >= userData.size()) return null;
return userData.get(index);
}
/**
* Adding of object into UserData list
* @param object
* @return index of object in UserData list
*/
public int setUserData(Object object) {
this.userData.add(object);
return this.userData.indexOf(object);
}
/**
* @param index
* @param object
* @constraints (index >= 0 && index < userData.size())
*/
public void setUserData(int index, Object object) {
if (index < 0 || index > userData.size()) return;
this.userData.add(index,object);
}
/**
* @return size of UserData list
*/
public int getUserDataSize() {
return this.userData.size();
}
/**
* @return OpenH264 license message
*/
public String getLicenseMessage() {
return licenseMessage;
}
/**
* Set filename to storage for OpenH264 codec
* @param name
*/
public void setNameLib(String name) {
nameLib = name;
}
/**
* @return filename of OpenH264 codec
*/
public String getNameLib() {
return nameLib;
}
/**
* @return path of the lib
*/
public String getFullPathLib() {
return this.fileDirection + "/" + this.getNameLib();
}
/**
* Set name download file
* @param name : must be the same name relative to the url
*/
public void setNameFileDownload(String name) {
nameFileDownload = name;
}
/**
* Set new url
* @param url : must be a Cisco Url to OpenH264 and .bzip2 file
*/
public void setUrlDownload(String url) {
urlDownload = url;
}
/**
* Indicates whether the lib exists
* Requirements : fileDirection and nameLib init
* @return file exists ?
*/
public boolean isCodecFound() {
return new File(fileDirection+"/" + nameLib).exists();
}
/**
* Try to download and load codec
* Requirements :
* fileDirection
* nameFileDownload
* urlDownload
* nameLib
* codecDownListener
*/
public void downloadCodec() {
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
try {
String path = fileDirection+"/" + nameLib;
URL url = new URL(urlDownload);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.connect();
Log.i("OpenH264Downloader"," ");
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(fileDirection+"/"+nameFileDownload);
int totalSize = urlConnection.getContentLength();
openH264DownloadHelperListener.OnProgress(0,totalSize);
Log.i("OpenH264Downloader"," Download file:" + nameFileDownload);
byte[] buffer = new byte[4096];
int bufferLength;
int total = 0;
while((bufferLength = inputStream.read(buffer))>0 ){
total += bufferLength;
fileOutputStream.write(buffer, 0, bufferLength);
openH264DownloadHelperListener.OnProgress(total, totalSize);
}
fileOutputStream.close();
inputStream.close();
Log.i("OpenH264Downloader"," Uncompress file:" + nameFileDownload);
FileInputStream in = new FileInputStream(fileDirection+"/"+nameFileDownload);
FileOutputStream out = new FileOutputStream(path);
BZip2CompressorInputStream bzIn = new BZip2CompressorInputStream(in);
while ((bufferLength = bzIn.read(buffer))>0) {
out.write(buffer, 0, bufferLength);
}
in.close();
out.close();
bzIn.close();
Log.i("OpenH264Downloader"," Remove file:" + nameFileDownload);
new File(fileDirection+"/"+nameFileDownload).delete();
Log.i("OpenH264Downloader"," Loading plugin:" + path);
System.load(path);
openH264DownloadHelperListener.OnProgress(2,1);
} catch (FileNotFoundException e) {
openH264DownloadHelperListener.OnError(e.getLocalizedMessage());
} catch (IOException e) {
openH264DownloadHelperListener.OnError(e.getLocalizedMessage());
}
}
});
thread.start();
}
}
LinphoneCoreImpl.java
说明
是否允许下载H264
代码
public void enableDownloadOpenH264(boolean enable) {
Log.i("[LinphoneCoreImpl] enableDownloadOpenH264 enable = " + enable);
openh264DownloadEnabled = enable;
}
public boolean downloadOpenH264Enabled() {
Log.i("[LinphoneCoreImpl] downloadOpenH264Enabled return openh264DownloadEnabled = " + openh264DownloadEnabled);
return openh264DownloadEnabled;
}
LinphoneManager.java
说明
代码
public void initOpenH264DownloadHelper() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
Log.i("Android >= 5.1 we disable the download of OpenH264");
getLc().enableDownloadOpenH264(false);
return;
}
mCodecDownloader = LinphoneCoreFactory.instance().createOpenH264DownloadHelper();
mCodecListener = new OpenH264DownloadHelperListener() {
ProgressDialog progress;
int ctxt = 0;
int box = 1;
@Override
public void OnProgress(final int current, final int max) {
mHandler.post(new Runnable() {
@Override
public void run() {
OpenH264DownloadHelper ohcodec = LinphoneManager.getInstance().getOpenH264DownloadHelper();
if (progress == null) {
progress = new ProgressDialog((Context) ohcodec.getUserData(ctxt));
progress.setCanceledOnTouchOutside(false);
progress.setCancelable(false);
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
} else if (current <= max) {
progress.setMessage(getString(R.string.assistant_openh264_downloading));
progress.setMax(max);
progress.setProgress(current);
progress.show();
} else {
progress.dismiss();
progress = null;
LinphoneManager.getLc().reloadMsPlugins(LinphoneManager.this.getContext().getApplicationInfo().nativeLibraryDir);
if (ohcodec.getUserDataSize() > box && ohcodec.getUserData(box) != null) {
((CheckBoxPreference) ohcodec.getUserData(box)).setSummary(mCodecDownloader.getLicenseMessage());
((CheckBoxPreference) ohcodec.getUserData(box)).setTitle("OpenH264");
}
}
}
});
}
使用iniitOpenH264DownloadHelper()
public synchronized static final LinphoneManager createAndStart(Context c) {
if (instance != null)
throw new RuntimeException("Linphone Manager is already initialized");
instance = new LinphoneManager(c);
instance.startLibLinphone(c);
instance.initOpenH264DownloadHelper();
// H264 codec Management - set to auto mode -> MediaCodec >= android 5.0 >= OpenH264
//H264Helper.setH264Mode(H264Helper.MODE_AUTO, getLc());
H264Helper.setH264Mode(H264Helper.MODE_OPENH264, getLc());
TelephonyManager tm = (TelephonyManager) c.getSystemService(Context.TELEPHONY_SERVICE);
boolean gsmIdle = tm.getCallState() == TelephonyManager.CALL_STATE_IDLE;
setGsmIdle(gsmIdle);
return instance;
}
createAndStart()方法在LinphoneService创建的时候使用。
LinphoneService.java
public void onCreate() {
...
LinphoneManager.createAndStart(LinphoneService.this);
...
}
用到的地方-显示篇章-主要的显示逻辑
SettingsFragment.java
说明
主要是显示视频编码的地方。
代码
initVideoSettings()
private void initVideoSettings() {
initializePreferredVideoSizePreferences((ListPreference) findPreference(getString(R.string.pref_preferred_video_size_key)));
initializePreferredVideoFpsPreferences((ListPreference) findPreference(getString(R.string.pref_preferred_video_fps_key)));
EditTextPreference bandwidth = (EditTextPreference) findPreference(getString(R.string.pref_bandwidth_limit_key));
bandwidth.setText(Integer.toString(mPrefs.getBandwidthLimit()));
bandwidth.setSummary(bandwidth.getText());
updateVideoPreferencesAccordingToPreset();
ListPreference videoPresetPref = (ListPreference) findPreference(getString(R.string.pref_video_preset_key));
videoPresetPref.setSummary(mPrefs.getVideoPreset());
videoPresetPref.setValue(mPrefs.getVideoPreset());
PreferenceCategory codecs = (PreferenceCategory) findPreference(getString(R.string.pref_video_codecs_key));
codecs.removeAll();
final LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
final OpenH264DownloadHelper mCodecDownloader = LinphoneManager.getInstance().getOpenH264DownloadHelper();
for (final PayloadType pt : lc.getVideoCodecs()) {
final CheckBoxPreference codec = new CheckBoxPreference(getActivity());
codec.setTitle(pt.getMime());
if (!pt.getMime().equals("VP8")) {
Log.i("[SettingsFragment] !pt.getMime().equals(\"VP8\"");
if (getResources().getBoolean(R.bool.disable_all_patented_codecs_for_markets)) {
continue;
} else {
if (!Version.hasFastCpuWithAsmOptim() && pt.getMime().equals("H264"))
{
// Android without neon doesn't support H264
Log.w("CPU does not have asm optimisations available, disabling H264");
continue;
}
}
}
if (lc.downloadOpenH264Enabled()) {
if (pt.getMime().equals("H264") && mCodecDownloader.isCodecFound()) {
codec.setSummary(mCodecDownloader.getLicenseMessage());
codec.setTitle("OpenH264");
}
}
codec.setChecked(lc.isPayloadTypeEnabled(pt));
codec.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enable = (Boolean) newValue;
try {
if (lc.downloadOpenH264Enabled()) {
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
&& pt.getMime().equals("H264") && !mCodecDownloader.isCodecFound()) {
mCodecDownloader.setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
mCodecDownloader.setUserData(0, LinphoneManager.getInstance().getContext());
mCodecDownloader.setUserData(1, codec);
AlertDialog.Builder builder = new AlertDialog.Builder(LinphoneManager.getInstance().getContext());
builder.setCancelable(false);
builder.setMessage("Do you agree to download " + mCodecDownloader.getLicenseMessage()).setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE)
mCodecDownloader.downloadCodec();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
// Disable H264
}
}
}).show();
}
}
LinphoneManager.getLcIfManagerNotDestroyedOrNull().enablePayloadType(pt, enable);
} catch (LinphoneCoreException e) {
Log.e(e);
}
return true; }
});
codecs.addPreference(codec);
}
((CheckBoxPreference) findPreference(getString(R.string.pref_video_enable_key))).setChecked(mPrefs.isVideoEnabled());
((CheckBoxPreference) findPreference(getString(R.string.pref_video_use_front_camera_key))).setChecked(mPrefs.useFrontCam());
((CheckBoxPreference) findPreference(getString(R.string.pref_video_initiate_call_with_video_key))).setChecked(mPrefs.shouldInitiateVideoCall());
((CheckBoxPreference) findPreference(getString(R.string.pref_video_automatically_accept_video_key))).setChecked(mPrefs.shouldAutomaticallyAcceptVideoRequests());
((CheckBoxPreference) findPreference(getString(R.string.pref_overlay_key))).setChecked(mPrefs.isOverlayEnabled());
}
这里用到了lc.getVideoCodecs(), 在Android 5.0以上是有H264编码的, 而且显示在了设置上.
LinphoneCore.java & LinphoneCoreImpl.java
public synchronized PayloadType[] getVideoCodecs() {
long[] typesPtr = listVideoPayloadTypes(nativePtr);
if (typesPtr == null) return null;
PayloadType[] codecs = new PayloadType[typesPtr.length];
for (int i = 0; i < codecs.length; i++) {
codecs[i] = new PayloadTypeImpl(typesPtr[i]);
}
return codecs;
}
这里是获取所有的视频编码。
然后调用层来加载所有的视频编码。
private native long[] listVideoPayloadTypes(long nativePtr);
linphonecore_jni.cc中
extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTypes(JNIEnv* env
,jobject thiz
,jlong lc) {
const bctbx_list_t* codecs = linphone_core_get_video_codecs((LinphoneCore*)lc);
size_t codecsCount = bctbx_list_size(codecs);
jlongArray jCodecs = env->NewLongArray(codecsCount);
jlong *jInternalArray = env->GetLongArrayElements(jCodecs, NULL);
for (size_t i = 0; i < codecsCount; i++ ) {
jInternalArray[i] = (unsigned long) (codecs->data);
codecs = codecs->next;
}
env->ReleaseLongArrayElements(jCodecs, jInternalArray, 0);
return jCodecs;
}
linphonecore.c中
const bctbx_list_t *linphone_core_get_video_codecs(const LinphoneCore *lc) {
return lc->codecs_conf.video_codecs;
}
LinphoneManager.java中
说明
整个获取VideoCodecs的逻辑是在LinhoneCore中获得的, 所以得明白LinphoneCore的生成, 也就是mLc的生成。
代码
initLiblinphone(LinphoneCore)中
private synchronized void initLiblinphone(LinphoneCore lc) throws LinphoneCoreException {
mLc = lc;
PreferencesMigrator prefMigrator = new PreferencesMigrator(mServiceContext);
prefMigrator.migrateRemoteProvisioningUriIfNeeded();
prefMigrator.migrateSharingServerUrlIfNeeded();
prefMigrator.doPresenceMigrationIfNeeded();
if (prefMigrator.isMigrationNeeded()) {
prefMigrator.doMigration();
}
mLc.setZrtpSecretsCache(basePath + "/zrtp_secrets");
try {
String versionName = mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionName;
if (versionName == null) {
versionName = String.valueOf(mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionCode);
}
mLc.setUserAgent("LinphoneAndroid", versionName);
} catch (NameNotFoundException e) {
Log.e(e, "cannot get version name");
}
mLc.setRingback(mRingbackSoundFile);
mLc.setRootCA(mLinphoneRootCaFile);
mLc.setPlayFile(mPauseSoundFile);
mLc.setChatDatabasePath(mChatDatabaseFile);
mLc.setCallLogsDatabasePath(mCallLogDatabaseFile);
mLc.setFriendsDatabasePath(mFriendsDatabaseFile);
mLc.setUserCertificatesPath(mUserCertificatePath);
subscribeFriendList(mPrefs.isFriendlistsubscriptionEnabled());
//mLc.setCallErrorTone(Reason.NotFound, mErrorToneFile);
enableDeviceRingtone(mPrefs.isDeviceRingtoneEnabled());
int availableCores = Runtime.getRuntime().availableProcessors();
Log.w("MediaStreamer : " + availableCores + " cores detected and configured");
mLc.setCpuCount(availableCores);
mLc.migrateCallLogs();
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
initPushNotificationsService();
}
/*
You cannot receive this through components declared in manifests, only
by explicitly registering for it with Context.registerReceiver(). This is a protected intent that can only
be sent by the system.
*/
mKeepAliveIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
mKeepAliveIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
mKeepAliveReceiver = new KeepAliveReceiver();
mServiceContext.registerReceiver(mKeepAliveReceiver, mKeepAliveIntentFilter);
mDozeIntentFilter = new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mDozeIntentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mDozeReceiver = new DozeReceiver();
mServiceContext.registerReceiver(mDozeReceiver, mDozeIntentFilter);
updateNetworkReachability();
resetCameraFromPreferences();
accountCreator = LinphoneCoreFactory.instance().createAccountCreator(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setDomain(getString(R.string.default_domain));
accountCreator.setListener(this);
startLibLinphone(Context c)中
private synchronized void startLibLinphone(Context c) {
try {
copyAssetsFromPackage();
//traces alway start with traces enable to not missed first initialization
mLc = LinphoneCoreFactory.instance().createLinphoneCore(this, mLinphoneConfigFile, mLinphoneFactoryConfigFile, null, c);
TimerTask lTask = new TimerTask() {
@Override
public void run() {
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
if (mLc != null) {
mLc.iterate();
}
}
});
}
};
/*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
} catch (Exception e) {
Log.e(e);
Log.e(e, "Cannot start linphone");
}
}
在LinphoneCoreFactoryImpl.java中
这里生成和创建了LinphoneCore
@Override
public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException {
try {
fcontext = (Context) context;
boolean openh264DownloadEnabled = false;
if (context != null) openh264DownloadEnabled = loadingDownloadedOpenH264(fcontext);
MediastreamerAndroidContext.setContext(context);
LinphoneCore lc = new LinphoneCoreImpl(listener);
Log.i("[LinphoneCoreFactoryImpl] createLinphoneCore2 lc.enableDownloadOpenH264(openh264DownloadEnabled) --> " + openh264DownloadEnabled);
lc.enableDownloadOpenH264(openh264DownloadEnabled);
if (context != null) lc.setContext(context);
return lc;
} catch (IOException e) {
throw new LinphoneCoreException("Cannot create LinphoneCore", e);
}
}
跟H264Helper中的setH264Mode有没有关系,答案是没有太大的关系
/**
* Define the Codec to use between MediaCodec and OpenH264
* Possible mode are:
* - Auto to let the system choose in function of you OS version,
* - OpenH264 to enable OpenH264 Encoder and Decoder,
* - Mediacodec to enable Mediacodec only.
* @param mode String value between Auto, OpenH264 and MediaCodec
*/
public static void setH264Mode(String mode, LinphoneCore linphoneCore){
if(mode.equals(MODE_OPENH264)){
Log.i("H264Helper"," setH264Mode MODE_OPENH264 - Mode = "+mode);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true);
}else if(mode.equals(MODE_MEDIA_CODEC)){
Log.i("H264Helper"," setH264Mode MODE_MEDIA_CODEC - Mode = "+mode);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true);
}else if(mode.equals(MODE_AUTO)){
Log.i("H264Helper"," setH264Mode MODE_AUTO - Mode = "+mode);
// if android >= 5.0 use MediaCodec
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
Log.i("H264Helper"," setH264Mode MODE_AUTO 1 - Mode = "+mode);
Log.i("LinphoneCoreFactoryImpl"," Openh264 disabled on the project, now using MediaCodec");
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , true);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , true);
}
//otherwise use OpenH264
else{
Log.i("H264Helper"," setH264Mode MODE_AUTO 2 - Mode = "+mode);
Log.i("LinphoneCoreFactoryImpl"," Openh264 enabled on the project");
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_DEC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_MEDIA_CODEC_ENC , false);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_DEC , true);
linphoneCore.getMSFactory().enableFilterFromName(FILTER_NAME_OPENH264_ENC , true);
}
}else {
Log.i("LinphoneCoreFactoryImpl"," Error: Openh264 mode not reconized !");
}
Log.i("H264Helper"," setH264Mode - Mode = "+mode);
}
多次修改setH264Mode, 这个是没有效果的。
问题出在了哪里? 先找找设置H264的地方吧,这个实在linphonecore_jni.cc中
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv* env
,jobject thiz
,jlong lc
,jlong pt
,jboolean enable) {
return (jint)linphone_core_enable_payload_type((LinphoneCore*)lc,(PayloadType*)pt,enable);
}
然后就找到了misc.c文件中的一些代码
int linphone_core_enable_payload_type(LinphoneCore *lc, LinphonePayloadType *pt, bool_t enabled){
if (bctbx_list_find(lc->codecs_conf.audio_codecs,pt) || bctbx_list_find(lc->codecs_conf.video_codecs,pt) || bctbx_list_find(lc->codecs_conf.text_codecs,pt)){
payload_type_set_enable(pt,enabled);
_linphone_core_codec_config_write(lc);
linphone_core_update_allocated_audio_bandwidth(lc);
return 0;
}
ms_error("Enabling codec not in audio or video list of PayloadType !");
return -1;
}
这里又使用了一些函数
static MS2_INLINE void payload_type_set_enable(PayloadType *pt,int value)
{
if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
}
最后找到了payloadtype.h中的代码, 发现没什么用
#define payload_type_set_flag(pt,flag) (pt)->flags|=((int)flag)
从得到编码集找找效果?回过头来继续看LinphoneCore结构体的结果
struct _LinphoneCore
{
...
codecs_config_t codecs_conf;
...
}
找到了codecs_config
typedef struct codecs_config
{
MSList *audio_codecs; /* list of audio codecs in order of preference*/
MSList *video_codecs;
MSList *text_codecs;
int dyn_pt;
int telephone_event_pt;
}codecs_config_t;
突然感觉两处很有用
linphone/coreapi/linphonecore.c: lc->codecs_conf.audio_codecs=codecs;
linphone/coreapi/linphonecore.c: lc->codecs_conf.video_codecs=codecs;
这两个都是设置codecs。
第一个设置codecs
# linphonecore.c
int linphone_core_set_video_codecs(LinphoneCore *lc, bctbx_list_t *codecs){
if (lc->codecs_conf.video_codecs!=NULL) bctbx_list_free(lc->codecs_conf.video_codecs);
lc->codecs_conf.video_codecs=codecs;
_linphone_core_codec_config_write(lc);
return 0;
}
这里面有这样一个函数_linphone_core_codec_config_write
# linphonecore.c
void _linphone_core_codec_config_write(LinphoneCore *lc){
if (linphone_core_ready(lc)){
PayloadType *pt;
codecs_config_t *config=&lc->codecs_conf;
bctbx_list_t *node;
char key[50];
int index;
index=0;
for(node=config->audio_codecs;node!=NULL;node=bctbx_list_next(node)){
pt=(PayloadType*)(node->data);
sprintf(key,"audio_codec_%i",index);
lp_config_set_string(lc->config,key,"mime",pt->mime_type);
lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
lp_config_set_int(lc->config,key,"channels",pt->channels);
lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
index++;
}
sprintf(key,"audio_codec_%i",index);
lp_config_clean_section (lc->config,key);
index=0;
for(node=config->video_codecs;node!=NULL;node=bctbx_list_next(node)){
pt=(PayloadType*)(node->data);
sprintf(key,"video_codec_%i",index);
lp_config_set_string(lc->config,key,"mime",pt->mime_type);
lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
index++;
}
sprintf(key,"video_codec_%i",index);
lp_config_clean_section (lc->config,key);
}
}
不管怎样, 这个是写入到配置文件的参数。 让我稍微看一看。
该往上找了
第二个设置codecs
跟上面是一个
linphone_core_set_video_codecs被linphonecore_jni.cc用到
codecs_config_config_read是什么
static void codecs_config_read(LinphoneCore *lc){
int i;
PayloadType *pt;
bctbx_list_t *audio_codecs=NULL;
bctbx_list_t *video_codecs=NULL;
bctbx_list_t *text_codecs=NULL;
lc->codecs_conf.dyn_pt=96;
lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101);
for (i=0;get_codec(lc,SalAudio,i,&pt);i++){
if (pt){
audio_codecs=codec_append_if_new(audio_codecs, pt);
}
}
audio_codecs = handle_missing_codecs(lc, lc->default_audio_codecs,audio_codecs, MSAudio);
for (i=0;get_codec(lc,SalVideo,i,&pt);i++){
if (pt){
video_codecs=codec_append_if_new(video_codecs, pt);
}
}
video_codecs = handle_missing_codecs(lc, lc->default_video_codecs, video_codecs, MSVideo);
for (i=0;get_codec(lc,SalText,i,&pt);i++){
if (pt){
text_codecs=codec_append_if_new(text_codecs, pt);
}
}
text_codecs = add_missing_supported_codecs(lc, lc->default_text_codecs, text_codecs);
linphone_core_set_audio_codecs(lc,audio_codecs);
linphone_core_set_video_codecs(lc,video_codecs);
linphone_core_set_text_codecs(lc, text_codecs);
linphone_core_update_allocated_audio_bandwidth(lc);
}
追踪一下LinphoneCore的实例试试
全在newLinphoneCore()函数中
#linphonecore_jni.cc
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env
,jobject thiz
,jobject jlistener
,jstring juserConfig
,jstring jfactoryConfig
,jobject juserdata){
const char* userConfig = GetStringUTFChars(env, juserConfig);
const char* factoryConfig = GetStringUTFChars(env, jfactoryConfig);
LinphoneJavaBindings *ljb = new LinphoneJavaBindings(env);
LinphoneCoreVTable *vTable = linphone_core_v_table_new();
LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener, ljb);
linphone_core_v_table_set_user_data(vTable, ldata);
jobject core = env->NewGlobalRef(thiz);
ljb->setCore(core);
LinphoneCore *lc = linphone_core_new(vTable, userConfig, factoryConfig, ljb);
jlong nativePtr = (jlong)lc;
ReleaseStringUTFChars(env, juserConfig, userConfig);
ReleaseStringUTFChars(env, jfactoryConfig, factoryConfig);
return nativePtr;
}
这里用到了一下几个函数, 可以依依追踪一下
- LinphoneCoreVTable *vTable = linphone_core_v_table_new();
- LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener, ljb);
- linphone_core_v_table_set_user_data(vTable, ldata);
- LinphoneCore *lc = linphone_core_new(vTable, userConfig, factoryConfig, ljb);
LinphoneCoreVTable, 回调的一些状态
/**
* This structure holds all callbacks that the application should implement.
* None is mandatory.
**/
typedef struct _LinphoneCoreVTable{
LinphoneCoreGlobalStateChangedCb global_state_changed; /**<Notifies global state changes*/
LinphoneCoreRegistrationStateChangedCb registration_state_changed;/**<Notifies registration state changes*/
LinphoneCoreCallStateChangedCb call_state_changed;/**<Notifies call state changes*/
LinphoneCoreNotifyPresenceReceivedCb notify_presence_received; /**< Notify received presence events*/
LinphoneCoreNotifyPresenceReceivedForUriOrTelCb notify_presence_received_for_uri_or_tel; /**< Notify received presence events*/
LinphoneCoreNewSubscriptionRequestedCb new_subscription_requested; /**< Notify about pending presence subscription request */
LINPHONE_DEPRECATED LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< @deprecated Use authentication_requested instead. Ask the application some authentication information */
LinphoneCoreAuthenticationRequestedCb authentication_requested; /**< Ask the application some authentication information */
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
LinphoneCoreMessageReceivedCb message_received; /**< a message is received, can be text or external body*/
LinphoneCoreCbsMessageReceivedUnableDecryptCb message_received_unable_decrypt; /**< an encrypted message is received but we can't decrypt it*/
LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */
LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */
LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
LinphoneCoreTransferStateChangedCb transfer_state_changed; /**<Notifies when a transfer is in progress */
LinphoneCoreBuddyInfoUpdatedCb buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
LinphoneCoreCallStatsUpdatedCb call_stats_updated; /**<Notifies on refreshing of call's statistics. */
LinphoneCoreInfoReceivedCb info_received; /**<Notifies an incoming informational message received.*/
LinphoneCoreSubscriptionStateChangedCb subscription_state_changed; /**<Notifies subscription state change */
LinphoneCoreNotifyReceivedCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */
LinphoneCorePublishStateChangedCb publish_state_changed;/**Notifies publish state change (only from #LinphoneEvent api)*/
LinphoneCoreConfiguringStatusCb configuring_status; /** Notifies configuring status changes */
LINPHONE_DEPRECATED DisplayStatusCb display_status; /**< @deprecated Callback that notifies various events with human readable text.*/
LINPHONE_DEPRECATED DisplayMessageCb display_message;/**< @deprecated Callback to display a message to the user */
LINPHONE_DEPRECATED DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */
LINPHONE_DEPRECATED DisplayUrlCb display_url; /**< @deprecated */
LINPHONE_DEPRECATED ShowInterfaceCb show; /**< vNotifies the application that it should show up*/
LINPHONE_DEPRECATED LinphoneCoreTextMessageReceivedCb text_received; /**< @deprecated, use #message_received instead <br> A text message has been received */
LINPHONE_DEPRECATED LinphoneCoreFileTransferRecvCb file_transfer_recv; /**< @deprecated Callback to store file received attached to a #LinphoneChatMessage */
LINPHONE_DEPRECATED LinphoneCoreFileTransferSendCb file_transfer_send; /**< @deprecated Callback to collect file chunk to be sent for a #LinphoneChatMessage */
LINPHONE_DEPRECATED LinphoneCoreFileTransferProgressIndicationCb file_transfer_progress_indication; /**< @deprecated Callback to indicate file transfer progress */
LinphoneCoreNetworkReachableCb network_reachable; /**< Callback to report IP network status (I.E up/down )*/
LinphoneCoreLogCollectionUploadStateChangedCb log_collection_upload_state_changed; /**< Callback to upload collected logs */
LinphoneCoreLogCollectionUploadProgressIndicationCb log_collection_upload_progress_indication; /**< Callback to indicate log collection upload progress */
LinphoneCoreFriendListCreatedCb friend_list_created;
LinphoneCoreFriendListRemovedCb friend_list_removed;
void *user_data; /**<User data associated with the above callbacks */
} LinphoneCoreVTable;
linphone_core_v_table_new()就是创建一个内存空间
LinphoneCoreVTable *linphone_core_v_table_new() {
return ms_new0(LinphoneCoreVTable,1);
}
LinphoneCoreData, 这个代码实在有点长, 但这个才是真正回调的逻辑, 前边LinphoneJavaBinding只是绑定java程序而已。
class LinphoneCoreData {
public:
LinphoneCoreData(JNIEnv *env, jobject lc, LinphoneCoreVTable *vTable, jobject alistener, LinphoneJavaBindings *ljb) {
core = env->NewGlobalRef(lc);
listener = env->NewGlobalRef(alistener);
memset(vTable, 0, sizeof(LinphoneCoreVTable));
if (ljb->displayStatusId) {
vTable->display_status = displayStatusCb;
}
if (ljb->globalStateId) {
vTable->global_state_changed = globalStateChange;
}
if (ljb->registrationStateId) {
vTable->registration_state_changed = registrationStateChange;
}
if (ljb->callStateId) {
vTable->call_state_changed = callStateChange;
}
if (ljb->transferStateId) {
vTable->transfer_state_changed = transferStateChanged;
}
if (ljb->callStatsUpdatedId) {
vTable->call_stats_updated = callStatsUpdated;
}
if (ljb->callEncryptionChangedId) {
vTable->call_encryption_changed = callEncryptionChange;
}
if (ljb->newSubscriptionRequestId) {
vTable->new_subscription_requested = new_subscription_requested;
}
if (ljb->authInfoRequestedId) {
vTable->auth_info_requested = authInfoRequested;
}
if (ljb->authenticationRequestedId) {
vTable->authentication_requested = authenticationRequested;
}
if (ljb->notifyPresenceReceivedId) {
vTable->notify_presence_received = notify_presence_received;
}
if (ljb->messageReceivedId) {
vTable->message_received = message_received;
}
if (ljb->messageReceivedUnableToDecryptedId) {
vTable->message_received_unable_decrypt = message_received_unable_decrypt;
}
if (ljb->isComposingReceivedId) {
vTable->is_composing_received = is_composing_received;
}
if (ljb->dtmfReceivedId) {
vTable->dtmf_received = dtmf_received;
}
if (ljb->infoReceivedId) {
vTable->info_received = infoReceived;
}
if (ljb->subscriptionStateId) {
vTable->subscription_state_changed = subscriptionStateChanged;
}
if (ljb->publishStateId) {
vTable->publish_state_changed = publishStateChanged;
}
if (ljb->notifyRecvId) {
vTable->notify_received = notifyReceived;
}
if (ljb->configuringStateId) {
vTable->configuring_status = configuringStatus;
}
if (ljb->fileTransferProgressIndicationId) {
vTable->file_transfer_progress_indication = fileTransferProgressIndication;
}
if (ljb->fileTransferSendId) {
vTable->file_transfer_send = fileTransferSend;
}
if (ljb->fileTransferRecvId) {
vTable->file_transfer_recv = fileTransferRecv;
}
if (ljb->logCollectionUploadProgressId) {
vTable->log_collection_upload_progress_indication = logCollectionUploadProgressIndication;
}
if (ljb->logCollectionUploadStateId) {
vTable->log_collection_upload_state_changed = logCollectionUploadStateChange;
}
if (ljb->friendListCreatedId) {
vTable->friend_list_created = friendListCreated;
}
if (ljb->friendListRemovedId) {
vTable->friend_list_removed = friendListRemoved;
}
}
~LinphoneCoreData() {
JNIEnv *env = 0;
jvm->AttachCurrentThread(&env,NULL);
env->DeleteGlobalRef(core);
env->DeleteGlobalRef(listener);
}
jobject core;
jobject listener;
LinphoneCoreVTable vTable;
static void displayStatusCb(LinphoneCore *lc, const char *message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener,ljb->displayStatusId,lcData->core,msg);
handle_possible_java_exception(env, lcData->listener);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring r = realm ? env->NewStringUTF(realm) : NULL;
jstring u = username ? env->NewStringUTF(username) : NULL;
jstring d = domain ? env->NewStringUTF(domain) : NULL;
env->CallVoidMethod(lcData->listener,
ljb->authInfoRequestedId,
lcData->core,
r,
u,
d
);
handle_possible_java_exception(env, lcData->listener);
if (r) {
env->DeleteLocalRef(r);
}
if (u) {
env->DeleteLocalRef(u);
}
if (d) {
env->DeleteLocalRef(d);
}
}
static void authenticationRequested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener,
ljb->authenticationRequestedId,
lcData->core,
getAuthInfo(env, lc, auth_info, lcData->core),
env->CallStaticObjectMethod(ljb->authMethodClass,ljb->authMethodFromIntId,(jint)method)
);
handle_possible_java_exception(env, lcData->listener);
}
static void setCoreIfNotDone(JNIEnv *env, jobject jcore, LinphoneCore *lc){
jclass objClass = env->GetObjectClass(jcore);
jfieldID myFieldID = env->GetFieldID(objClass, "nativePtr", "J");
jlong fieldVal = env->GetLongField(jcore, myFieldID);
if (fieldVal == 0){
env->SetLongField(jcore, myFieldID, (jlong)lc);
}
}
static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jobject jcore = lcData->core;
/*at this stage, the java object may not be aware of its C object, because linphone_core_new() hasn't returned yet.*/
setCoreIfNotDone(env,jcore, lc);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,ljb->globalStateId
,lcData->core
,env->CallStaticObjectMethod(ljb->globalStateClass,ljb->globalStateFromIntId,(jint)gstate),
msg);
handle_possible_java_exception(env, lcData->listener);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void registrationStateChange(LinphoneCore *lc, LinphoneProxyConfig* proxy,LinphoneRegistrationState state,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jproxy;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,ljb->registrationStateId
,lcData->core
,(jproxy=getProxy(env,proxy,lcData->core))
,env->CallStaticObjectMethod(ljb->registrationStateClass,ljb->registrationStateFromIntId,(jint)state),
msg);
handle_possible_java_exception(env, lcData->listener);
if (msg) {
env->DeleteLocalRef(msg);
}
if (jproxy) {
env->DeleteLocalRef(jproxy);
}
}
static void callStateChange(LinphoneCore *lc, LinphoneCall* call,LinphoneCallState state,const char* message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jcall;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = message ? env->NewStringUTF(message) : NULL;
env->CallVoidMethod(lcData->listener
,ljb->callStateId
,lcData->core
,(jcall=getCall(env,call))
,env->CallStaticObjectMethod(ljb->callStateClass,ljb->callStateFromIntId,(jint)state),
msg);
handle_possible_java_exception(env, lcData->listener);
if (state==LinphoneCallReleased) {
linphone_call_set_user_pointer(call,NULL);
env->DeleteGlobalRef(jcall);
}
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void callEncryptionChange(LinphoneCore *lc, LinphoneCall* call, bool_t encrypted,const char* authentication_token) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->callEncryptionChangedId
,lcData->core
,getCall(env,call)
,encrypted
,authentication_token ? env->NewStringUTF(authentication_token) : NULL);
handle_possible_java_exception(env, lcData->listener);
}
static void notify_presence_received(LinphoneCore *lc, LinphoneFriend *my_friend) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jfriend = NULL;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jfriend = getFriend(env, my_friend);
env->CallVoidMethod(lcData->listener
,ljb->notifyPresenceReceivedId
,lcData->core
,jfriend);
handle_possible_java_exception(env, lcData->listener);
env->DeleteLocalRef(jfriend);
}
static void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jobject jfriend = getFriend(env, my_friend);
env->CallVoidMethod(lcData->listener
,ljb->newSubscriptionRequestId
,lcData->core
,jfriend
,url ? env->NewStringUTF(url) : NULL);
env->DeleteLocalRef(jfriend);
handle_possible_java_exception(env, lcData->listener);
}
static void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->dtmfReceivedId
,lcData->core
,getCall(env,call)
,dtmf);
handle_possible_java_exception(env, lcData->listener);
}
static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
jobject jmsg;
jobject jroom;
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
/*note: we call linphone_chat_message_ref() because the application does not acquire the object when invoked from a callback*/
env->CallVoidMethod(lcData->listener
,ljb->messageReceivedId
,lcData->core
,(jroom = getChatRoom(env, room))
,(jmsg = getChatMessage(env, msg)));
handle_possible_java_exception(env, lcData->listener);
if (jmsg) {
env->DeleteLocalRef(jmsg);
}
if (jroom) {
env->DeleteLocalRef(jroom);
}
}
static void message_received_unable_decrypt(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
jobject jmsg;
jobject jroom;
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
/*note: we call linphone_chat_message_ref() because the application does not acquire the object when invoked from a callback*/
env->CallVoidMethod(lcData->listener
,ljb->messageReceivedUnableToDecryptedId
,lcData->core
,(jroom = getChatRoom(env, room))
,(jmsg = getChatMessage(env, msg)));
handle_possible_java_exception(env, lcData->listener);
if (jmsg) {
env->DeleteLocalRef(jmsg);
}
if (jroom) {
env->DeleteLocalRef(jroom);
}
}
static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
jobject jroom;
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->isComposingReceivedId
,lcData->core
,(jroom = getChatRoom(env, room)));
handle_possible_java_exception(env, lcData->listener);
if (jroom) {
env->DeleteLocalRef(jroom);
}
}
static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = (LinphoneCoreVTable*) data;
if (table && ljb) {
LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_v_table_get_user_data(table);
if (ljb->ecCalibrationStatusId) {
jobject state = env->CallStaticObjectMethod(ljb->ecCalibratorStatusClass, ljb->ecCalibratorStatusFromIntId, (jint)status);
env->CallVoidMethod(lcData->listener
,ljb->ecCalibrationStatusId
,lcData->core
,state
,delay_ms
,NULL);
handle_possible_java_exception(env, lcData->listener);
}
if (status != LinphoneEcCalibratorInProgress) {
linphone_core_v_table_destroy(table);
}
}
}
static void callStatsUpdated(LinphoneCore *lc, LinphoneCall* call, const LinphoneCallStats *stats) {
JNIEnv *env = 0;
jobject statsobj;
jobject callobj;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
statsobj = env->NewObject(ljb->callStatsClass, ljb->callStatsId, (jlong)call, (jlong)stats);
callobj = getCall(env, call);
env->CallVoidMethod(lcData->listener, ljb->callStatsUpdatedId, lcData->core, callobj, statsobj);
handle_possible_java_exception(env, lcData->listener);
if (statsobj) env->DeleteLocalRef(statsobj);
}
static void transferStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState remote_call_state){
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jcall;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->transferStateId
,lcData->core
,(jcall=getCall(env,call))
,env->CallStaticObjectMethod(ljb->callStateClass,ljb->callStateFromIntId,(jint)remote_call_state)
);
handle_possible_java_exception(env, lcData->listener);
}
static void infoReceived(LinphoneCore *lc, LinphoneCall*call, const LinphoneInfoMessage *info){
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneInfoMessage *copy_info=linphone_info_message_copy(info);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->infoReceivedId
,lcData->core
,getCall(env,call)
,env->NewObject(ljb->infoMessageClass,ljb->infoMessageCtor,(jlong)copy_info)
);
handle_possible_java_exception(env, lcData->listener);
}
static void subscriptionStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state){
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jevent;
jobject jstate;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jevent=getEvent(env,ev);
jstate=env->CallStaticObjectMethod(ljb->subscriptionStateClass,ljb->subscriptionStateFromIntId,(jint)state);
env->CallVoidMethod(lcData->listener
,ljb->subscriptionStateId
,lcData->core
,jevent
,jstate
);
handle_possible_java_exception(env, lcData->listener);
if (state==LinphoneSubscriptionTerminated){
/*loose the java reference */
linphone_event_set_user_data(ev,NULL);
env->DeleteGlobalRef(jevent);
}
}
static void publishStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jevent;
jobject jstate;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jevent=getEvent(env,ev);
jstate=env->CallStaticObjectMethod(ljb->publishStateClass,ljb->publishStateFromIntId,(jint)state);
env->CallVoidMethod(lcData->listener
,ljb->publishStateId
,lcData->core
,jevent
,jstate
);
handle_possible_java_exception(env, lcData->listener);
}
static void notifyReceived(LinphoneCore *lc, LinphoneEvent *ev, const char *evname, const LinphoneContent *content){
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
jobject jevent;
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jevent=getEvent(env,ev);
env->CallVoidMethod(lcData->listener
,ljb->notifyRecvId
,lcData->core
,jevent
,env->NewStringUTF(evname)
,content ? create_java_linphone_content(env,content) : NULL
);
handle_possible_java_exception(env, lcData->listener);
}
static void configuringStatus(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener, ljb->configuringStateId, lcData->core, env->CallStaticObjectMethod(ljb->configuringStateClass,ljb->configuringStateFromIntId,(jint)status), message ? env->NewStringUTF(message) : NULL);
handle_possible_java_exception(env, lcData->listener);
}
static void fileTransferProgressIndication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) {
JNIEnv *env = 0;
jobject jmsg;
size_t progress = (offset * 100) / total;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jobject jcontent = content ? create_java_linphone_content(env, content) : NULL;
env->CallVoidMethod(lcData->listener,
ljb->fileTransferProgressIndicationId,
lcData->core,
(jmsg = getChatMessage(env, message)),
jcontent,
progress);
if (jcontent) {
env->DeleteLocalRef(jcontent);
}
if (jmsg) {
env->DeleteLocalRef(jmsg);
}
handle_possible_java_exception(env, lcData->listener);
}
static void fileTransferSend(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size) {
JNIEnv *env = 0;
jobject jmsg;
size_t asking = *size;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jobject jcontent = content ? create_java_linphone_content(env, content) : NULL;
jobject jbuffer = buff ? env->NewDirectByteBuffer(buff, asking) : NULL;
*size = env->CallIntMethod(lcData->listener,
ljb->fileTransferSendId,
lcData->core,
(jmsg = getChatMessage(env, message)),
jcontent,
jbuffer,
asking);
if (jcontent) {
env->DeleteLocalRef(jcontent);
}
if (jbuffer) {
env->DeleteLocalRef(jbuffer);
}
if (jmsg) {
env->DeleteLocalRef(jmsg);
}
handle_possible_java_exception(env, lcData->listener);
}
static void fileTransferRecv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) {
JNIEnv *env = 0;
jobject jmsg;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jbyteArray jbytes = env->NewByteArray(size);
env->SetByteArrayRegion(jbytes, 0, size, (jbyte*)buff);
jobject jcontent = content ? create_java_linphone_content(env, content) : NULL;
env->CallVoidMethod(lcData->listener,
ljb->fileTransferRecvId,
lcData->core,
(jmsg = getChatMessage(env, message)),
jcontent,
jbytes,
size);
if (jcontent) {
env->DeleteLocalRef(jcontent);
}
if (jmsg) {
env->DeleteLocalRef(jmsg);
}
handle_possible_java_exception(env, lcData->listener);
}
static void logCollectionUploadProgressIndication(LinphoneCore *lc, size_t offset, size_t total) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->logCollectionUploadProgressId
,lcData->core
,(jlong)offset
,(jlong)total);
handle_possible_java_exception(env, lcData->listener);
}
static void logCollectionUploadStateChange(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
jstring msg = info ? env->NewStringUTF(info) : NULL;
env->CallVoidMethod(lcData->listener
,ljb->logCollectionUploadStateId
,lcData->core
,env->CallStaticObjectMethod(ljb->logCollectionUploadStateClass,ljb->logCollectionUploadStateFromIntId,(jint)state),
msg);
handle_possible_java_exception(env, lcData->listener);
if (msg) {
env->DeleteLocalRef(msg);
}
}
static void friendListCreated(LinphoneCore *lc, LinphoneFriendList *list) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->friendListCreatedId
,lcData->core
,getFriendList(env, list));
handle_possible_java_exception(env, lcData->listener);
}
static void friendListRemoved(LinphoneCore *lc, LinphoneFriendList *list) {
JNIEnv *env = 0;
jint result = jvm->AttachCurrentThread(&env,NULL);
if (result != 0) {
ms_error("cannot attach VM");
return;
}
jobject jfriendlist;
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_core_get_user_data(lc);
LinphoneCoreVTable *table = linphone_core_get_current_vtable(lc);
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_v_table_get_user_data(table);
env->CallVoidMethod(lcData->listener
,ljb->friendListRemovedId
,lcData->core
,(jfriendlist = getFriendList(env, list)));
handle_possible_java_exception(env, lcData->listener);
if (jfriendlist) {
env->DeleteLocalRef(jfriendlist);
}
}
private:
static inline void handle_possible_java_exception(JNIEnv *env, jobject listener)
{
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
ms_error("Listener %p raised an exception",listener);
}
}
};
原来所有的最原始的回调在这儿呢
# LinphoneManger implements LinphoneCoreListener
private synchronized void startLibLinphone(Context c) {
try {
copyAssetsFromPackage();
//traces alway start with traces enable to not missed first initialization
mLc = LinphoneCoreFactory.instance().createLinphoneCore(this, mLinphoneConfigFile, mLinphoneFactoryConfigFile, null, c);
TimerTask lTask = new TimerTask() {
@Override
public void run() {
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
if (mLc != null) {
mLc.iterate();
}
}
});
}
};
/*use schedule instead of scheduleAtFixedRate to avoid iterate from being call in burst after cpu wake up*/
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
} catch (Exception e) {
Log.e(e);
Log.e(e, "Cannot start linphone");
}
}
linphone_core_v_table_set_user_data(vTable, ldata);,这么小的函数让我忐忑啊, 可还是设置回调的
void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data) {
table->user_data = data;
}
linphone_core_new(vTable, userConfig, factoryConfig, ljb);, 这是这个线索最后的希望了。
static LinphoneCore *_linphone_core_new(const LinphoneCoreVTable *vtable,
const char *config_path, const char *factory_config_path, void * userdata) {
LinphoneCore *lc;
LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
lc=linphone_core_new_with_config(vtable, config, userdata);
lp_config_unref(config);
return lc;
}
LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
const char *config_path, const char *factory_config_path, void * userdata) {
return _linphone_core_new(vtable, config_path, factory_config_path, userdata);
}
这里又有几个函数
- LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
- lc=linphone_core_new_with_config(vtable, config, userdata);
- lp_config_unref(config);
LpConfig
#lpconfig.h
struct _LpConfig{
belle_sip_object_t base;
bctbx_vfs_file_t* pFile;
char *filename;
char *tmpfilename;
bctbx_list_t *sections;
int modified;
int readonly;
bctbx_vfs_t* g_bctbx_vfs;
};
liphone_config_new_with_factory
#lpconfig.c
LpConfig *linphone_config_new_with_factory(const char *config_filename, const char *factory_config_filename) {
LpConfig *lpconfig=belle_sip_object_new(LinphoneConfig);
if (_linphone_config_init_from_files(lpconfig, config_filename, factory_config_filename) == 0) {
return lpconfig;
} else {
ms_free(lpconfig);
return NULL;
}
}
通过这个跟文件打交道
static int _linphone_config_init_from_files(LinphoneConfig *lpconfig, const char *config_filename, const char *factory_config_filename) {
lpconfig->g_bctbx_vfs = bctbx_vfs_get_default();
if (config_filename!=NULL){
if(ortp_file_exist(config_filename) == 0) {
lpconfig->filename=lp_realpath(config_filename, NULL);
if(lpconfig->filename == NULL) {
ms_error("Could not find the real path of %s: %s", config_filename, strerror(errno));
goto fail;
}
} else {
lpconfig->filename = ms_strdup(config_filename);
}
lpconfig->tmpfilename=ortp_strdup_printf("%s.tmp",lpconfig->filename);
ms_message("Using (r/w) config information from %s", lpconfig->filename);
#if !defined(_WIN32)
{
struct stat fileStat;
if ((stat(lpconfig->filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) {
/* make existing configuration files non-group/world-accessible */
if (chmod(lpconfig->filename, S_IRUSR | S_IWUSR) == -1) {
ms_warning("unable to correct permissions on "
"configuration file: %s", strerror(errno));
}
}
}
#endif /*_WIN32*/
/*open with r+ to check if we can write on it later*/
lpconfig->pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,lpconfig->filename, "r+");
#ifdef RENAME_REQUIRES_NONEXISTENT_NEW_PATH
if (lpconfig->pFile == NULL){
lpconfig->pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,lpconfig->tmpfilename, "r+");
if (lpconfig->pFile == NULL){
ms_warning("Could not open %s but %s works, app may have crashed during last sync.",lpconfig->filename,lpconfig->tmpfilename);
}
}
#endif
if (lpconfig->pFile != NULL){
linphone_config_parse(lpconfig, lpconfig->pFile);
bctbx_file_close(lpconfig->pFile);
lpconfig->pFile = NULL;
lpconfig->modified=0;
}
}
if (factory_config_filename != NULL) {
linphone_config_read_file(lpconfig, factory_config_filename);
}
return 0;
fail:
return -1;
}
最后一个函数linphone_core_new_with_config, 比我想象的要简单
#linphone.c
LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) {
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
LinphoneCoreVTable *local_vtable = linphone_core_v_table_new();
LinphoneCore *core = NULL;
if (vtable != NULL) *local_vtable = *vtable;
_linphone_core_cbs_set_v_table(cbs, local_vtable, TRUE);
core = _linphone_core_new_with_config(cbs, config, userdata);
linphone_core_cbs_unref(cbs);
return core;
}
又新出来几个函数
- LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get())
- LinphoneCoreVTable *local_vtable = linphone_core_v_table_new();
- _linphone_core_cbs_set_v_table(cbs, local_vtable, TRUE);
- core = _linphone_core_new_with_config(cbs, config, userdata);
LinphoneCoreCbs
# private.h
struct _LinphoneCoreCbs {
belle_sip_object_t base;
LinphoneCoreVTable *vtable;
bool_t autorelease;
};
linphone_factory_get(void)
LinphoneFactory *linphone_factory_get(void) {
if (_factory == NULL) {
_factory = belle_sip_object_new(LinphoneFactory);
atexit(_linphone_factory_destroying_cb);
}
return _factory;
}
static void _linphone_factory_destroying_cb(void) {
if (_factory != NULL) {
belle_sip_object_unref(_factory);
_factory = NULL;
}
}
_linphone_core_cbs_new(void)
LinphoneCoreCbs *_linphone_core_cbs_new(void) {
LinphoneCoreCbs *obj = belle_sip_object_new(LinphoneCoreCbs);
obj->vtable = ms_new0(LinphoneCoreVTable, 1);
obj->autorelease = TRUE;
return obj;
}
LinphoneCoreVTable *linphone_core_v_table_new() {
return ms_new0(LinphoneCoreVTable,1);
}
_linphone_core_cbs_set_v_table
void _linphone_core_cbs_set_v_table(LinphoneCoreCbs *cbs, LinphoneCoreVTable *vtable, bool_t autorelease) {
ms_free(cbs->vtable);
cbs->vtable = vtable;
cbs->autorelease = autorelease;
}
_linphone_core_new_with_config
LinphoneCore *_linphone_core_new_with_config(LinphoneCoreCbs *cbs, struct _LpConfig *config, void *userdata) {
LinphoneCore *core = belle_sip_object_new(LinphoneCore);
linphone_core_init(core, cbs, config, userdata);
return core;
}
belle_sip_object_unref
#belle_sip_object.c
void belle_sip_object_unref(void *ptr){
belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr);
if (obj->ref <= -1) {
belle_sip_error("Object [%p] freed twice or corrupted !",obj);
if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name);
if (obj->name) belle_sip_error("Object name might be [%s]",obj->name);
belle_sip_fatal("Fatal object error encountered, aborting.");
return;
}
if (obj->vptr->initially_unowned && obj->ref==0){
if (obj->pool)
belle_sip_object_pool_remove(obj->pool,obj);
obj->ref=-1;
belle_sip_object_delete(obj);
return;
}
obj->ref--;
if (obj->ref == 0){
obj->ref = -1;
belle_sip_object_delete(obj);
}
}
linphone_core_init
static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata){
const char *remote_provisioning_uri = NULL;
LinphoneFactory *lfactory = linphone_factory_get();
LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new();
char *msplugins_dir;
char *image_resources_dir;
ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
linphone_task_list_init(&lc->hooks);
linphone_core_cbs_set_notify_received(internal_cbs, linphone_core_internal_notify_received);
linphone_core_cbs_set_subscription_state_changed(internal_cbs, linphone_core_internal_subscription_state_changed);
_linphone_core_add_callbacks(lc, internal_cbs, TRUE);
belle_sip_object_unref(internal_cbs);
if (cbs != NULL) {
_linphone_core_add_callbacks(lc, cbs, FALSE);
} else {
LinphoneCoreCbs *fallback_cbs = linphone_factory_create_core_cbs(linphone_factory_get());
_linphone_core_add_callbacks(lc, fallback_cbs, FALSE);
belle_sip_object_unref(fallback_cbs);
}
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
ortp_init();
linphone_core_activate_log_serialization_if_needed();
msplugins_dir = linphone_factory_get_msplugins_dir(lfactory);
lc->factory = ms_factory_new_with_voip_and_plugins_dir(msplugins_dir);
if (msplugins_dir) bctbx_free(msplugins_dir);
image_resources_dir = linphone_factory_get_image_resources_dir(lfactory);
ms_factory_set_image_resources_dir(lc->factory, image_resources_dir);
bctbx_free(image_resources_dir);
linphone_core_register_default_codecs(lc);
linphone_core_register_offer_answer_providers(lc);
/* Get the mediastreamer2 event queue */
/* This allows to run event's callback in linphone_core_iterate() */
lc->msevq=ms_factory_create_event_queue(lc->factory);
lc->sal=sal_init(lc->factory);
sal_set_http_proxy_host(lc->sal, linphone_core_get_http_proxy_host(lc));
sal_set_http_proxy_port(lc->sal, linphone_core_get_http_proxy_port(lc));
sal_set_user_pointer(lc->sal,lc);
sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
#ifdef TUNNEL_ENABLED
lc->tunnel=linphone_core_tunnel_new(lc);
#endif
lc->network_last_check = 0;
lc->network_last_status = FALSE;
/* Create the http provider in dual stack mode (ipv4 and ipv6.
* If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
*/
lc->http_provider = belle_sip_stack_create_http_provider(sal_get_stack_impl(lc->sal), "::0");
lc->http_crypto_config = belle_tls_crypto_config_new();
belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
certificates_config_read(lc);
lc->ringtoneplayer = linphone_ringtoneplayer_new();
#ifdef SQLITE_STORAGE_ENABLED
sqlite3_bctbx_vfs_register(0);
#endif
lc->vcard_context = linphone_vcard_context_new();
linphone_core_initialize_supported_content_types(lc);
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri == NULL) {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
} // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate)
lc->bw_controller = ms_bandwidth_controller_new();
}
linphone_core_register_default_codecs, 这个才是真正用得到的地方
static void linphone_core_register_default_codecs(LinphoneCore *lc){
const char *aac_fmtp162248, *aac_fmtp3244;
bool_t opus_enabled=TRUE;
/*default enabled audio codecs, in order of preference*/
#if defined(__arm__) || defined(_M_ARM)
/*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/
//if (ms_get_cpu_count()==1) opus_enabled=FALSE;
if (ms_factory_get_cpu_count(lc->factory)==1) opus_enabled=FALSE;
#endif
linphone_core_register_payload_type(lc,&payload_type_opus,"useinbandfec=1",opus_enabled);
linphone_core_register_payload_type(lc,&payload_type_silk_wb,NULL,TRUE);
linphone_core_register_payload_type(lc,&payload_type_speex_wb,"vbr=on",TRUE);
linphone_core_register_payload_type(lc,&payload_type_speex_nb,"vbr=on",TRUE);
linphone_core_register_payload_type(lc,&payload_type_pcmu8000,NULL,TRUE);
linphone_core_register_payload_type(lc,&payload_type_pcma8000,NULL,TRUE);
/* Text codecs in order or preference (RED first (more robust), then T140) */
linphone_core_register_payload_type(lc, &payload_type_t140_red, NULL, TRUE);
linphone_core_register_payload_type(lc, &payload_type_t140, NULL, TRUE);
/*other audio codecs, not enabled by default, in order of preference*/
linphone_core_register_payload_type(lc,&payload_type_gsm,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_g722,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_ilbc,"mode=30",FALSE);
linphone_core_register_payload_type(lc,&payload_type_amr,"octet-align=1",FALSE);
linphone_core_register_payload_type(lc,&payload_type_amrwb,"octet-align=1",FALSE);
linphone_core_register_payload_type(lc,&payload_type_g729,"annexb=yes",TRUE);
/* For AAC, we use a config value to determine if we ought to support SBR. Since it is not offically supported
* for the mpeg4-generic mime type, setting this flag to 1 will break compatibility with other clients. */
if( lp_config_get_int(lc->config, "misc", "aac_use_sbr", FALSE) ) {
ms_message("Using SBR for AAC");
aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5; SBR-enabled=1";
} else {
aac_fmtp162248 = "config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
aac_fmtp3244 = "config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5";
}
linphone_core_register_payload_type(lc,&payload_type_aaceld_16k,aac_fmtp162248,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aaceld_22k,aac_fmtp162248,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aaceld_32k,aac_fmtp3244,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aaceld_44k,aac_fmtp3244,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aaceld_48k,aac_fmtp162248,FALSE);
linphone_core_register_payload_type(lc,&payload_type_isac,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_speex_uwb,"vbr=on",FALSE);
linphone_core_register_payload_type(lc,&payload_type_silk_nb,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_silk_mb,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_silk_swb,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_g726_16,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_g726_24,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_g726_32,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_g726_40,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_16,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_24,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_32,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE);
linphone_core_register_payload_type(lc,&payload_type_bv16,NULL,FALSE);
#ifdef VIDEO_ENABLED
/*default enabled video codecs, in order of preference*/
linphone_core_register_payload_type(lc,&payload_type_vp8,NULL,TRUE);
linphone_core_register_payload_type(lc,&payload_type_h264,"profile-level-id=42801F",TRUE);
linphone_core_register_payload_type(lc,&payload_type_mp4v,"profile-level-id=3",TRUE);
linphone_core_register_payload_type(lc,&payload_type_h263_1998,"CIF=1;QCIF=1",FALSE);
linphone_core_register_payload_type(lc,&payload_type_h263,NULL,FALSE);
#endif
/*register all static payload types declared in av_profile of oRTP, if not already declared above*/
linphone_core_register_static_payloads(lc);
}
在这个函数中找到了一些端倪
static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){
bctbx_list_t **codec_list = const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : const_pt->type==PAYLOAD_TEXT ? &lc->default_text_codecs : &lc->default_audio_codecs;
PayloadType *pt=payload_type_clone(const_pt);
int number=-1;
payload_type_set_enable(pt,enabled);
if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
/*Set a number to the payload type from the statically defined (RFC3551) profile, if not static, -1 is returned
and the payload type number will be determined dynamically later, at call time.*/
payload_type_set_number(pt,
(number=rtp_profile_find_payload_number(&av_profile, pt->mime_type, pt->clock_rate, pt->channels))
);
ms_message("Codec %s/%i fmtp=[%s] number=%i, default enablement: %i) added to the list of possible codecs.", pt->mime_type, pt->clock_rate,
pt->recv_fmtp ? pt->recv_fmtp : "", number, (int)payload_type_enabled(pt));
*codec_list=bctbx_list_append(*codec_list,pt);
}
logcat中找到写区别
H264允许
Codec H264/90000 fmtp=[profile-level-id=42801F] number=-1, default enablement: 1) added to the list of possible codecs.
Codec H263-1998/90000 fmtp=[CIF=1;QCIF=1] number=-1, default enablement: 0) added to the list of possible codecs.
Codec H263/90000 fmtp=[] number=34, default enablement: 0) added to the list of possible codecs.
Codec H261/90000 fmtp=[] number=31, default enablement: 0) added to the list of possible codecs.
H264不允许
Codec H264/90000 fmtp=[profile-level-id=42801F] number=-1, default enablement: 1) added to the list of possible codecs.
Codec H263-1998/90000 fmtp=[CIF=1;QCIF=1] number=-1, default enablement: 0) added to the list of possible codecs.
Codec H263/90000 fmtp=[] number=34, default enablement: 0) added to the list of possible codecs.
Codec H261/90000 fmtp=[] number=31, default enablement: 0) added to the list of possible codecs
又一个突破点mLc.iterate(), 调用这个方法, 生成了配置文件
下面就是实实在在的使用的方法
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate(JNIEnv* env
,jobject thiz
,jlong lc) {
linphone_core_iterate((LinphoneCore*)lc);
}
linphone_core_iterate()方法的调用
void linphone_core_iterate(LinphoneCore *lc){
bctbx_list_t *calls;
LinphoneCall *call;
uint64_t curtime_ms = ms_get_cur_time_ms(); /*monotonic time*/
int elapsed;
time_t current_real_time = ms_time(NULL);
int64_t diff_time;
bool_t one_second_elapsed=FALSE;
const char *remote_provisioning_uri = NULL;
if (lc->network_reachable_to_be_notified) {
lc->network_reachable_to_be_notified=FALSE;
linphone_core_notify_network_reachable(lc,lc->sip_network_reachable);
}
if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) {
if (sal_get_root_ca(lc->sal)) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, sal_get_root_ca(lc->sal));
belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
}
linphone_core_notify_display_status(lc, _("Configuring"));
linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri) {
int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri);
if (err == -1) {
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI");
}
} // else linphone_configuring_terminated has already been called in linphone_core_init
}
if (lc->prevtime_ms == 0){
lc->prevtime_ms = curtime_ms;
}
if ((diff_time=curtime_ms-lc->prevtime_ms) >= 1000){
one_second_elapsed=TRUE;
if (diff_time>3000){
/*since monotonic time doesn't increment while machine is sleeping, we don't want to catchup too much*/
lc->prevtime_ms = curtime_ms;
}else{
lc->prevtime_ms += 1000;
}
}
if (lc->ecc!=NULL){
LinphoneEcCalibratorStatus ecs=ec_calibrator_get_status(lc->ecc);
if (ecs!=LinphoneEcCalibratorInProgress){
if (lc->ecc->cb)
lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
if (ecs==LinphoneEcCalibratorDone){
int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
int margin=len/2;
lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
} else if (ecs == LinphoneEcCalibratorFailed) {
lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
} else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
linphone_core_enable_echo_cancellation(lc, FALSE);
}
ec_calibrator_destroy(lc->ecc);
lc->ecc=NULL;
}
}
if (lc->preview_finished){
lc->preview_finished=0;
linphone_ringtoneplayer_stop(lc->ringtoneplayer);
lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
}
if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0
&& (curtime_ms/1000 - lc->dmfs_playing_start_time)>5){
MSPlayerState state;
bool_t stop=TRUE;
if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){
if (state==MSPlayerPlaying) stop=FALSE;
}
if (stop) {
ms_message("Releasing inactive tone player.");
linphone_core_stop_dtmf_stream(lc);
}
}
sal_iterate(lc->sal);
if (lc->msevq) ms_event_queue_pump(lc->msevq);
if (lc->auto_net_state_mon) monitor_network_state(lc, current_real_time);
proxy_update(lc);
//we have to iterate for each call
calls = lc->calls;
while(calls!= NULL){
call = (LinphoneCall *)calls->data;
elapsed = (int)(current_real_time - call->log->start_date_time);
/* get immediately a reference to next one in case the one
we are going to examine is destroy and removed during
linphone_call_start_invite() */
calls=calls->next;
linphone_call_background_tasks(call,one_second_elapsed);
if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
/*start the call even if the OPTIONS reply did not arrive*/
if (call->ice_session != NULL) {
ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
,linphone_core_get_stun_server(lc));
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
}
#ifdef BUILD_UPNP
if (call->upnp_session != NULL) {
ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway.");
linphone_call_delete_upnp_session(call);
}
#endif //BUILD_UPNP
linphone_call_start_invite(call, NULL);
}
if (call->state==LinphoneCallIncomingReceived || call->state==LinphoneCallIncomingEarlyMedia){
if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed);
if (elapsed>lc->sip_conf.inc_timeout){
LinphoneReason decline_reason;
ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout);
decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined;
call->log->status=LinphoneCallMissed;
sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL);
linphone_core_decline_call(lc,call,decline_reason);
}
}
if ( (lc->sip_conf.in_call_timeout > 0)
&& (call->log->connected_date_time != 0)
&& ((current_real_time - call->log->connected_date_time) > lc->sip_conf.in_call_timeout))
{
ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout);
linphone_core_terminate_call(lc,call);
}
}
if (linphone_core_video_preview_enabled(lc)){
if (lc->previewstream==NULL && lc->calls==NULL)
toggle_video_preview(lc,TRUE);
#ifdef VIDEO_ENABLED
if (lc->previewstream) video_stream_iterate(lc->previewstream);
#endif
}else{
if (lc->previewstream!=NULL)
toggle_video_preview(lc,FALSE);
}
linphone_core_run_hooks(lc);
linphone_core_do_plugin_tasks(lc);
if (lc->sip_network_reachable && lc->netup_time!=0 && (current_real_time-lc->netup_time)>=2){
/*not do that immediately, take your time.*/
linphone_core_send_initial_subscribes(lc);
}
if (one_second_elapsed) {
bctbx_list_t *elem = NULL;
if (lp_config_needs_commit(lc->config)) {
lp_config_sync(lc->config);
}
for (elem = lc->friends_lists; elem != NULL; elem = bctbx_list_next(elem)) {
LinphoneFriendList *list = (LinphoneFriendList *)elem->data;
if (list->dirty_friends_to_update) {
linphone_friend_list_update_dirty_friends(list);
}
}
}
if (liblinphone_serialize_logs == TRUE) {
ortp_logv_flush();
}
}
追踪从哪里获得的数据, 从get_codec函数开始
这个函数专门用来判断是否有这个编码的, 这里主要是看视频编码。
# linphonecore.c
static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, PayloadType **ret){
char codeckey[50];
const char *mime,*fmtp;
int rate,channels,enabled;
PayloadType *pt;
LpConfig *config=lc->config;
*ret=NULL;
snprintf(codeckey,50,"%s_codec_%i",type == SalAudio ? "audio" : type == SalVideo ? "video" : "text", index);
mime=lp_config_get_string(config,codeckey,"mime",NULL);
if (mime==NULL || strlen(mime)==0 ) return FALSE;
rate=lp_config_get_int(config,codeckey,"rate",8000);
fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
channels=lp_config_get_int(config,codeckey,"channels",0);
enabled=lp_config_get_int(config,codeckey,"enabled",1);
if (!linphone_core_codec_supported(lc, type, mime)){
ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate);
return TRUE;
}
pt = find_payload(type == SalAudio ? lc->default_audio_codecs : type == SalVideo ? lc->default_video_codecs : lc->default_text_codecs ,mime,rate,channels,fmtp);
if (!pt){
bctbx_list_t **default_list = (type==SalAudio) ? &lc->default_audio_codecs : type == SalVideo ? &lc->default_video_codecs : &lc->default_text_codecs;
if (type == SalAudio)
ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels);
else if (type == SalVideo)
ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate);
else
ms_warning("Codec %s read from conf is not in the default list.",mime);
pt=payload_type_new();
pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : type == SalVideo ? PAYLOAD_VIDEO : PAYLOAD_TEXT;
pt->mime_type=ortp_strdup(mime);
pt->clock_rate=rate;
pt->channels=channels;
payload_type_set_number(pt,-1); /*dynamic assignment*/
payload_type_set_recv_fmtp(pt,fmtp);
*default_list=bctbx_list_append(*default_list, pt);
}
if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
else pt->flags&=~PAYLOAD_TYPE_ENABLED;
*ret=pt;
return TRUE;
}
找一下PayloadType结构体, 看看能不能打印出信息。
#payloadtype.h
struct _PayloadType
{
int type; /**< one of PAYLOAD_* macros*/
int clock_rate; /**< rtp clock rate*/
char bits_per_sample; /* in case of continuous audio data */
char *zero_pattern;
int pattern_length;
/* other useful information for the application*/
int normal_bitrate; /*in bit/s */
char *mime_type; /**<actually the submime, ex: pcm, pcma, gsm*/
int channels; /**< number of channels of audio */
char *recv_fmtp; /* various format parameters for the incoming stream */
char *send_fmtp; /* various format parameters for the outgoing stream */
struct _PayloadTypeAvpfParams avpf; /* AVPF parameters */
int flags;
void *user_data;
};
linphone_config_get_string是要获取mime的
# lpconfig.c
const char *linphone_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){
LpSection *sec;
LpItem *item;
sec=linphone_config_find_section(lpconfig,section);
if (sec!=NULL){
item=lp_section_find_item(sec,key);
if (item!=NULL) return item->value;
}
return default_string;
}
LpSection *linphone_config_find_section(const LpConfig *lpconfig, const char *name){
LpSection *sec;
bctbx_list_t *elem;
/*printf("Looking for section %s\n",name);*/
for (elem=lpconfig->sections;elem!=NULL;elem=bctbx_list_next(elem)){
sec=(LpSection*)elem->data;
if (strcmp(sec->name,name)==0){
/*printf("Section %s found\n",name);*/
return sec;
}
}
return NULL;
}
Could not find encoder for H264
#msfactory.c
bool_t ms_factory_codec_supported(MSFactory* factory, const char *mime){
MSFilterDesc *enc = ms_factory_get_encoding_capturer(factory, mime);
MSFilterDesc *dec = ms_factory_get_decoding_renderer(factory, mime);
if (enc == NULL) enc = ms_factory_get_encoder(factory, mime);
if (dec == NULL) dec = ms_factory_get_decoder(factory, mime);
if(enc!=NULL && dec!=NULL) return TRUE;
if(enc==NULL) ms_message("[get_codec] Could not find encoder for %s", mime);
if(dec==NULL) ms_message("[get_codec] Could not find decoder for %s", mime);
return FALSE;
}
linphone/coreapi/misc.c: if (ms_factory_codec_supported(lc->factory, pt->mime_type)){
linphone/coreapi/linphonecore.c: return ms_factory_codec_supported(lc->factory, mime);
linphone/tester/dtmf_tester.c: if(!ms_factory_codec_supported(marie->lc->factory, "opus") && !ms_factory_codec_supported(pauline->lc->factory, "opus")){
linphone/tester/call_single_tester.c: if(!ms_factory_codec_supported(marie->lc->factory, "opus") && !ms_factory_codec_supported(pauline->lc->factory, "opus")){
linphone/mediastreamer2/src/base/msfactory.c:bool_t ms_factory_codec_supported(MSFactory* factory, const char *mime){
linphone/mediastreamer2/src/base/msfilter.c: return ms_factory_codec_supported(ms_factory_get_fallback(),mime);
ms_factory_get_encoder
MSFilterDesc * ms_factory_get_encoder(MSFactory* factory, const char *mime){
bctbx_list_t *elem;
for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
MSFilterDesc *desc=(MSFilterDesc*)elem->data;
if ((desc->flags & MS_FILTER_IS_ENABLED)
&& (desc->category==MS_FILTER_ENCODER || desc->category==MS_FILTER_ENCODING_CAPTURER)
&& strcasecmp(desc->enc_fmt,mime)==0){
return desc;
}
}
return NULL;
}
_MSFilterDesc
struct _MSFilterDesc{
MSFilterId id; /**< the id declared in allfilters.h */
const char *name; /**< the filter name*/
const char *text; /**< short text describing the filter's function*/
MSFilterCategory category; /**< filter's category*/
const char *enc_fmt; /**< sub-mime of the format, must be set if category is MS_FILTER_ENCODER or MS_FILTER_DECODER */
int ninputs; /**< number of inputs */
int noutputs; /**< number of outputs */
MSFilterFunc init; /**< Filter's init function*/
MSFilterFunc preprocess; /**< Filter's preprocess function, called one time before starting to process*/
MSFilterFunc process; /**< Filter's process function, called every tick by the MSTicker to do the filter's job*/
MSFilterFunc postprocess; /**< Filter's postprocess function, called once after processing (the filter is no longer called in process() after)*/
MSFilterFunc uninit; /**< Filter's uninit function, used to deallocate internal structures*/
MSFilterMethod *methods; /**<Filter's method table*/
unsigned int flags; /**<Filter's special flags, from the MSFilterFlags enum.*/
};
过滤的一些参数
I/Linphone(25635): [ms_factory_get_encoding_capturer] mime = VP8
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRtcIlbcDec , text=WebRtc's iLBC decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRtcIlbcEnc , text=WebRtc's iLBC encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRTCAEC , text=Echo canceller using WebRTC library., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSiSACDec , text=iSAC audio decoder filter., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSiSACEnc , text=iSAC audio encoder filter., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSBCG729Dec , text=G729 audio decoder filter, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSBCG729Enc , text=G729 audio encoder filter, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSILKDec , text=Silk decoder filter., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSILKEnc , text=SILK audio encoder filter., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAndroidDisplay , text=OpenGL-ES2 video display filter for Android., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAndroidVideoCapture , text=A filter that captures Android video., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMKVPlayer , text=MKV file player, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMKVRecorder , text=MKV file recorder, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVp8Dec , text=A VP8 video decoder using libvpx library., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVp8Enc , text=A VP8 video encoder using libvpx library., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSJpegWriter , text=Take a video snapshot as jpg file, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSizeConv , text=a small video size converter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSPixConv , text=A pixel format converter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSStaticImage , text=A filter that outputs a static image., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMire , text=A filter that outputs synthetic moving picture, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSExtDisplay , text=A display filter sending the buffers to draw to the upper layer, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexEC , text=Echo canceller using speex library, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexEnc , text=The free and wonderful speex codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexDec , text=The free and wonderful speex codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSResample , text=Audio resampler, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSOpusDec , text=An opus decoder., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSOpusEnc , text=An opus encoder., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGsmEnc , text=The GSM full-rate codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGsmDec , text=The GSM codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUdpSend , text=UDP output filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRTT4103Sink , text=A filter to receive real time text, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRTT4103Source , text=A filter to send real time text, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRtpRecv , text=RTP input filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRtpSend , text=RTP output filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUlawEnc , text=ITU-G.711 ulaw encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUlawDec , text=ITU-G.711 ulaw decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSToneDetector , text=Custom tone detection filter., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVolume , text=A filter that controls and measure sound volume, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVadDtx , text=A filter detecting silence period and encoding residual noise, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSG722Enc , text=The G.722 wideband codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSG722Dec , text=The G.722 wideband codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSFileRec , text=Wav file recorder, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSFilePlayer , text=Raw files and wav reader, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSL16Enc , text=L16 dummy encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSL16Dec , text=L16 dummy decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGenericPLC , text=Generic PLC., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSEqualizer , text=Parametric sound equalizer., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSDtmfGen , text=DTMF generator, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSChannelAdapter , text=A filter that converts from mono to stereo and vice versa., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAudioMixer , text=A filter that mixes down 16 bit sample audio streams, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAlawEnc , text=ITU-G.711 alaw encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAlawDec , text=ITU-G.711 alaw decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVoidSink , text=A filter that trashes its input (useful for terminating some graphs)., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVoidSource , text=A filter that generates silence on its output (useful for beginning some graphs)., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSTee , text=A filter that reads from input and copy to its multiple outputs., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSJoin , text=A filter that send several inputs to one output., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSItcSink , text=Inter ticker communication filter., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSItcSource , text=Inter ticker communication filter., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] mime = H264
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRtcIlbcDec , text=WebRtc's iLBC decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRtcIlbcEnc , text=WebRtc's iLBC encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSWebRTCAEC , text=Echo canceller using WebRTC library., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSiSACDec , text=iSAC audio decoder filter., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSiSACEnc , text=iSAC audio encoder filter., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSBCG729Dec , text=G729 audio decoder filter, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSBCG729Enc , text=G729 audio encoder filter, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSILKDec , text=Silk decoder filter., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSILKEnc , text=SILK audio encoder filter., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAndroidDisplay , text=OpenGL-ES2 video display filter for Android., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAndroidVideoCapture , text=A filter that captures Android video., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMKVPlayer , text=MKV file player, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMKVRecorder , text=MKV file recorder, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVp8Dec , text=A VP8 video decoder using libvpx library., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVp8Enc , text=A VP8 video encoder using libvpx library., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSJpegWriter , text=Take a video snapshot as jpg file, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSizeConv , text=a small video size converter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSPixConv , text=A pixel format converter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSStaticImage , text=A filter that outputs a static image., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSMire , text=A filter that outputs synthetic moving picture, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSExtDisplay , text=A display filter sending the buffers to draw to the upper layer, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexEC , text=Echo canceller using speex library, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexEnc , text=The free and wonderful speex codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSSpeexDec , text=The free and wonderful speex codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSResample , text=Audio resampler, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSOpusDec , text=An opus decoder., category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSOpusEnc , text=An opus encoder., category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGsmEnc , text=The GSM full-rate codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGsmDec , text=The GSM codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUdpSend , text=UDP output filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRTT4103Sink , text=A filter to receive real time text, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRTT4103Source , text=A filter to send real time text, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRtpRecv , text=RTP input filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSRtpSend , text=RTP output filter, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUlawEnc , text=ITU-G.711 ulaw encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSUlawDec , text=ITU-G.711 ulaw decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSToneDetector , text=Custom tone detection filter., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVolume , text=A filter that controls and measure sound volume, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVadDtx , text=A filter detecting silence period and encoding residual noise, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSG722Enc , text=The G.722 wideband codec, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSG722Dec , text=The G.722 wideband codec, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSFileRec , text=Wav file recorder, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSFilePlayer , text=Raw files and wav reader, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSL16Enc , text=L16 dummy encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSL16Dec , text=L16 dummy decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSGenericPLC , text=Generic PLC., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSEqualizer , text=Parametric sound equalizer., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSDtmfGen , text=DTMF generator, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSChannelAdapter , text=A filter that converts from mono to stereo and vice versa., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAudioMixer , text=A filter that mixes down 16 bit sample audio streams, category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAlawEnc , text=ITU-G.711 alaw encoder, category=1
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSAlawDec , text=ITU-G.711 alaw decoder, category=2
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVoidSink , text=A filter that trashes its input (useful for terminating some graphs)., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSVoidSource , text=A filter that generates silence on its output (useful for beginning some graphs)., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSTee , text=A filter that reads from input and copy to its multiple outputs., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSJoin , text=A filter that send several inputs to one output., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSItcSink , text=Inter ticker communication filter., category=0
I/Linphone(25635): [ms_factory_get_encoding_capturer] name=MSItcSource , text=Inter ticker communication filter., category=0
linphone_core_codec_supported
#linphonecore.c
static bool_t linphone_core_codec_supported(LinphoneCore *lc, SalStreamType type, const char *mime){
if (type == SalVideo && lp_config_get_int(lc->config, "video", "rtp_io", FALSE)){
return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/
} else if (type == SalAudio && lp_config_get_int(lc->config, "sound", "rtp_io", FALSE)){
return TRUE; /*in rtp io mode, we don't transcode video, thus we can support a format for which we have no encoder nor decoder.*/
} else if (type == SalText) {
return TRUE;
}
return ms_factory_codec_supported(lc->factory, mime);
}
linphone_core_codec_config_write, 这个就是每次开启linphone程序写入配置文件的地方
void _linphone_core_codec_config_write(LinphoneCore *lc){
if (linphone_core_ready(lc)){
PayloadType *pt;
codecs_config_t *config=&lc->codecs_conf;
bctbx_list_t *node;
char key[50];
int index;
index=0;
for(node=config->audio_codecs;node!=NULL;node=bctbx_list_next(node)){
pt=(PayloadType*)(node->data);
sprintf(key,"audio_codec_%i",index);
lp_config_set_string(lc->config,key,"mime",pt->mime_type);
lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
lp_config_set_int(lc->config,key,"channels",pt->channels);
lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
index++;
}
sprintf(key,"audio_codec_%i",index);
lp_config_clean_section (lc->config,key);
index=0;
for(node=config->video_codecs;node!=NULL;node=bctbx_list_next(node)){
pt=(PayloadType*)(node->data);
sprintf(key,"video_codec_%i",index);
lp_config_set_string(lc->config,key,"mime",pt->mime_type);
lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
index++;
}
sprintf(key,"video_codec_%i",index);
lp_config_clean_section (lc->config,key);
}
}
PayloadType结构体
struct _PayloadType
{
int type; /**< one of PAYLOAD_* macros*/
int clock_rate; /**< rtp clock rate*/
char bits_per_sample; /* in case of continuous audio data */
char *zero_pattern;
int pattern_length;
/* other useful information for the application*/
int normal_bitrate; /*in bit/s */
char *mime_type; /**<actually the submime, ex: pcm, pcma, gsm*/
int channels; /**< number of channels of audio */
char *recv_fmtp; /* various format parameters for the incoming stream */
char *send_fmtp; /* various format parameters for the outgoing stream */
struct _PayloadTypeAvpfParams avpf; /* AVPF parameters */
int flags;
void *user_data;
};
# private.h
typedef struct codecs_config
{
MSList *audio_codecs; /* list of audio codecs in order of preference*/
MSList *video_codecs;
MSList *text_codecs;
int dyn_pt;
int telephone_event_pt;
}codecs_config_t;
视频编码的问题,搜寻网址:
android linphone 在mediastreamer2新建filter进行h264硬件编码
Linphone探索:7 . 如何进行视频电话
哪里判断和哪里得到的编码信息
# msfactory.h
/*do not use these fields directly*/
struct _MSFactory{
MSList *desc_list;
MSList *stats_list;
MSList *offer_answer_provider_list;
#ifdef _WIN32
MSList *ms_plugins_loaded_list;
#endif
MSList *formats;
MSList *platform_tags;
char *plugins_dir;
struct _MSVideoPresetsManager *video_presets_manager;
int cpu_count;
struct _MSEventQueue *evq;
int max_payload_size;
int mtu;
struct _MSSndCardManager* sndcardmanager;
struct _MSWebCamManager* wbcmanager;
void (*voip_uninit_func)(struct _MSFactory*);
bool_t statistics_enabled;
bool_t voip_initd;
MSDevicesInfo *devices_info;
char *image_resources_dir;
};
#msfilter.h
struct _MSFilterDesc{
MSFilterId id; /**< the id declared in allfilters.h */
const char *name; /**< the filter name*/
const char *text; /**< short text describing the filter's function*/
MSFilterCategory category; /**< filter's category*/
const char *enc_fmt; /**< sub-mime of the format, must be set if category is MS_FILTER_ENCODER or MS_FILTER_DECODER */
int ninputs; /**< number of inputs */
int noutputs; /**< number of outputs */
MSFilterFunc init; /**< Filter's init function*/
MSFilterFunc preprocess; /**< Filter's preprocess function, called one time before starting to process*/
MSFilterFunc process; /**< Filter's process function, called every tick by the MSTicker to do the filter's job*/
MSFilterFunc postprocess; /**< Filter's postprocess function, called once after processing (the filter is no longer called in process() after)*/
MSFilterFunc uninit; /**< Filter's uninit function, used to deallocate internal structures*/
MSFilterMethod *methods; /**<Filter's method table*/
unsigned int flags; /**<Filter's special flags, from the MSFilterFlags enum.*/
};
/**
* Filter's category
*
*/
enum _MSFilterCategory{
/**others*/
MS_FILTER_OTHER,
/**used by encoders*/
MS_FILTER_ENCODER,
/**used by decoders*/
MS_FILTER_DECODER,
/**used by capture filters that perform encoding*/
MS_FILTER_ENCODING_CAPTURER,
/**used by filters that perform decoding and rendering */
MS_FILTER_DECODER_RENDERER
};
msfilter.c中使用判断编码是否可用
bool_t ms_filter_codec_supported(const char *mime){
return ms_factory_codec_supported(ms_factory_get_fallback(),mime);
}
应该就是在这里判断是否有这个编码的
bool_t ms_factory_codec_supported(MSFactory* factory, const char *mime){
ms_message("[get_codec] [msfactory] ms_factory_codec_supported(MSFactory* factory, const char *mime=%s", mime);
MSFilterDesc *enc = ms_factory_get_encoding_capturer(factory, mime);
MSFilterDesc *dec = ms_factory_get_decoding_renderer(factory, mime);
if (enc == NULL) enc = ms_factory_get_encoder(factory, mime);
if (dec == NULL) dec = ms_factory_get_decoder(factory, mime);
if(enc!=NULL && dec!=NULL) return TRUE;
if(enc==NULL) ms_message("Could not find encoder for %s", mime);
if(dec==NULL) ms_message("Could not find decoder for %s", mime);
return FALSE;
}
ms_factory_get_encoding_capturer
MSFilterDesc * ms_factory_get_encoding_capturer(MSFactory* factory, const char *mime) {
bctbx_list_t *elem;
for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
MSFilterDesc *desc = (MSFilterDesc *)elem->data;
if (desc->category == MS_FILTER_ENCODING_CAPTURER) {
char *saveptr=NULL;
char *enc_fmt = ms_strdup(desc->enc_fmt);
char *token = strtok_r(enc_fmt, " ", &saveptr);
while (token != NULL) {
if (strcasecmp(token, mime) == 0) {
break;
}
token = strtok_r(NULL, " ", &saveptr);
}
ms_free(enc_fmt);
if (token != NULL) return desc;
}
}
return NULL;
}
ms_factory_get_decoding_renderer
MSFilterDesc * ms_factory_get_decoding_renderer(MSFactory* factory, const char *mime) {
bctbx_list_t *elem;
for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
MSFilterDesc *desc = (MSFilterDesc *)elem->data;
if (desc->category == MS_FILTER_DECODER_RENDERER) {
char *saveptr=NULL;
char *enc_fmt = ms_strdup(desc->enc_fmt);
char *token = strtok_r(enc_fmt, " ", &saveptr);
while (token != NULL) {
if (strcasecmp(token, mime) == 0) {
break;
}
token = strtok_r(NULL, " ", &saveptr);
}
ms_free(enc_fmt);
if (token != NULL) return desc;
}
}
return NULL;
}
ms_factory_get_encoder
MSFilterDesc * ms_factory_get_encoder(MSFactory* factory, const char *mime){
bctbx_list_t *elem;
for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
MSFilterDesc *desc=(MSFilterDesc*)elem->data;
if ((desc->flags & MS_FILTER_IS_ENABLED)
&& (desc->category==MS_FILTER_ENCODER || desc->category==MS_FILTER_ENCODING_CAPTURER)
&& strcasecmp(desc->enc_fmt,mime)==0){
return desc;
}
}
return NULL;
}
ms_factory_get_decoder
MSFilterDesc * ms_factory_get_decoder(MSFactory* factory, const char *mime){
bctbx_list_t *elem;
for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
MSFilterDesc *desc=(MSFilterDesc*)elem->data;
if ((desc->flags & MS_FILTER_IS_ENABLED)
&& (desc->category==MS_FILTER_DECODER || desc->category==MS_FILTER_DECODER_RENDERER)
&& strcasecmp(desc->enc_fmt,mime)==0){
return desc;
}
}
return NULL;
}
突然发现所有的编码在MSFilterDesc中
strcasecmp(desc->enc_fmt,mime)==0)
bctbx_list_t *elem;
for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
MSFilterDesc *desc=(MSFilterDesc*)elem->data;
ms_message("[ms_factory_get_encoder] MSFilterDesc name=%s, text=%s, enc_fmt=%s ",desc->name ,desc->text, desc->enc_fmt);
if ((desc->flags & MS_FILTER_IS_ENABLED)
&& (desc->category==MS_FILTER_ENCODER || desc->category==MS_FILTER_ENCODING_CAPTURER)
&& strcasecmp(desc->enc_fmt,mime)==0){
return desc;
}
}
linphone_core_start 调用的方式
代码调用的过程
要点似乎实在linphone_core_init函数中
# linphonecore.c
static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig *config, void * userdata){
ms_message("[getLinphoneCoreMSFilterDescDebug] [linphone_core_init]");
//getLinphoneCoreMSFilterDescDebug(lc);
const char *remote_provisioning_uri = NULL;
LinphoneFactory *lfactory = linphone_factory_get();
LinphoneCoreCbs *internal_cbs = _linphone_core_cbs_new();
char *msplugins_dir;
char *image_resources_dir;
ms_message("Initializing LinphoneCore %s", linphone_core_get_version());
lc->config=lp_config_ref(config);
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
linphone_task_list_init(&lc->hooks);
linphone_core_cbs_set_notify_received(internal_cbs, linphone_core_internal_notify_received);
linphone_core_cbs_set_subscription_state_changed(internal_cbs, linphone_core_internal_subscription_state_changed);
_linphone_core_add_callbacks(lc, internal_cbs, TRUE);
belle_sip_object_unref(internal_cbs);
if (cbs != NULL) {
_linphone_core_add_callbacks(lc, cbs, FALSE);
} else {
LinphoneCoreCbs *fallback_cbs = linphone_factory_create_core_cbs(linphone_factory_get());
_linphone_core_add_callbacks(lc, fallback_cbs, FALSE);
belle_sip_object_unref(fallback_cbs);
}
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
ortp_init();
linphone_core_activate_log_serialization_if_needed();
msplugins_dir = linphone_factory_get_msplugins_dir(lfactory);
lc->factory = ms_factory_new_with_voip_and_plugins_dir(msplugins_dir);
if (msplugins_dir) bctbx_free(msplugins_dir);
image_resources_dir = linphone_factory_get_image_resources_dir(lfactory);
ms_factory_set_image_resources_dir(lc->factory, image_resources_dir);
bctbx_free(image_resources_dir);
linphone_core_register_default_codecs(lc);
linphone_core_register_offer_answer_providers(lc);
/* Get the mediastreamer2 event queue */
/* This allows to run event's callback in linphone_core_iterate() */
lc->msevq=ms_factory_create_event_queue(lc->factory);
lc->sal=sal_init(lc->factory);
sal_set_http_proxy_host(lc->sal, linphone_core_get_http_proxy_host(lc));
sal_set_http_proxy_port(lc->sal, linphone_core_get_http_proxy_port(lc));
sal_set_user_pointer(lc->sal,lc);
sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
#ifdef TUNNEL_ENABLED
lc->tunnel=linphone_core_tunnel_new(lc);
#endif
lc->network_last_check = 0;
lc->network_last_status = FALSE;
/* Create the http provider in dual stack mode (ipv4 and ipv6.
* If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
*/
lc->http_provider = belle_sip_stack_create_http_provider(sal_get_stack_impl(lc->sal), "::0");
lc->http_crypto_config = belle_tls_crypto_config_new();
belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
certificates_config_read(lc);
lc->ringtoneplayer = linphone_ringtoneplayer_new();
#ifdef SQLITE_STORAGE_ENABLED
sqlite3_bctbx_vfs_register(0);
#endif
lc->vcard_context = linphone_vcard_context_new();
linphone_core_initialize_supported_content_types(lc);
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri == NULL) {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
} // else linphone_core_start will be called after the remote provisioning (see linphone_core_iterate)
lc->bw_controller = ms_bandwidth_controller_new();
}
linphonecore.c 中的 linphone_core_iterate函数, 是不断调用的
没找原因。
android5.0之前后之后代码调用日志情况
android5.0之前
04-10 11:06:54.924 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [_linphone_core_new]
04-10 11:06:54.934 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [linphone_core_new_with_config]
04-10 11:06:54.934 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [_linphone_core_new_with_config]
04-10 11:06:54.934 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [linphone_core_init]
04-10 11:06:56.024 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [linphone_configuring_terminated] linphone_core_start(lc);
04-10 11:06:56.024 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [linphone_core_start]
04-10 11:06:56.024 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [codecs_config_read]
04-10 11:06:56.204 9070-9070/org.linphone I/Linphone: [getLinphoneCoreMSFilterDescDebug] [codecs_config_read]
android 5.0之后
[getLinphoneCoreMSFilterDescDebug] [_linphone_core_new]
[getLinphoneCoreMSFilterDescDebug] [linphone_core_new_with_config]
[getLinphoneCoreMSFilterDescDebug] [_linphone_core_new_with_config]
[getLinphoneCoreMSFilterDescDebug] [linphone_core_init]
[getLinphoneCoreMSFilterDescDebug] [linphone_configuring_terminated] linphone_core_start(lc);
[getLinphoneCoreMSFilterDescDebug] [linphone_core_start]
[getLinphoneCoreMSFilterDescDebug] [codecs_config_read]