msandroid_sound_write_data() :audio_track_class(0),audio_track(0),write_chunk_size(0),writtenBytes(0),last_sample_date(0) { bufferizer = ms_bufferizer_new(); ms_cond_init(&cond,0); JNIEnv *jni_env = NULL; JavaVM *jvm = ms_get_jvm(); if (jvm->AttachCurrentThread(&jni_env, NULL)!=0) { ms_fatal("AttachCurrentThread() failed !"); return; } //JNIEnv *jni_env = ms_get_jni_env(); jclass temp_class = 0; temp_class = jni_env->FindClass("android/media/AudioTrack"); audio_track_class = (jclass)jni_env->NewGlobalRef(temp_class); if (audio_track_class == 0) { ms_error("cannot find android/media/AudioTrack\n"); return; } jmethodID hwrate_id = jni_env->GetStaticMethodID(audio_track_class,"getNativeOutputSampleRate", "(I)I"); if (hwrate_id == 0) { ms_error("cannot find int AudioRecord.getNativeOutputSampleRate(int streamType)"); return; } rate = jni_env->CallStaticIntMethod(audio_track_class,hwrate_id,0 /*STREAM_VOICE_CALL*/); ms_message("Hardware sample rate is %i",rate); jvm->DetachCurrentThread(); };
void conf_stream_start(LinphoneConferenceStream *stream,bool_t video_monitor) { bool_t ptt = stream->ptt_mode; int tmp; { stream->audio_ticker = ms_ticker_new(); ms_cond_init(&stream->audio_ticker->cond,NULL); ms_ticker_set_name(stream->audio_ticker,"Audio Mixer MSTicker"); stream->audio_mixer = ms_filter_new(MS_CONF_ID); stream->audio_filerecorder = ms_filter_new(MS_FILE_REC_ID); stream->audio_fileplayer = ms_filter_new(MS_FILE_PLAYER_ID); ms_filter_call_method(stream->audio_mixer,MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); ms_filter_call_method (stream->audio_fileplayer , MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); tmp = 1; /*默认采用单声道会议*/ ms_filter_call_method (stream->audio_fileplayer , MS_FILTER_SET_NCHANNELS,&tmp); /*设置会议音频采样率,8k,16k,32k*/ ms_filter_call_method(stream->audio_filerecorder,MS_FILTER_SET_SAMPLE_RATE,&stream->sample_rate); ms_message("Link audio filter list!!!"); /*创建录制端口*/ { int audio_mixer_pin = NB_AUDIO_MAX_OUPUT_PINS-2; stream->audio_record_sink = ms_filter_new(MS_CONF_ITC_SINK_ID); ms_filter_link(stream->audio_mixer,audio_mixer_pin,stream->audio_record_sink,0); } {/*创建音频对接端口*/ int max_ports = stream->max_ports; for(int i=0; i< max_ports; i++) { ConfAudioPort *port = audio_slot_new(); audio_slot_init(port,i); stream->audio_ports = ms_list_append(stream->audio_ports, port); /*顺序连接音频对接端口*/ ms_filter_link(port->audio_itc_source,0,stream->audio_mixer,i);// <--- call[i].sink <--- call[i].decode <--- call[i].rtp_recv ms_filter_link(stream->audio_mixer,i,port->audio_itc_sink,0); // ---> call[i].itc_source --->call[i].encode --->call[i].rtp_send } /*将音频播放,及录制连接至最末端端口*/ ms_filter_link(stream->audio_fileplayer,0,stream->audio_mixer,stream->max_ports); ms_filter_link(stream->audio_mixer,stream->max_ports,stream->audio_filerecorder,0); } /*启动音频mixer线程*/ ms_ticker_attach(stream->audio_ticker,stream->audio_mixer); } if(stream->has_video) { ms_message("Link video filter list!!!"); MSPixFmt format=MS_YUV420P; MSVideoSize vsize,cam_vsize,disp_size; stream->video_mixer=ms_filter_new_from_name("MSVideoMixer"); if(stream->video_mixer==NULL){ ms_error("Not have MSVideoStitcher, Can't to Video Conference!!!"); return; } stream->video_ticker = ms_ticker_new(); ms_cond_init(&stream->video_ticker->cond,NULL); ms_ticker_set_name(stream->video_ticker,"Video Mixer MSTicker"); /*设置视频会议的输出尺寸*/ ms_filter_call_method(stream->video_mixer,MS_FILTER_SET_VIDEO_SIZE,&stream->sent_vsize); /*添加服务器端视频监视,可添加jpeg画面截取filer,用于web端实时会议的画面截取*/ if(video_monitor) stream->video_output=ms_filter_new_from_name (stream->display_name); /*配置监视器*/ if(stream->video_output!=NULL){ disp_size = stream->sent_vsize; tmp=1; ms_filter_call_method(stream->video_output,MS_FILTER_SET_VIDEO_SIZE,&disp_size); ms_filter_call_method(stream->video_output,MS_VIDEO_DISPLAY_ENABLE_AUTOFIT,&tmp); ms_filter_call_method(stream->video_output,MS_FILTER_SET_PIX_FMT,&format); /*在已有窗口上绘图,或创建新window*/ if (stream->video_window_id!=0) ms_filter_call_method(stream->video_output, MS_VIDEO_DISPLAY_SET_NATIVE_WINDOW_ID,&stream->video_window_id); /*设置服务器端 视频监视filter,将其连接至视频Mixer输出最后的端口上*/ ms_filter_link (stream->video_mixer,VIDEO_MIXER_MAX_OUTPUTS-1, stream->video_output, 0); } /*输出录制端口*/ { int video_mixer_pin = VIDEO_MIXER_MAX_OUTPUTS-2; stream->video_record_sink = ms_filter_new(MS_CONF_ITC_SINK_ID); ms_filter_link(stream->video_mixer,video_mixer_pin,stream->video_record_sink,0); } /*创建无信号输出时,显示的图片*/ stream->video_static_image = ms_web_cam_create_reader(get_image_webcam_device()); if(stream->static_image_path!=NULL) ms_filter_call_method(stream->video_static_image, MS_STATIC_IMAGE_SET_IMAGE,(void *)stream->static_image_path); ms_filter_call_method(stream->video_static_image, MS_FILTER_SET_FPS,&stream->fps); ms_filter_call_method(stream->video_static_image,MS_FILTER_SET_VIDEO_SIZE,&stream->sent_vsize); /*并行输出至所有视频端口*/ stream->video_static_image_tee = ms_filter_new(MS_TEE_ID); ms_filter_link (stream->video_static_image, 0, stream->video_static_image_tee, 0); /*最大视频端口,需小于视频Mixer最大布局数,当前最大为 9 画面*/ int max_ports = (stream->max_ports > NB_MAX_VIDEO_LAYOUT)? NB_MAX_VIDEO_LAYOUT:stream->max_ports; int static_pic_index=0; /*创建端口连接插座*/ for(int i=0; i<max_ports; i++) { ConfVideoPort *port = video_slot_new(); video_slot_init(port,i); stream->video_ports = ms_list_append(stream->video_ports, port); /** * 视频采集输入源 和 静态图片 同时 join 至mixer的输入端口, * 当视频流有效时需MUTE 静态图片的输入,反之则输入静态图片 * * video_input -------> join ------> mixer ----> video_output * | * static_pic ----------+ * **/ ms_filter_link (port->video_itc_source, 0, port->video_input_join,0); ms_filter_link (stream->video_static_image_tee, static_pic_index++, port->video_input_join,1); /*自动布局模式下除了0号端口外,均不输出静态图片*/ if(stream->auto_layout && (static_pic_index > 0)){ ms_filter_call_method(stream->video_static_image_tee,MS_TEE_MUTE,&static_pic_index); } ms_filter_link (port->video_input_join, 0, stream->video_mixer,i); ms_filter_link (stream->video_mixer,i, port->video_itc_sink,0); } ms_ticker_attach(stream->video_ticker,stream->video_mixer); } }