Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1079488
  • 博文数量: 165
  • 博客积分: 3900
  • 博客等级: 中校
  • 技术积分: 1887
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-06 15:15
文章分类

全部博文(165)

文章存档

2020年(3)

2019年(8)

2017年(2)

2016年(8)

2015年(14)

2013年(15)

2012年(32)

2011年(11)

2010年(14)

2009年(7)

2008年(20)

2007年(31)

分类: Android平台

2015-02-06 10:36:20

/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);
阅读(4245) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~