/linphone/console/linphonec.c
int
main (int argc, char *argv[]) {
#endif
linphonec_vtable.call_state_changed=linphonec_call_state_changed;
linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
linphonec_vtable.new_subscription_request = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
linphonec_vtable.refer_received=linphonec_display_refer;
linphonec_vtable.notify_recv=linphonec_notify_received;
linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed;
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
linphonec_main_loop (linphonec);
linphonec_finish(EXIT_SUCCESS);
exit(EXIT_SUCCESS); /* should never reach here */
}
linphone_init:
static int
linphonec_init(int argc, char **argv)
{
//g_mem_set_vtable(&dbgtable);
/*
* Set initial values for global variables
*/
mylogfile = NULL;
#ifndef _WIN32
snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
getenv("HOME"));
snprintf(zrtpsecrets, PATH_MAX, "%s/.linphone-zidcache",
getenv("HOME"));
#elif defined(_WIN32_WCE)
strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
printf("Logs are redirected in" PACKAGE_DIR "\\linphonec.log");
#else
snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
getenv("APPDATA"));
snprintf(zrtpsecrets, PATH_MAX, "%s/Linphone/linphone-zidcache",
getenv("APPDATA"));
#endif
/* Handle configuration filename changes */
switch (handle_configfile_migration())
{
case -1: /* error during file copies */
fprintf(stderr,
"Error in configuration file migration\n");
break;
case 0: /* nothing done */
case 1: /* migrated */
default:
break;
}
#ifdef ENABLE_NLS
if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
perror ("bindtextdomain failed");
#ifndef __ARM__
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
textdomain (GETTEXT_PACKAGE);
#else
printf ("NLS disabled.\n");
#endif
linphonec_parse_cmdline(argc, argv);
if (trace_level > 0)
{
if (logfile_name != NULL)
mylogfile = fopen (logfile_name, "w+");
if (mylogfile == NULL)
{
mylogfile = stdout;
fprintf (stderr,
"INFO: no logfile, logging to stdout\n");
}
linphone_core_enable_logs(mylogfile);
}
else
{
linphone_core_disable_logs();
}
/*
* Initialize auth stack
*/
auth_stack.nitems=0;
/*
* Initialize linphone core
*/
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
if (display_enabled && window_id != 0)
{
printf ("Setting window_id: 0x%x\n", window_id);
linphone_core_set_native_video_window_id(linphonec,window_id);
}
linphone_core_enable_video_preview(linphonec,preview_enabled);
if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
#ifdef HAVE_READLINE
/*
* Initialize readline
*/
linphonec_initialize_readline();
#endif
#if !defined(_WIN32_WCE)
/*
* Initialize signal handlers
*/
signal(SIGTERM, linphonec_finish);
signal(SIGINT, linphonec_finish);
#endif /*_WIN32_WCE*/
return 1;
}
看里面的**************Initialize linphone core******************
/*
* Initialize linphone core
*/
linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets);
linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
if (display_enabled && window_id != 0)
{
printf ("Setting window_id: 0x%x\n", window_id);
linphone_core_set_native_video_window_id(linphonec,window_id);
}
linphone_core_enable_video_preview(linphonec,preview_enabled);
if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
*************************
----------->linphonecore.c------>[linphone_core_new]
LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
const char *config_path, const char *factory_config_path, void * userdata)
{
LinphoneCore *core=ms_new(LinphoneCore,1);
linphone_core_init(core,vtable,config_path, factory_config_path, userdata);
return core;
}
----------->linphonecore.c------>[linphone_core_init]
static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path,
const char *factory_config_path, void * userdata)
{
memset (lc, 0, sizeof (LinphoneCore));
lc->data=userdata;
lc->ringstream_autorelease=TRUE;
memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable));
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
ortp_init();
lc->dyn_pt=96;
linphone_core_assign_payload_type(lc,&payload_type_pcmu8000,0,NULL);
linphone_core_assign_payload_type(lc,&payload_type_gsm,3,NULL);
linphone_core_assign_payload_type(lc,&payload_type_pcma8000,8,NULL);
linphone_core_assign_payload_type(lc,&payload_type_speex_nb,110,"vbr=on");
linphone_core_assign_payload_type(lc,&payload_type_speex_wb,111,"vbr=on");
linphone_core_assign_payload_type(lc,&payload_type_speex_uwb,112,"vbr=on");
linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-11");
linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL);
#if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED)
/*shorten the DNS lookup time and send more retransmissions on mobiles:
- to workaround potential packet losses
- to avoid hanging for 30 seconds when the network doesn't work despite the phone thinks it does.
*/
_linphone_core_configure_resolver();
#endif
#ifdef ENABLE_NONSTANDARD_GSM
{
PayloadType *pt;
pt=payload_type_clone(&payload_type_gsm);
pt->clock_rate=11025;
linphone_core_assign_payload_type(lc,pt,-1,NULL);
pt->clock_rate=22050;
linphone_core_assign_payload_type(lc,pt,-1,NULL);
payload_type_destroy(pt);
}
#endif
#ifdef VIDEO_ENABLED
linphone_core_assign_payload_type(lc,&payload_type_h263,34,NULL);
linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL);
linphone_core_assign_payload_type(lc,&payload_type_h263_1998,98,"CIF=1;QCIF=1");
linphone_core_assign_payload_type(lc,&payload_type_mp4v,99,"profile-level-id=3");
linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=428014");
linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL);
linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL);
/* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */
/* linphone_core_assign_payload_type(&payload_type_h264,-1,"packetization-mode=1;profile-level-id=428014");*/
#endif
/*add all payload type for which we don't care about the number */
linphone_core_assign_payload_type(lc,&payload_type_ilbc,-1,"mode=30");
linphone_core_assign_payload_type(lc,&payload_type_amr,-1,"octet-align=1");
linphone_core_assign_payload_type(lc,&payload_type_amrwb,-1,"octet-align=1");
linphone_core_assign_payload_type(lc,&payload_type_lpc1015,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_g726_16,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_g726_24,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_g726_32,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_g726_40,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_16,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_24,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_32,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_aal2_g726_40,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_silk_nb,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_silk_mb,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_silk_wb,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_silk_swb,-1,NULL);
linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no");
linphone_core_handle_static_payloads(lc);
ms_init();
/* create a mediastreamer2 event queue and set it as global */
/* This allows to run event's callback in linphone_core_iterate() */
lc->msevq=ms_event_queue_new();
ms_set_global_event_queue(lc->msevq);
lc->config=lp_config_new(config_path);
if (factory_config_path)
lp_config_read_file(lc->config,factory_config_path);
lc->sal=sal_init();
sal_set_user_pointer(lc->sal,lc);
sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
sip_setup_register_all();
sound_config_read(lc);
net_config_read(lc);
rtp_config_read(lc);
codecs_config_read(lc);
sip_config_read(lc); /* this will start eXosip*/
video_config_read(lc);
//autoreplier_config_init(&lc->autoreplier_conf);
lc->presence_mode=LinphoneStatusOnline;
misc_config_read(lc);
ui_config_read(lc);
#ifdef TUNNEL_ENABLED
lc->tunnel=linphone_core_tunnel_new(lc);
if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
#endif
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Ready"));
lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
linphone_core_set_state(lc,LinphoneGlobalOn,"Ready");
}
----------->linphonecore.c------>在linphone_core_init中调用sound_config_read,初始化声音设备
在sound_config_read中:将声卡添加到_MSSndCardManager
#ifdef __linux
/*alsadev let the user use custom alsa device within linphone*/
devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
if (devid){
MSSndCard *card=ms_alsa_card_new_custom(devid,devid); //获取声卡
ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); //将声卡设备添加到声卡管理器中
}
tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
#endif
但是:
MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev){
ms_warning("Alsa support not available in this build of mediastreamer2");
return NULL;
}
void ms_alsa_card_set_forced_sample_rate(int samplerate){
ms_warning("Alsa support not available in this build of mediastreamer2");
}
说明这里还没有拿到真正的声卡设备:
在----------->linphonecore.c------>linphone_core_init中
有这么一段:
/* 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);
看一下linphone_core_set_capture_device--->
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->sound_conf.capt_sndcard=card; //将声卡放到了LinphoneCore的sound_conf中
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;
}
找到了!!!!!
mscommong.c ---》ms_init中:
ms_message("Registering all soundcard handlers");
cm=ms_snd_card_manager_get();
for (i=0;ms_snd_card_descs[i]!=NULL;i++){
ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);
}
但是ms_snd_card_descs从哪里来呢?
上面有定义,且定义了好多中desc ,发现有个 msandroid_sound_card_desc 安卓声卡描述
而msandroid_sound_card_desc 在msandroid.cpp中有定义:
MSSndCardDesc msandroid_sound_card_desc = {
/*.driver_type=*/"ANDROID SND",
/*.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
};
在mssndcard.c中发现只要有了声卡描述desc就可以创建声卡了:
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) {
MSSndCard *obj=(MSSndCard *)ms_new(MSSndCard,1);
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;
}
所以我们进入msandroid_sound_card_desc的init方法就可以了
可是非常遗憾!!!
void msandroid_sound_init(MSSndCard *card){
}
这个方法为空:
难道白找了?
继续看,在msandroid.cpp中发现:!!!!!!!
sound_read_setup这个方法:
*************************************************************
static void sound_read_setup(MSFilter *f){
ms_debug("andsnd_read_preprocess");
msandroid_sound_read_data *d=(msandroid_sound_read_data*)f->data;
jmethodID constructor_id=0;
jmethodID min_buff_size_id;
//jmethodID set_notification_period;
int rc;
JNIEnv *jni_env = ms_get_jni_env();
d->audio_record_class = (jclass)jni_env->NewGlobalRef(jni_env->FindClass("android/media/AudioRecord"));
if (d->audio_record_class == 0) {
ms_error("cannot find android/media/AudioRecord\n");
return;
}
constructor_id = jni_env->GetMethodID(d->audio_record_class,"", "(IIIII)V");
if (constructor_id == 0) {
ms_error("cannot find AudioRecord (int audioSource, int sampleRateInHz, \
int channelConfig, int audioFormat, int bufferSizeInBytes)");
return;
}
min_buff_size_id = jni_env->GetStaticMethodID(d->audio_record_class,"getMinBufferSize", "(III)I");
if (min_buff_size_id == 0) {
ms_error("cannot find AudioRecord.getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)");
return;
}
d->buff_size = jni_env->CallStaticIntMethod(d->audio_record_class,min_buff_size_id,d->rate,2/*CHANNEL_CONFIGURATION_MONO*/,2/* ENCODING_PCM_16BIT */);
d->read_chunk_size = d->buff_size/4;
d->buff_size*=2;/*double the size for configuring the recorder: this does not affect latency but prevents "AudioRecordThread: buffer overflow"*/
if (d->buff_size > 0) {
ms_message("Configuring recorder with [%i] bits rate [%i] nchanels [%i] buff size [%i], chunk size [%i]"
,d->bits
,d->rate
,d->nchannels
,d->buff_size
,d->read_chunk_size);
} else {
ms_message("Cannot configure recorder with [%i] bits rate [%i] nchanels [%i] buff size [%i] chunk size [%i]"
,d->bits
,d->rate
,d->nchannels
,d->buff_size
,d->read_chunk_size);
return;
}
d->read_buff = jni_env->NewByteArray(d->buff_size);
d->read_buff = (jbyteArray)jni_env->NewGlobalRef(d->read_buff);
if (d->read_buff == 0) {
ms_error("cannot instanciate read buff");
return;
}
//卧槽,原来是用Android的AudioRecord类来跟音频打交道!!!!
d->audio_record = jni_env->NewObject(d->audio_record_class
,constructor_id
,1/*MIC*/
,d->rate
,2/*CHANNEL_CONFIGURATION_MONO*/
,2/* ENCODING_PCM_16BIT */
,d->buff_size);
d->audio_record = jni_env->NewGlobalRef(d->audio_record);
if (d->audio_record == 0) {
ms_error("cannot instantiate AudioRecord");
return;
}
d->min_avail=-1;
d->read_samples=0;
d->ticker_synchronizer = ms_ticker_synchronizer_new();
d->outgran_ms=20;
d->start_time=-1;
d->framesize=(d->outgran_ms*d->rate)/1000;
d->started=true;
// start reader thread
rc = ms_thread_create(&d->thread_id, 0, (void*(*)(void*))msandroid_read_cb, d);
if (rc){
ms_error("cannot create read thread return code is [%i]", rc);
d->started=false;
}
}**********************************************************************
读到了声音后有个回调方法:在这里能拿到音频对应的byte buffer!!!!!
static void* msandroid_read_cb(msandroid_sound_read_data* d) {
mblk_t *m;
int nread;
jmethodID read_id=0;
jmethodID record_id=0;
set_high_prio();
JNIEnv *jni_env = ms_get_jni_env();
record_id = jni_env->GetMethodID(d->audio_record_class,"startRecording", "()V");
if(record_id==0) {
ms_error("cannot find AudioRecord.startRecording() method");
goto end;
}
//start recording
jni_env->CallVoidMethod(d->audio_record,record_id);
// int read (byte[] audioData, int offsetInBytes, int sizeInBytes)
read_id = jni_env->GetMethodID(d->audio_record_class,"read", "([BII)I");
if(read_id==0) {
ms_error("cannot find AudioRecord.read() method");
goto end;
}
while (d->started && (nread=jni_env->CallIntMethod(d->audio_record,read_id,d->read_buff,0, d->read_chunk_size))>0) {
m = allocb(nread,0);
jni_env->GetByteArrayRegion(d->read_buff, 0,nread, (jbyte*)m->b_wptr);
//ms_error("%i octets read",nread);
m->b_wptr += nread;
d->read_samples+=nread/(2*d->nchannels);
compute_timespec(d);
ms_mutex_lock(&d->mutex);
ms_bufferizer_put (&d->rb,m);
ms_mutex_unlock(&d->mutex);
};
goto end;
end: {
ms_thread_exit(NULL);
return 0;
}
}
----------->linphonecore.c------>在linphone_core_init中[初始化mediastream2]
ms_init();
/* create a mediastreamer2 event queue and set it as global */
/* This allows to run event's callback in linphone_core_iterate() */
lc->msevq=ms_event_queue_new();
ms_set_global_event_queue(lc->msevq);
阅读(4514) | 评论(0) | 转发(0) |