您的位置:首页 > 移动开发 > Android开发

linphone在android中,怎么读取音频之探索过程!终于找到它是怎么读声音的!

2012-06-21 12:14 549 查看
/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,"<init>", "(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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: