Linphone录音器的初始化流程分析
来源:互联网 发布:重庆西南大学网络学费 编辑:程序博客网 时间:2024/04/30 04:50
初始化入口:
linphone_core_init() ——linphonecore.c 1793
static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata){ const char *remote_provisioning_uri = NULL; linphone_task_list_init(&lc->hooks); _linphone_core_add_listener(lc, internal_vtable, TRUE, TRUE); memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable)); _linphone_core_add_listener(lc, local_vtable, TRUE, FALSE); lc->factory = ms_factory_new_with_voip(); 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);}
媒体库初始化在ms_factory_new_with_voip() —— msvoip.c 354
MSFactory *ms_factory_new_with_voip(void){ ms_message("ms_factory_new_with_voip"); MSFactory *f = ms_factory_new(); ms_factory_init_voip(f); ms_factory_init_plugins(f); return f;}
第一步、ms_factory_new()新建一个MSFactory对象
第二步、ms_factory_init_voip(),初始化voip;
第三步、ms_factory_init_plugins();初始化插件;
先分析第一步,ms_factory_new()只是实例化一个MSFactory结构体 位于msfactory.c line223
MSFactory *ms_factory_new(void){ MSFactory *obj=ms_new0(MSFactory,1); ms_factory_init(obj); return obj;}
ms_factory_init(); ——msfactory.c 144
void ms_factory_init(MSFactory *obj){ int i; long num_cpu=1; char *debug_log_enabled = NULL; char *tags; ... ms_message("Mediastreamer2 factory " MEDIASTREAMER_VERSION " (git: " GIT_VERSION ") initialized."); /* register builtin MSFilter's */ for (i=0;ms_base_filter_descs[i]!=NULL;i++){ ms_factory_register_filter(obj,ms_base_filter_descs[i]); } ms_factory_set_cpu_count(obj,num_cpu); ms_factory_set_mtu(obj,MS_MTU_DEFAULT); #ifdef ANDROID ms_factory_add_platform_tag(obj, "android"); #endif #ifdef TARGET_OS_IPHONE ms_factory_add_platform_tag(obj, "ios"); #endif ... tags = ms_factory_get_platform_tags_as_string(obj); ms_message("ms_factory_init() done: platform_tags=%s", tags); ms_free(tags);}
主要是设置MSFactory*的一些属性,重点在中间的for循环。
其中的ms_base_filter_descs[]定义在basedesc.h中,
extern MSFilterDesc ms_tee_desc;extern MSFilterDesc ms_join_desc;extern MSFilterDesc ms_void_source_desc;extern MSFilterDesc ms_void_sink_desc;MSFilterDesc * ms_base_filter_descs[]={&ms_tee_desc,&ms_join_desc,&ms_void_source_desc,&ms_void_sink_desc,NULL};
而ms_factory_register_filter()在msfactory.c line 230
void ms_factory_register_filter(MSFactory* factory, MSFilterDesc* desc ) { if (desc->id==MS_FILTER_NOT_SET_ID){ ms_fatal("MSFilterId for %s not set !",desc->name); } desc->flags|=MS_FILTER_IS_ENABLED; /*by default a registered filter is enabled*/ /*lastly registered encoder/decoders may replace older ones*/ factory->desc_list=bctbx_list_prepend(factory->desc_list,desc);}
将整个数组中定义的desc设置到factory->desc_list;
再看第二步ms_factory_init_voip(MSFactory *) 在msvoip.c line260
void ms_factory_init_voip(MSFactory *obj){ MSSndCardManager *cm; int i; if (obj->voip_initd) return; ms_srtp_init(); obj->devices_info = ms_devices_info_new(); ...... #if defined(ANDROID) && defined(VIDEO_ENABLED) if (AMediaImage_isAvailable()) { ms_factory_register_filter(obj, &ms_mediacodec_h264_dec_desc); ms_factory_register_filter(obj, &ms_mediacodec_h264_enc_desc); } #endif /* register builtin VoIP MSFilter's */ for (i=0;ms_voip_filter_descs[i]!=NULL;i++){ ms_factory_register_filter(obj,ms_voip_filter_descs[i]); } cm=ms_snd_card_manager_new(); ms_message("Registering all soundcard handlers"); cm->factory=obj; obj->sndcardmanager = cm; for (i=0;ms_snd_card_descs[i]!=NULL;i++){ ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]); } ... #if defined(ANDROID) && defined (VIDEO_ENABLED) { MSDevicesInfo *devices = ms_factory_get_devices_info(obj); SoundDeviceDescription *description = ms_devices_info_get_sound_device_description(devices); if (description && description->flags & DEVICE_HAS_CRAPPY_OPENGL) { if (!libmsandroiddisplay_init(obj)) { libmsandroiddisplaybad_init(obj); } } else { libmsandroidopengldisplay_init(obj); } } #endif obj->voip_initd=TRUE; obj->voip_uninit_func = ms_factory_uninit_voip; ms_message("ms_factory_init_voip() done");}
初始化有个重要的操作,构建一个MSSndCardManager对象,然后将系统允许的集中声卡注册进去;
其中ms_snd_card_manager_new() ,在mssndcard.c line27
MSSndCardManager * ms_snd_card_manager_new(void){ MSSndCardManager *obj=(MSSndCardManager *)ms_new0(MSSndCardManager,1); obj->factory = NULL; obj->cards=NULL; obj->descs=NULL; return obj;}
只是初始化一个MSSndCardManager结构体,并与外部传入的MSFactory互相关联属性;
ms_snd_card_descs[]是预先定义好的
static MSSndCardDesc * ms_snd_card_descs[]={ #ifdef MS2_FILTERS ... #ifdef __ALSA_ENABLED__ &alsa_card_desc, #endif ... #ifdef ANDROID &android_native_snd_card_desc, &android_native_snd_opensles_card_desc, &msandroid_sound_card_desc, #endif #endif /* MS2_FILTERS */ NULL};
对于Android 平台 一共定义了3中声卡模型,
其中的android_native_snd_card_desc定义在 androidsound.cpp中
MSSndCardDesc android_native_snd_card_desc={ "libmedia", //char* drive_type android_snd_card_detect, //detect android_native_snd_card_init, //init NULL, //set_level NULL, //get_level NULL, //set_capture NULL, //set_control NULL, //get_control android_snd_card_create_reader,//create_reader android_snd_card_create_writer,//create_writer android_native_snd_card_uninit //duplicate};
android_native_snd_opensles_card_desc 定义在androidsound_opensles.cpp中
MSSndCardDesc android_native_snd_opensles_card_desc = { "openSLES", android_snd_card_detect, android_native_snd_card_init, NULL, NULL, NULL, NULL, NULL, android_snd_card_create_reader, android_snd_card_create_writer, android_native_snd_card_uninit};
msandroid_sound_card_desc 定义在 androidsound_depr.cpp中
MSSndCardDesc msandroid_sound_card_desc = {/*.driver_type=*/"ANDROID SND (deprecated)",/*.detect=*/ msandroid_sound_detect,/*.init=*/msandroid_sound_init,/*.set_level=*/msandroid_sound_set_level,/*.get_level=*/msandroid_sound_get_level,/*.set_capture=*/msandroid_sound_set_source, /*.set_control=*/NULL, /*.get_control=*/NULL,/*.create_reader=*/msandroid_sound_read_new,/*.create_writer=*/msandroid_sound_write_new,/*.uninit=*/msandroid_sound_uninit,/*.duplicate=*/msandroid_sound_duplicate};
for循环内,ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);在mssndcard.c line 142;
void ms_snd_card_manager_register_desc(MSSndCardManager *m, MSSndCardDesc *desc){ if (bctbx_list_find(m->descs, desc) == NULL){ m->descs=bctbx_list_append(m->descs,desc); card_detect(m,desc); }}
遍历每个ms_snd_card_descs中的desc,并执行card_detect(m,desc);
static void card_detect(MSSndCardManager *m, MSSndCardDesc *desc){ if (desc->detect!=NULL) desc->detect(m);}
只是执行desc->detect(m);
已知Android平台有三种声卡,所以这里会执行每个声卡描述的detect函数;
对于android_native_snd_card_desc,在执行desc->detect(m)的时候,实质上就是执行了android_native_snd_card_desc中定义的的detect函数
android_snd_card_detect(m),在androidsound.cpp中.
static void android_snd_card_detect(MSSndCardManager *m) { ms_message("android_snd_card_detect"); bool audio_record_loaded = false; bool audio_track_loaded = false; bool audio_system_loaded = false; bool string8_loaded = false; bool refbase_loaded = false; SoundDeviceDescription *d = NULL; MSDevicesInfo *devices = NULL; if (get_sdk_version() > 19) { /*it is actually working well on android 5 on Nexus 4 but crashes on Samsung S5, due to, maybe * calling convention of C++ method being different. Arguments received by AudioTrack constructor do not match the arguments * sent by the caller (TransferType maps to uid argument!). * Until we find a rational explanation to this, the native module is disabled on Android 5. **/ ms_message("Native android sound support not tested on SDK [%i], disabled.",get_sdk_version()); return; } devices = ms_factory_get_devices_info(m->factory); d = ms_devices_info_get_sound_device_description(devices); if (d->flags & DEVICE_HAS_UNSTANDARD_LIBMEDIA){ ms_message("Native android sound support is blacklisted for this device."); return; } /* libmedia and libutils static variable may survive to Linphone restarts It is then necessary to perform the *::init() calls even if the libmedia and libutils are there.*/ if (!libmedia) libmedia=Library::load("/system/lib/libmedia.so"); if (!libutils) libutils=Library::load("/system/lib/libutils.so"); if (libmedia && libutils) { /*perform initializations in order rather than in a if statement so that all missing symbols are shown in logs*/ string8_loaded = String8Impl::init(libutils); refbase_loaded = RefBaseImpl::init(libutils); audio_record_loaded = AudioRecordImpl::init(libmedia); audio_track_loaded = AudioTrackImpl::init(libmedia); audio_system_loaded = AudioSystemImpl::init(libmedia); } if (audio_record_loaded && audio_track_loaded && audio_system_loaded && string8_loaded && refbase_loaded) { ms_message("Native android sound support available."); MSSndCard* card = android_snd_card_new(d); ms_snd_card_set_manager(m, card); ms_snd_card_manager_add_card(m, card); return; } ms_message("Native android sound support is NOT available.");}
- 首先会判断系统sdk版本,如果19以上的android系统,直接跳过,不使用这个声卡模型,给出的解释是,Android5上面的native
module is disabled; - 19以下的版本才会使用这个声卡模型:加载需要使用的媒体库,使用的是system/lib下的libmedia.so,这个很关键;
- 然后使用这个libmedia.so初始化三个媒体
AudioRecordImpl、AudioTrackImpl、AudioSystemImpl的init; - 然后构建真实的声卡模型对象,android_snd_card_new(d),每个声卡模型都有自己的android_snd_card_new函数;
static MSSndCard * android_snd_card_new(SoundDeviceDescription *d){ MSSndCard * obj; obj=ms_snd_card_new(&android_native_snd_card_desc); obj->name=ms_strdup("android sound card"); if (d->flags & DEVICE_HAS_BUILTIN_AEC) obj->capabilities|=MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER; obj->latency=d->delay; obj->data = new AndroidNativeSndCardData( d->recommended_rate, d->flags); return obj;}
对于android_native_snd_opensles_card_desc,在执行desc->detect(m)的时候,实质上就是执行了android_native_snd_opensles_card_desc中定义的的detect函数 android_snd_card_detect, 在androidsound_opensles.cpp中
static void android_snd_card_detect(MSSndCardManager *m) { SoundDeviceDescription* d = NULL; MSDevicesInfo *devices = NULL; if (initOpenSLES() == 0) { // Try to dlopen libOpenSLES ms_message("libOpenSLES correctly loaded, creating OpenSLES MS soundcard"); devices = ms_factory_get_devices_info(m->factory); d = ms_devices_info_get_sound_device_description(devices); if (d->flags & DEVICE_HAS_CRAPPY_OPENSLES) return; MSSndCard *card = android_snd_card_new(m); ms_snd_card_manager_add_card(m, card); } else { ms_warning("Failed to dlopen libOpenSLES, OpenSLES MS soundcard unavailable"); }}
同样的,该类下也有android_snd_card_new方法,
static MSSndCard* android_snd_card_new(MSSndCardManager *m) { MSSndCard* card = NULL; SoundDeviceDescription *d = NULL; MSDevicesInfo *devices = NULL; card = ms_snd_card_new(&android_native_snd_opensles_card_desc); card->name = ms_strdup("android sound card"); devices = ms_factory_get_devices_info(m->factory); d = ms_devices_info_get_sound_device_description(devices); OpenSLESContext *context = opensles_context_init(); if (d->flags & DEVICE_HAS_BUILTIN_OPENSLES_AEC) { card->capabilities |= MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER; context->builtin_aec = true; } else if (d->flags & DEVICE_HAS_BUILTIN_AEC) { ms_warning("Removing MS_SND_CARD_CAP_CAPTURE flag from soundcard to use HAEC Java capture soundcard"); card->capabilities = MS_SND_CARD_CAP_PLAYBACK; } card->latency = d->delay; card->data = context; if (d->recommended_rate){ context->samplerate = d->recommended_rate; } return card;}
对于msandroid_sound_card_desc,在执行desc->detect(m)的时候,实质上就是执行了msandroid_sound_card_desc中定义的的detect函数msandroid_sound_detect,
void msandroid_sound_detect(MSSndCardManager *m) { ms_message("msandroid_sound_detect"); MSSndCard *card = msandroid_sound_card_new(m); ms_snd_card_manager_add_card(m, card);}
MSSndCard *msandroid_sound_card_new(MSSndCardManager *m) { ms_message("msandroid_sound_card_new"); SoundDeviceDescription *d = NULL; MSDevicesInfo *devices = NULL; MSSndCard *card = ms_snd_card_new(&msandroid_sound_card_desc); card->name = ms_strdup("Android Sound card"); devices = ms_factory_get_devices_info(m->factory); d = ms_devices_info_get_sound_device_description(devices); if (d->flags & DEVICE_HAS_BUILTIN_AEC) { card->capabilities |= MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER; } card->data = d; return card;}
三种声卡都会设置capabilities属性,这个属性主要是决定这个声卡是做为播放器使用还是录音器使用,取值不一样,这里三种声卡的capabilities取值为3,表示既可以作为录音器也可以作为播放器
三种MSSndCardDesc*的detect最终都是调用ms_snd_card_new(MSSndCardDesc*)来实现的;
该函数在mssndcard.c中,line171
MSSndCard * ms_snd_card_new(MSSndCardDesc *desc){ return ms_snd_card_new_with_name(desc,NULL);}
MSSndCard * ms_snd_card_new_with_name(MSSndCardDesc *desc,const char* name) { ms_message("ms_snd_card_new_with_name %s",desc->driver_type); MSSndCard *obj=(MSSndCard *)ms_new0(MSSndCard,1); obj->sndcardmanager = NULL; obj->desc=desc; obj->name=name?ms_strdup(name):NULL; obj->data=NULL; obj->id=NULL; obj->capabilities=MS_SND_CARD_CAP_CAPTURE|MS_SND_CARD_CAP_PLAYBACK; if (desc->init!=NULL) desc->init(obj); return obj;}
执行各个desc->init();
对于android_native_snd_card_desc和android_native_snd_opensles_card_desc,init是个空函数,msandroid_sound_card_desc内有init函数;
void msandroid_sound_init(MSSndCard *card){ /*get running sdk version*/ JNIEnv *jni_env = ms_get_jni_env(); jclass version_class = jni_env->FindClass("android/os/Build$VERSION"); jfieldID fid = jni_env->GetStaticFieldID(version_class, "SDK_INT", "I"); sdk_version=jni_env->GetStaticIntField(version_class, fid); ms_message("SDK version [%i] detected",sdk_version); jni_env->DeleteLocalRef(version_class);}
对于三种不同的声卡模型,执行ms_snd_card_new生成MSSndCard模型对象以后,都会通过ms_snd_card_manager_add_card();来完成MSSndCardManager对象和MSSndCard对象的相互关联
ms_snd_card_manager_add_card() 位于mssndcard.c Line119
void ms_snd_card_manager_add_card(MSSndCardManager *m, MSSndCard *c){ ms_snd_card_set_manager(m,c); ms_message("Card '%s' added with capabilities [%s]",ms_snd_card_get_string_id(c), cap_to_string(c->capabilities)); m->cards=bctbx_list_append(m->cards,c);}void ms_snd_card_set_manager(MSSndCardManager*m, MSSndCard *c){ if (c->sndcardmanager == NULL) c->sndcardmanager = m;}
操作比较简单,首先将给每个MSSndCard对象设置->sndcardmanager属性为MSSndCardManager对象;
然后将声卡模型对象追加到MSSndCardManager对象的cards列表里;
至此ms_factory_init_voip全部结束。
简单总结一下:
- **初始化首先构建一个声卡模型对象管理者 MSSndCardManager对象,并与传入的MSFactory互相关联
factory->sndcardmanager = sndcardManager;
sndcardManager->factory =factory;** - **然后系统自身配置了一个声卡模型描述的数组,定义了三种不同的声卡模型;
android_native_snd_card_desc;
android_native_snd_opensles_card_desc;
msandroid_sound_card_desc;** - **通过调用模型中定义的detect函数和init函数指针来构建MSSndCard模型对象,并且与MSSndCardManager对象相互关联;
sndcard->sndcardmanager = sndcardmanager;
sndcardmanager->cards =bctbx_list_append(sndcard);** - 最终返回MSFactory模型;
需要注意的是,sndcardmanager->cards中存放的声卡模型列表是按先后顺序存放的,这点很重要,因为后面再读取音频配置的手,会根据id和capability来选择匹配的声卡,并且是返回第一个匹配的;
第三步,ms_factory_init_plugins(f); 位于msfactory.c line672;
void ms_factory_init_plugins(MSFactory *obj) { if (obj->plugins_dir == NULL) {#ifdef PACKAGE_PLUGINS_DIR obj->plugins_dir = ms_strdup(PACKAGE_PLUGINS_DIR);#else obj->plugins_dir = ms_strdup("");#endif } if (strlen(obj->plugins_dir) > 0) { ms_message("Loading ms plugins from [%s]",obj->plugins_dir); ms_factory_load_plugins(obj,obj->plugins_dir); }}
因为MSFactory是刚新建并初始化的,这里他的plugins_dir还没有值;
这里预定义了一个PACKAGE_PLUGINS_DIR字符串,赋值给factory->plugins_dir;
ms_factory_load_plugins();在msfactory.c line467中;从log来看, 这里指定的plugins_dir路径不存在,结果返回了-1;
至此 ms_factory_new_with_voip()全部结束。
回到linphone_core_init中 ,函数内部最后有一段
remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); if(remote_provisioning_uri == NULL){ linphone_configuring_terminated(lc,LinphoneConfiguringSkipped,NULL) }
linphone_core_get_provisioning_uri() 位于remote_provisioning.c line157
const char*linphone_core_get_provisioning_uri(const LinphoneCore *lc){ return lp_config_get_string(lc->config,"misc","config-uri",NULL);}
从系统配置文件中读取misc下的config-uri字段。
系统默认的配置文件中没有设置这个字段,顾返回的是NULL;
因而继续执行linphone_configuring_terminated(), 位于linphonecore.c line1670;
void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { ms_message("linphone_configuring_terminated"); linphone_core_notify_configuring_status(lc, state, message); if (state == LinphoneConfiguringSuccessful) { if (linphone_core_is_provisioning_transient(lc) == TRUE) linphone_core_set_provisioning_uri(lc, NULL); } if (lc->provisioning_http_listener){ belle_sip_object_unref(lc->provisioning_http_listener); lc->provisioning_http_listener = NULL; } linphone_core_start(lc);}
首先更新状态为LinphoneConfiguringSkipped;linphone_core_notify_configuring_status位于vtables.c line264
void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { NOTIFY_IF_EXIST(configuring_status, lc,status,message); cleanup_dead_vtable_refs(lc);}
通过NOTIFY_IF_EXIST宏,去在vtables中找configuring_status是否有对应的回调函数,并执行对应的回调通知java层状态变化;
剩下的两步操作应该都不存在,直接进入linphone_core_start(lc);位于linphonecore.c line1640;
static void linphone_core_start(LinphoneCore * lc) { ms_message("linphone_core_start"); LinphoneFriendList *list = linphone_core_create_friend_list(lc); linphone_friend_list_set_display_name(list, "_default"); linphone_core_add_friend_list(lc, list); linphone_friend_list_unref(list); sip_setup_register_all(lc->factory); sound_config_read(lc); net_config_read(lc); rtp_config_read(lc); codecs_config_read(lc); sip_config_read(lc); video_config_read(lc); //autoreplier_config_init(&lc->autoreplier_conf); lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); misc_config_read(lc); ui_config_read(lc); #ifdef TUNNEL_ENABLED if (lc->tunnel) { linphone_tunnel_configure(lc->tunnel); } #endif linphone_core_notify_display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; linphone_core_set_state(lc,LinphoneGlobalOn,"Ready");}
关于声卡的配置在sound_config_read中,linphonecore.c line825
static void sound_config_read(LinphoneCore *lc){ ms_message("sound_config_read"); int tmp; const char *tmpbuf; const char *devid; #ifdef __linux /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); if (devid){ ... for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){ char s=*i; *i='\0'; card=ms_alsa_card_new_custom(d+l,d+l); ms_snd_card_manager_add_card(ms_factory_get_snd_card_manager(lc->factory),card); *i=s; l=i-d+1; } ... } tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1); if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp); #endif /* retrieve all sound devices */ build_sound_devices_table(lc); devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL); linphone_core_set_playback_device(lc,devid); devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL); linphone_core_set_ringer_device(lc,devid); devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL); linphone_core_set_capture_device(lc,devid); ... }
这个函数主要的操作是通过读取lc->config中关于sound的配置字段,然后进行相关的设置操作;
按顺序进行一下检查配置:
- 检查是或否存在alsadev字段,如果存在的话,通过ms_alsa_card_new_custom新建一个MSSndCard,并添加到lc->factory->mssndcardmanager;
- build_sound_devices_table(lc),从lc中读取mssndcardmanager中的声卡模型列表,并重新定义一个字符串数组,保存这些声卡的driver_type值;
然后将数组保存到lc->sound_conf.cards中; - 读取lc->config中sound字段下的playback_dev_id值,并调用linphone_core_set_playback_device设置,这是播放器声卡
- 读取lc->config中sound字段下的ringer_dev_id值,并调用linphone_core_set_ringer_device设置;
- 读取lc->config中sound字段下的capture_dev_id值,并调用linphone_core_set_capture_device设置,这是录音器声卡
- 后面依次设置sound下的local_ring、remot_ring、hold_music、echocancelllation、echolimiter、agc等其他相关配置
- _linphone_core_set_tone,设置遇忙情况下的响铃,保存在lc->tones中;
重点分析一下第2~5步的操作
第二步:build_sound_devices_table(lc),位于linphonecore.c line794;
static void build_sound_devices_table(LinphoneCore *lc){ const char **devices; const char **old; size_t ndev; int i; const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(lc->factory)); ndev=bctbx_list_size(elem); devices=ms_malloc((ndev+1)*sizeof(const char *)); for (i=0;elem!=NULL;elem=elem->next,i++){ devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data); ms_message("build sound devices table %i = %s",i,devices[i]); } devices[ndev]=NULL; old=lc->sound_conf.cards; lc->sound_conf.cards=devices; if (old!=NULL) ms_free((void *)old); }
第三步:播放器的设置
系统默认的配置文件中是没有定义playback_dev_id的,linphone_core_set_playback_device中的第二个入参实际是null;函数位于
linphonecore.c line4812;
int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){ ms_message("linphone_core_set_playback_device %s",devid); MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK, lc->factory); lc->sound_conf.play_sndcard=card; if (card && linphone_core_ready(lc)) lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card)); return 0;}
通过传入的id和MS_SND_CARD_CAP_PLAYBACK类型,从lc->factory中读取对应的声卡模型;
然后将这个声卡模型设置给lc->sound_conf.play_sndcard;
并且将这个声卡的id设置到系统配置lc->config中;
简单看一下get_card_from_string_id()这个函数,位于linphonecore.c line4738中;
static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap, MSFactory *f){ MSSndCard *sndcard=NULL; if (devid!=NULL){ sndcard=ms_snd_card_manager_get_card(ms_factory_get_snd_card_manager(f),devid); if (sndcard!=NULL &&(ms_snd_card_get_capabilities(sndcard) & cap)==0 ){ sndcard=NULL; } } if (sndcard==NULL) { if ((cap & MS_SND_CARD_CAP_CAPTURE) && (cap & MS_SND_CARD_CAP_PLAYBACK)){ sndcard=ms_snd_card_manager_get_default_card(ms_factory_get_snd_card_manager(f)); }else if (cap & MS_SND_CARD_CAP_CAPTURE){ sndcard=ms_snd_card_manager_get_default_capture_card(ms_factory_get_snd_card_manager(f)); } else if (cap & MS_SND_CARD_CAP_PLAYBACK){ sndcard=ms_snd_card_manager_get_default_playback_card(ms_factory_get_snd_card_manager(f)); } if (sndcard==NULL){/*looks like a bug! take the first one !*/ const bctbx_list_t *elem=ms_snd_card_manager_get_list(ms_factory_get_snd_card_manager(f)); if (elem) sndcard=(MSSndCard*)elem->data; } } if (sndcard==NULL) ms_error("Could not find a suitable soundcard !"); return sndcard;}
- 如果入参devid有值,就通过ms_snd_card_manager_get_card来查找id相同的MSSndCard,同时检查一下这个声卡的capability是否与入参中的cap一致;
- 如果id相同、capability不一致,也重新查找;
- 根据入参的Cap来选择不同的查找方式,这里我们用的是MS_SND_CARD_CAP_PLAYBACK的类别;
所以选择ms_snd_card_manager_get_default_playback_card(manager); 函数位于 mssndcard.c line100;
MSSndCard * ms_snd_card_manager_get_default_playback_card(MSSndCardManager *m){ return get_card_with_cap(m, NULL, MS_SND_CARD_CAP_PLAYBACK);}static MSSndCard *get_card_with_cap(MSSndCardManager *m, const char *id, unsigned int caps){ bctbx_list_t *elem; for (elem=m->cards;elem!=NULL;elem=elem->next){ MSSndCard *card=(MSSndCard*)elem->data; if ((id== NULL || strcmp(ms_snd_card_get_string_id(card),id)==0) && (card->capabilities & caps) == caps) return card; } return NULL;}
其实这里的获取方式也是根据cap和id来的,如果有id值,则返回同时匹配的声卡, 如果没有id值,则返回cap匹配的声卡;
需要注意的是,这里只要匹配到第一个满足条件的声卡模型,就返回了,所以如果存放的顺序也决定了linphone最终选择使用何种声卡;
第五步: 录音器的设置
同样的,系统默认的配置中没有指定capture_dev_id,整个流程与播音器的设置基本一致;
linphone_core_set_capture_device() 位于linphonecore.c line4831
int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){ MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE, lc->factory); lc->sound_conf.capt_sndcard=card; if (card && linphone_core_ready(lc)) lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card)); return 0;}
将读取到的声卡设置到lc->sound_conf.capt_sndcard中;
后面的操作不细看了,到这里linphone使用的录音器和播放器全部设置好了;
**后续再音频、视屏通话的时候,启动录音器就是通过lc->sound_conf.capt_sndcard来获取对应的声卡模型;
然后调用模型中定义的函数接口来获取录音数据;**
- Linphone录音器的初始化流程分析
- linphone 分析1 linphone的架构和初始化
- linphone呼叫流程分析
- [RK3288][Android6.0] Audio录音HAL层的初始化流程分析
- linphone源码分析----初始化部分
- linphone源码分析----初始化部分
- linphone源码分析----初始化部分
- linphone 流程
- Linphone android去电增加自定义SIP消息头的流程分析
- [Android7.0]NFC初始化的流程分析
- uboot的eMMC初始化代码流程分析
- Linphone-android 登录过程增加自定义消息头流程分析
- wpa_supplicant 初始化流程分析
- wpa_supplicant 初始化流程分析
- wpa_supplicant 初始化流程分析
- wpa_supplicant 初始化流程分析
- wpa_supplicant 初始化流程分析
- wpa_supplicant初始化流程分析
- React 认知 一
- [VC++]如何让MSChart的饼图显示百分比
- 从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
- 自然场景下植物图像的基元检测
- Spark图计算(二)
- Linphone录音器的初始化流程分析
- 国内访问Google的方法(Google学术、Google香港、Twitter等)
- 数据包捕获与分析
- 程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印
- PatternLockView滑动解锁
- Jquery获取手机验证码后60秒内禁止重新获取 简单例子
- 使用Keras搭建一个CNN处理MNIST数据
- 鸿业revit电气插件使用结果
- 欢迎使用CSDN-markdown编辑器