Ticket #438 (Workaround for frame bursts from audio devices): added delay buffer implementation in pjmedia

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1664 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Benny Prijono 2008-01-04 18:19:40 +00:00
parent d7443937b2
commit 45710a4968
12 changed files with 2609 additions and 434 deletions

View File

@ -282,39 +282,42 @@ EXPORTS
pj_strtrim @ 281 NONAME
pj_symbianos_poll @ 282 NONAME
pj_symbianos_set_params @ 283 NONAME
pj_thread_create @ 284 NONAME
pj_thread_destroy @ 285 NONAME
pj_thread_get_name @ 286 NONAME
pj_thread_get_os_handle @ 287 NONAME
pj_thread_is_registered @ 288 NONAME
pj_thread_join @ 289 NONAME
pj_thread_local_alloc @ 290 NONAME
pj_thread_local_free @ 291 NONAME
pj_thread_local_get @ 292 NONAME
pj_thread_local_set @ 293 NONAME
pj_thread_register @ 294 NONAME
pj_thread_resume @ 295 NONAME
pj_thread_sleep @ 296 NONAME
pj_thread_this @ 297 NONAME
pj_time_decode @ 298 NONAME
pj_time_encode @ 299 NONAME
pj_time_gmt_to_local @ 300 NONAME
pj_time_local_to_gmt @ 301 NONAME
pj_time_val_normalize @ 302 NONAME
pj_timer_entry_init @ 303 NONAME
pj_timer_heap_cancel @ 304 NONAME
pj_timer_heap_count @ 305 NONAME
pj_timer_heap_create @ 306 NONAME
pj_timer_heap_destroy @ 307 NONAME
pj_timer_heap_earliest_time @ 308 NONAME
pj_timer_heap_mem_size @ 309 NONAME
pj_timer_heap_poll @ 310 NONAME
pj_timer_heap_schedule @ 311 NONAME
pj_timer_heap_set_lock @ 312 NONAME
pj_timer_heap_set_max_timed_out_per_poll @ 313 NONAME
pj_unicode_to_ansi @ 314 NONAME
pj_utoa @ 315 NONAME
pj_utoa_pad @ 316 NONAME
platform_strerror @ 317 NONAME
snprintf @ 318 NONAME
vsnprintf @ 319 NONAME
pj_thread_check_stack @ 284 NONAME
pj_thread_create @ 285 NONAME
pj_thread_destroy @ 286 NONAME
pj_thread_get_name @ 287 NONAME
pj_thread_get_os_handle @ 288 NONAME
pj_thread_get_stack_info @ 289 NONAME
pj_thread_get_stack_max_usage @ 290 NONAME
pj_thread_is_registered @ 291 NONAME
pj_thread_join @ 292 NONAME
pj_thread_local_alloc @ 293 NONAME
pj_thread_local_free @ 294 NONAME
pj_thread_local_get @ 295 NONAME
pj_thread_local_set @ 296 NONAME
pj_thread_register @ 297 NONAME
pj_thread_resume @ 298 NONAME
pj_thread_sleep @ 299 NONAME
pj_thread_this @ 300 NONAME
pj_time_decode @ 301 NONAME
pj_time_encode @ 302 NONAME
pj_time_gmt_to_local @ 303 NONAME
pj_time_local_to_gmt @ 304 NONAME
pj_time_val_normalize @ 305 NONAME
pj_timer_entry_init @ 306 NONAME
pj_timer_heap_cancel @ 307 NONAME
pj_timer_heap_count @ 308 NONAME
pj_timer_heap_create @ 309 NONAME
pj_timer_heap_destroy @ 310 NONAME
pj_timer_heap_earliest_time @ 311 NONAME
pj_timer_heap_mem_size @ 312 NONAME
pj_timer_heap_poll @ 313 NONAME
pj_timer_heap_schedule @ 314 NONAME
pj_timer_heap_set_lock @ 315 NONAME
pj_timer_heap_set_max_timed_out_per_poll @ 316 NONAME
pj_unicode_to_ansi @ 317 NONAME
pj_utoa @ 318 NONAME
pj_utoa_pad @ 319 NONAME
platform_strerror @ 320 NONAME
snprintf @ 321 NONAME
vsnprintf @ 322 NONAME

View File

@ -40,6 +40,7 @@ SOURCE echo_port.c
SOURCE echo_suppress.c
SOURCE endpoint.c
SOURCE errno.c
SOURCE delaybuf.c
SOURCE g711.c
SOURCE jbuf.c
SOURCE master_port.c

View File

@ -42,149 +42,152 @@ EXPORTS
pjmedia_conf_get_signal_level @ 41 NONAME
pjmedia_conf_remove_port @ 42 NONAME
pjmedia_conf_set_port0_name @ 43 NONAME
pjmedia_echo_cancel @ 44 NONAME
pjmedia_echo_capture @ 45 NONAME
pjmedia_echo_create @ 46 NONAME
pjmedia_echo_destroy @ 47 NONAME
pjmedia_echo_playback @ 48 NONAME
pjmedia_echo_port_create @ 49 NONAME
pjmedia_endpt_create @ 50 NONAME
pjmedia_endpt_create_pool @ 51 NONAME
pjmedia_endpt_create_sdp @ 52 NONAME
pjmedia_endpt_destroy @ 53 NONAME
pjmedia_endpt_dump @ 54 NONAME
pjmedia_endpt_get_codec_mgr @ 55 NONAME
pjmedia_endpt_get_ioqueue @ 56 NONAME
pjmedia_endpt_get_thread @ 57 NONAME
pjmedia_endpt_get_thread_count @ 58 NONAME
pjmedia_ice_create @ 59 NONAME
pjmedia_ice_destroy @ 60 NONAME
pjmedia_ice_get_comp @ 61 NONAME
pjmedia_ice_get_init_status @ 62 NONAME
pjmedia_ice_init_ice @ 63 NONAME
pjmedia_ice_modify_sdp @ 64 NONAME
pjmedia_ice_simulate_lost @ 65 NONAME
pjmedia_ice_start_ice @ 66 NONAME
pjmedia_ice_start_init @ 67 NONAME
pjmedia_ice_stop_ice @ 68 NONAME
pjmedia_jbuf_create @ 69 NONAME
pjmedia_jbuf_destroy @ 70 NONAME
pjmedia_jbuf_get_frame @ 71 NONAME
pjmedia_jbuf_get_state @ 72 NONAME
pjmedia_jbuf_put_frame @ 73 NONAME
pjmedia_jbuf_reset @ 74 NONAME
pjmedia_jbuf_set_adaptive @ 75 NONAME
pjmedia_jbuf_set_fixed @ 76 NONAME
pjmedia_master_port_create @ 77 NONAME
pjmedia_master_port_destroy @ 78 NONAME
pjmedia_master_port_get_dport @ 79 NONAME
pjmedia_master_port_get_uport @ 80 NONAME
pjmedia_master_port_set_dport @ 81 NONAME
pjmedia_master_port_set_uport @ 82 NONAME
pjmedia_master_port_start @ 83 NONAME
pjmedia_master_port_stop @ 84 NONAME
pjmedia_mem_capture_create @ 85 NONAME
pjmedia_mem_capture_get_size @ 86 NONAME
pjmedia_mem_capture_set_eof_cb @ 87 NONAME
pjmedia_mem_player_create @ 88 NONAME
pjmedia_mem_player_set_eof_cb @ 89 NONAME
pjmedia_null_port_create @ 90 NONAME
pjmedia_plc_create @ 91 NONAME
pjmedia_plc_generate @ 92 NONAME
pjmedia_plc_save @ 93 NONAME
pjmedia_port_destroy @ 94 NONAME
pjmedia_port_get_frame @ 95 NONAME
pjmedia_port_info_init @ 96 NONAME
pjmedia_port_put_frame @ 97 NONAME
pjmedia_resample_create @ 98 NONAME
pjmedia_resample_destroy @ 99 NONAME
pjmedia_resample_get_input_size @ 100 NONAME
pjmedia_resample_port_create @ 101 NONAME
pjmedia_resample_run @ 102 NONAME
pjmedia_rtcp_build_rtcp @ 103 NONAME
pjmedia_rtcp_fini @ 104 NONAME
pjmedia_rtcp_get_ntp_time @ 105 NONAME
pjmedia_rtcp_init @ 106 NONAME
pjmedia_rtcp_rx_rtcp @ 107 NONAME
pjmedia_rtcp_rx_rtp @ 108 NONAME
pjmedia_rtcp_tx_rtp @ 109 NONAME
pjmedia_rtp_decode_rtp @ 110 NONAME
pjmedia_rtp_encode_rtp @ 111 NONAME
pjmedia_rtp_session_init @ 112 NONAME
pjmedia_rtp_session_update @ 113 NONAME
pjmedia_session_check_dtmf @ 114 NONAME
pjmedia_session_create @ 115 NONAME
pjmedia_session_destroy @ 116 NONAME
pjmedia_session_dial_dtmf @ 117 NONAME
pjmedia_session_enum_streams @ 118 NONAME
pjmedia_session_get_dtmf @ 119 NONAME
pjmedia_session_get_info @ 120 NONAME
pjmedia_session_get_port @ 121 NONAME
pjmedia_session_get_stream_stat @ 122 NONAME
pjmedia_session_info_from_sdp @ 123 NONAME
pjmedia_session_pause @ 124 NONAME
pjmedia_session_pause_stream @ 125 NONAME
pjmedia_session_resume @ 126 NONAME
pjmedia_session_resume_stream @ 127 NONAME
pjmedia_session_set_dtmf_callback @ 128 NONAME
pjmedia_silence_det_apply @ 129 NONAME
pjmedia_silence_det_create @ 130 NONAME
pjmedia_silence_det_detect @ 131 NONAME
pjmedia_silence_det_disable @ 132 NONAME
pjmedia_silence_det_set_adaptive @ 133 NONAME
pjmedia_silence_det_set_fixed @ 134 NONAME
pjmedia_silence_det_set_name @ 135 NONAME
pjmedia_silence_det_set_params @ 136 NONAME
pjmedia_snd_port_connect @ 137 NONAME
pjmedia_snd_port_create @ 138 NONAME
pjmedia_snd_port_create_player @ 139 NONAME
pjmedia_snd_port_create_rec @ 140 NONAME
pjmedia_snd_port_destroy @ 141 NONAME
pjmedia_snd_port_disconnect @ 142 NONAME
pjmedia_snd_port_get_ec_tail @ 143 NONAME
pjmedia_snd_port_get_port @ 144 NONAME
pjmedia_snd_port_get_snd_stream @ 145 NONAME
pjmedia_snd_port_set_ec @ 146 NONAME
pjmedia_splitcomb_create @ 147 NONAME
pjmedia_splitcomb_create_rev_channel @ 148 NONAME
pjmedia_splitcomb_set_channel @ 149 NONAME
pjmedia_stream_check_dtmf @ 150 NONAME
pjmedia_stream_create @ 151 NONAME
pjmedia_stream_destroy @ 152 NONAME
pjmedia_stream_dial_dtmf @ 153 NONAME
pjmedia_stream_get_dtmf @ 154 NONAME
pjmedia_stream_get_port @ 155 NONAME
pjmedia_stream_get_stat @ 156 NONAME
pjmedia_stream_get_transport @ 157 NONAME
pjmedia_stream_info_from_sdp @ 158 NONAME
pjmedia_stream_pause @ 159 NONAME
pjmedia_stream_resume @ 160 NONAME
pjmedia_stream_set_dtmf_callback @ 161 NONAME
pjmedia_stream_start @ 162 NONAME
pjmedia_strerror @ 163 NONAME
pjmedia_tonegen_create @ 164 NONAME
pjmedia_tonegen_create2 @ 165 NONAME
pjmedia_tonegen_get_digit_map @ 166 NONAME
pjmedia_tonegen_is_busy @ 167 NONAME
pjmedia_tonegen_play @ 168 NONAME
pjmedia_tonegen_play_digits @ 169 NONAME
pjmedia_tonegen_set_digit_map @ 170 NONAME
pjmedia_tonegen_stop @ 171 NONAME
pjmedia_transport_udp_attach @ 172 NONAME
pjmedia_transport_udp_close @ 173 NONAME
pjmedia_transport_udp_create @ 174 NONAME
pjmedia_transport_udp_create2 @ 175 NONAME
pjmedia_transport_udp_create3 @ 176 NONAME
pjmedia_transport_udp_get_info @ 177 NONAME
pjmedia_transport_udp_simulate_lost @ 178 NONAME
pjmedia_wav_player_port_create @ 179 NONAME
pjmedia_wav_player_port_get_pos @ 180 NONAME
pjmedia_wav_player_port_set_pos @ 181 NONAME
pjmedia_wav_player_set_eof_cb @ 182 NONAME
pjmedia_wav_playlist_create @ 183 NONAME
pjmedia_wav_playlist_set_eof_cb @ 184 NONAME
pjmedia_wav_writer_port_create @ 185 NONAME
pjmedia_wav_writer_port_get_pos @ 186 NONAME
pjmedia_wav_writer_port_set_cb @ 187 NONAME
pjmedia_wave_hdr_file_to_host @ 188 NONAME
pjmedia_wave_hdr_host_to_file @ 189 NONAME
pjmedia_delay_buf_create @ 44 NONAME
pjmedia_delay_buf_get @ 45 NONAME
pjmedia_delay_buf_put @ 46 NONAME
pjmedia_echo_cancel @ 47 NONAME
pjmedia_echo_capture @ 48 NONAME
pjmedia_echo_create @ 49 NONAME
pjmedia_echo_destroy @ 50 NONAME
pjmedia_echo_playback @ 51 NONAME
pjmedia_echo_port_create @ 52 NONAME
pjmedia_endpt_create @ 53 NONAME
pjmedia_endpt_create_pool @ 54 NONAME
pjmedia_endpt_create_sdp @ 55 NONAME
pjmedia_endpt_destroy @ 56 NONAME
pjmedia_endpt_dump @ 57 NONAME
pjmedia_endpt_get_codec_mgr @ 58 NONAME
pjmedia_endpt_get_ioqueue @ 59 NONAME
pjmedia_endpt_get_thread @ 60 NONAME
pjmedia_endpt_get_thread_count @ 61 NONAME
pjmedia_ice_create @ 62 NONAME
pjmedia_ice_destroy @ 63 NONAME
pjmedia_ice_get_comp @ 64 NONAME
pjmedia_ice_get_init_status @ 65 NONAME
pjmedia_ice_init_ice @ 66 NONAME
pjmedia_ice_modify_sdp @ 67 NONAME
pjmedia_ice_simulate_lost @ 68 NONAME
pjmedia_ice_start_ice @ 69 NONAME
pjmedia_ice_start_init @ 70 NONAME
pjmedia_ice_stop_ice @ 71 NONAME
pjmedia_jbuf_create @ 72 NONAME
pjmedia_jbuf_destroy @ 73 NONAME
pjmedia_jbuf_get_frame @ 74 NONAME
pjmedia_jbuf_get_state @ 75 NONAME
pjmedia_jbuf_put_frame @ 76 NONAME
pjmedia_jbuf_reset @ 77 NONAME
pjmedia_jbuf_set_adaptive @ 78 NONAME
pjmedia_jbuf_set_fixed @ 79 NONAME
pjmedia_master_port_create @ 80 NONAME
pjmedia_master_port_destroy @ 81 NONAME
pjmedia_master_port_get_dport @ 82 NONAME
pjmedia_master_port_get_uport @ 83 NONAME
pjmedia_master_port_set_dport @ 84 NONAME
pjmedia_master_port_set_uport @ 85 NONAME
pjmedia_master_port_start @ 86 NONAME
pjmedia_master_port_stop @ 87 NONAME
pjmedia_mem_capture_create @ 88 NONAME
pjmedia_mem_capture_get_size @ 89 NONAME
pjmedia_mem_capture_set_eof_cb @ 90 NONAME
pjmedia_mem_player_create @ 91 NONAME
pjmedia_mem_player_set_eof_cb @ 92 NONAME
pjmedia_null_port_create @ 93 NONAME
pjmedia_plc_create @ 94 NONAME
pjmedia_plc_generate @ 95 NONAME
pjmedia_plc_save @ 96 NONAME
pjmedia_port_destroy @ 97 NONAME
pjmedia_port_get_frame @ 98 NONAME
pjmedia_port_info_init @ 99 NONAME
pjmedia_port_put_frame @ 100 NONAME
pjmedia_resample_create @ 101 NONAME
pjmedia_resample_destroy @ 102 NONAME
pjmedia_resample_get_input_size @ 103 NONAME
pjmedia_resample_port_create @ 104 NONAME
pjmedia_resample_run @ 105 NONAME
pjmedia_rtcp_build_rtcp @ 106 NONAME
pjmedia_rtcp_fini @ 107 NONAME
pjmedia_rtcp_get_ntp_time @ 108 NONAME
pjmedia_rtcp_init @ 109 NONAME
pjmedia_rtcp_rx_rtcp @ 110 NONAME
pjmedia_rtcp_rx_rtp @ 111 NONAME
pjmedia_rtcp_tx_rtp @ 112 NONAME
pjmedia_rtp_decode_rtp @ 113 NONAME
pjmedia_rtp_encode_rtp @ 114 NONAME
pjmedia_rtp_session_init @ 115 NONAME
pjmedia_rtp_session_update @ 116 NONAME
pjmedia_session_check_dtmf @ 117 NONAME
pjmedia_session_create @ 118 NONAME
pjmedia_session_destroy @ 119 NONAME
pjmedia_session_dial_dtmf @ 120 NONAME
pjmedia_session_enum_streams @ 121 NONAME
pjmedia_session_get_dtmf @ 122 NONAME
pjmedia_session_get_info @ 123 NONAME
pjmedia_session_get_port @ 124 NONAME
pjmedia_session_get_stream_stat @ 125 NONAME
pjmedia_session_info_from_sdp @ 126 NONAME
pjmedia_session_pause @ 127 NONAME
pjmedia_session_pause_stream @ 128 NONAME
pjmedia_session_resume @ 129 NONAME
pjmedia_session_resume_stream @ 130 NONAME
pjmedia_session_set_dtmf_callback @ 131 NONAME
pjmedia_silence_det_apply @ 132 NONAME
pjmedia_silence_det_create @ 133 NONAME
pjmedia_silence_det_detect @ 134 NONAME
pjmedia_silence_det_disable @ 135 NONAME
pjmedia_silence_det_set_adaptive @ 136 NONAME
pjmedia_silence_det_set_fixed @ 137 NONAME
pjmedia_silence_det_set_name @ 138 NONAME
pjmedia_silence_det_set_params @ 139 NONAME
pjmedia_snd_port_connect @ 140 NONAME
pjmedia_snd_port_create @ 141 NONAME
pjmedia_snd_port_create_player @ 142 NONAME
pjmedia_snd_port_create_rec @ 143 NONAME
pjmedia_snd_port_destroy @ 144 NONAME
pjmedia_snd_port_disconnect @ 145 NONAME
pjmedia_snd_port_get_ec_tail @ 146 NONAME
pjmedia_snd_port_get_port @ 147 NONAME
pjmedia_snd_port_get_snd_stream @ 148 NONAME
pjmedia_snd_port_set_ec @ 149 NONAME
pjmedia_splitcomb_create @ 150 NONAME
pjmedia_splitcomb_create_rev_channel @ 151 NONAME
pjmedia_splitcomb_set_channel @ 152 NONAME
pjmedia_stream_check_dtmf @ 153 NONAME
pjmedia_stream_create @ 154 NONAME
pjmedia_stream_destroy @ 155 NONAME
pjmedia_stream_dial_dtmf @ 156 NONAME
pjmedia_stream_get_dtmf @ 157 NONAME
pjmedia_stream_get_port @ 158 NONAME
pjmedia_stream_get_stat @ 159 NONAME
pjmedia_stream_get_transport @ 160 NONAME
pjmedia_stream_info_from_sdp @ 161 NONAME
pjmedia_stream_pause @ 162 NONAME
pjmedia_stream_resume @ 163 NONAME
pjmedia_stream_set_dtmf_callback @ 164 NONAME
pjmedia_stream_start @ 165 NONAME
pjmedia_strerror @ 166 NONAME
pjmedia_tonegen_create @ 167 NONAME
pjmedia_tonegen_create2 @ 168 NONAME
pjmedia_tonegen_get_digit_map @ 169 NONAME
pjmedia_tonegen_is_busy @ 170 NONAME
pjmedia_tonegen_play @ 171 NONAME
pjmedia_tonegen_play_digits @ 172 NONAME
pjmedia_tonegen_set_digit_map @ 173 NONAME
pjmedia_tonegen_stop @ 174 NONAME
pjmedia_transport_udp_attach @ 175 NONAME
pjmedia_transport_udp_close @ 176 NONAME
pjmedia_transport_udp_create @ 177 NONAME
pjmedia_transport_udp_create2 @ 178 NONAME
pjmedia_transport_udp_create3 @ 179 NONAME
pjmedia_transport_udp_get_info @ 180 NONAME
pjmedia_transport_udp_simulate_lost @ 181 NONAME
pjmedia_wav_player_port_create @ 182 NONAME
pjmedia_wav_player_port_get_pos @ 183 NONAME
pjmedia_wav_player_port_set_pos @ 184 NONAME
pjmedia_wav_player_set_eof_cb @ 185 NONAME
pjmedia_wav_playlist_create @ 186 NONAME
pjmedia_wav_playlist_set_eof_cb @ 187 NONAME
pjmedia_wav_writer_port_create @ 188 NONAME
pjmedia_wav_writer_port_get_pos @ 189 NONAME
pjmedia_wav_writer_port_set_cb @ 190 NONAME
pjmedia_wave_hdr_file_to_host @ 191 NONAME
pjmedia_wave_hdr_host_to_file @ 192 NONAME

View File

@ -7,5 +7,6 @@ EXPORTS
pjmedia_snd_open_player @ 6 NONAME
pjmedia_snd_open_rec @ 7 NONAME
pjmedia_snd_stream_close @ 8 NONAME
pjmedia_snd_stream_start @ 9 NONAME
pjmedia_snd_stream_stop @ 10 NONAME
pjmedia_snd_stream_get_info @ 9 NONAME
pjmedia_snd_stream_start @ 10 NONAME
pjmedia_snd_stream_stop @ 11 NONAME

View File

@ -41,7 +41,7 @@ export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJMEDIA_LIB)) \
export PJMEDIA_SRCDIR = ../src/pjmedia
export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
alaw_ulaw.o alaw_ulaw_table.o clock_thread.o codec.o \
conference.o echo_common.o echo_port.o \
conference.o delaybuf.o echo_common.o echo_port.o \
echo_suppress.o endpoint.o errno.o \
g711.o jbuf.o master_port.o mem_capture.o mem_player.o \
null_port.o plc_common.o port.o splitcomb.o \

View File

@ -113,6 +113,10 @@ SOURCE=..\src\pjmedia\conference.c
# End Source File
# Begin Source File
SOURCE=..\src\pjmedia\delaybuf.c
# End Source File
# Begin Source File
SOURCE=..\src\pjmedia\dsound.c
# End Source File
# Begin Source File
@ -293,6 +297,10 @@ SOURCE=..\include\pjmedia\config.h
# End Source File
# Begin Source File
SOURCE=..\include\pjmedia\delaybuf.h
# End Source File
# Begin Source File
SOURCE=..\include\pjmedia\doxygen.h
# End Source File
# Begin Source File

View File

@ -307,6 +307,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\src\pjmedia\delaybuf.c"
>
</File>
<File
RelativePath="..\src\pjmedia\dsound.c"
>
@ -1100,6 +1104,10 @@
RelativePath="..\include\pjmedia\config.h"
>
</File>
<File
RelativePath="..\include\pjmedia\delaybuf.h"
>
</File>
<File
RelativePath="..\include\pjmedia\doxygen.h"
>

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,30 @@
#endif
/**
* Specify whether delay buffer is used for sound device.
* When delay buffer is enabled, the sound device callback
* will be called one after another evenly.
* The delay buffer also performs the best delay calculation
* for the sound device, and will try to limit the delay caused
* by uneven callback calls to this delay.
*/
#ifndef PJMEDIA_SOUND_USE_DELAYBUF
# define PJMEDIA_SOUND_USE_DELAYBUF 0
#endif
/**
* Whenever delay buffer is enabled for sound device,
* PJMEDIA_SOUND_BUFFER_COUNT is better to be set to 1,
* because sound callbacks will be called evenly thus
* there's no need to have this buffer.
*/
#if defined(PJMEDIA_SOUND_USE_DELAYBUF) && PJMEDIA_SOUND_USE_DELAYBUF!=0
# define PJMEDIA_SOUND_BUFFER_COUNT 1
#endif
/**
* Specify number of sound buffers. Larger number is better for sound
* stability and to accommodate sound devices that are unable to send frames
@ -100,6 +124,9 @@
* The setting here currently is used by the conference bridge, the splitter
* combiner port, and dsound.c.
*
* Note that when PJMEDIA_SOUND_USE_DELAYBUF is enabled, it's best to
* set PJMEDIA_SOUND_BUFFER_COUNT to 1 to reduce voice latency.
*
* Default: 6
*/
#ifndef PJMEDIA_SOUND_BUFFER_COUNT

View File

@ -0,0 +1,138 @@
/* $Id$ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PJMEDIA_DELAYBUF_H__
#define __PJMEDIA_DELAYBUF_H__
/**
* @file delaybuf.h
* @brief Delay Buffer.
*/
#include <pjmedia/types.h>
/**
* @defgroup PJMED_DELAYBUF Delay Buffer
* @ingroup PJMEDIA_FRAME_OP
* @{
* This section describes PJMEDIA's implementation of delay buffer.
* Delay buffer works quite similarly like a fixed jitter buffer, that
* is it will delay the frame retrieval by some interval so that caller
* will get continuous frame from the buffer. This can be useful when
* the put() and get() operations are not evenly interleaved, for example
* when caller performs burst of put() operations and then followed by
* burst of get() operations. With using this delay buffer, the buffer
* will put the burst frames into a buffer so that get() operations
* will always get a frame from the buffer (assuming that the number of
* get() and put() are matched).
*
* The delay buffer is mostly used by the sound port, to accommodate
* for the burst frames returned by the sound device.
*
* To determine the level of delay to be applied, the delay buffer
* has a learning period on which it calculates the level of burst of
* both the put() and get(), and use the maximum value of both as the
* delay level.
*/
PJ_BEGIN_DECL
/** Opaque declaration for delay buffer. */
typedef struct pjmedia_delay_buf pjmedia_delay_buf;
/**
* Create the delay buffer. Once the delay buffer is created, it will
* enter learning state unless the delay argument is specified, which
* in this case it will directly enter the running state.
*
* @param pool Pool where the delay buffer will be allocated
* from.
* @param name Optional name for the buffer for log
* identification.
* @param samples_per_frame Number of samples per frame.
* @param max_cnt Maximum number of delay to be accommodated,
* in number of frames.
* @param delay The delay to be applied, in number of frames.
* If the value is -1, the delay buffer will
* learn about the delay automatically. If
* the value is greater than zero, then this
* value will be used and no learning will be
* performed.
* @param p_b Pointer to receive the delay buffer instance.
*
* @return PJ_SUCCESS if the delay buffer has been
* created successfully, otherwise the appropriate
* error will be returned.
*/
PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool,
const char *name,
unsigned samples_per_frame,
unsigned max_cnt,
int delay,
pjmedia_delay_buf **p_b);
/**
* Put one frame into the buffer.
*
* @param b The delay buffer.
* @param frame Frame to be put into the buffer. This frame
* must have samples_per_frame length.
*
* @return PJ_SUCCESS if frames can be put successfully.
* PJ_EPENDING if the buffer is still at learning
* state. PJ_ETOOMANY if the number of frames
* will exceed maximum delay level, which in this
* case the new frame will overwrite the oldest
* frame in the buffer.
*/
PJ_DECL(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
pj_int16_t frame[]);
/**
* Get one frame from the buffer.
*
* @param b The delay buffer.
* @param frame Buffer to receive the frame from the delay
* buffer.
*
* @return PJ_SUCCESS if frame has been copied successfully.
* PJ_EPENDING if no frame is available, either
* because the buffer is still at learning state or
* no buffer is available during running state.
* On non-successful return, the frame will be
* filled with zeroes.
*/
PJ_DECL(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b,
pj_int16_t frame[]);
/**
* Reinitiate learning state. This will clear the buffer's content.
*
* @param b The delay buffer.
*
* @return PJ_SUCCESS on success or the appropriate error.
*/
PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b);
PJ_END_DECL
#endif /* __PJMEDIA_DELAYBUF_H__ */

View File

@ -0,0 +1,231 @@
/* $Id$ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/delaybuf.h>
#include <pjmedia/errno.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/pool.h>
enum state
{
STATE_WAITING,
STATE_LEARNING,
STATE_RUNNING
};
enum OP
{
OP_PUT,
OP_GET,
OP_UNDEFINED
};
/* The following macros represent cycles of test. */
/* Since there are two operations performed (get & put), */
/* these macros value must be minimum 2 and should be even number */
#define WAITING_COUNT 8
#define LEARN_COUNT 8
struct pjmedia_delay_buf
{
char obj_name[PJ_MAX_OBJ_NAME];
pj_int16_t *frame_buf;
unsigned put_pos;
unsigned get_pos;
unsigned buf_cnt;
unsigned samples_per_frame;
unsigned max_cnt;
enum state state;
struct {
unsigned level;
} op[2];
enum OP last_op;
unsigned max_level;
unsigned state_count;
};
PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
const char *name,
unsigned samples_per_frame,
unsigned max_cnt,
int delay,
pjmedia_delay_buf **p_b)
{
pjmedia_delay_buf *b;
PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL);
if (!name) {
name = "delaybuf";
}
b = PJ_POOL_ZALLOC_T(pool, pjmedia_delay_buf);
pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1);
b->frame_buf = pj_pool_zalloc(pool, samples_per_frame * max_cnt *
sizeof(pj_int16_t));
b->samples_per_frame = samples_per_frame;
b->max_cnt = max_cnt;
if (delay >= 0) {
PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL);
b->max_level = delay;
b->state = STATE_RUNNING;
} else {
b->last_op = OP_UNDEFINED;
b->state = STATE_WAITING;
b->buf_cnt = 0;
}
*p_b = b;
PJ_LOG(5,(b->obj_name,"Delay buffer created"));
return PJ_SUCCESS;
}
static void update(pjmedia_delay_buf *b, enum OP op)
{
enum OP other = !op;
switch (b->state) {
case STATE_RUNNING:
break;
case STATE_WAITING:
++b->op[op].level;
if (b->op[other].level != 0) {
++b->state_count;
if (b->state_count == WAITING_COUNT) {
/* Start learning */
pjmedia_delay_buf_learn(b);
}
}
b->last_op = op;
break;
case STATE_LEARNING:
++b->op[op].level;
if (b->last_op == other) {
unsigned last_level = b->op[other].level;
if (last_level > b->max_level)
b->max_level = last_level;
b->op[other].level = 0;
b->state_count++;
if (b->state_count == LEARN_COUNT) {
/* give ONE frame compensation */
b->max_level += 1;
PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u",
b->max_level));
/* buffer not enough! */
if (b->max_level > b->max_cnt) {
b->max_level = b->max_cnt;
PJ_LOG(2,(b->obj_name,"Delay buffer %s learning result " \
"exceeds the maximum delay allowed",
b->max_level));
}
b->state = STATE_RUNNING;
}
}
b->last_op = op;
break;
}
}
PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
pj_int16_t frame[])
{
update(b, OP_PUT);
if (b->state != STATE_RUNNING)
return PJ_EPENDING;
pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame,
b->samples_per_frame*sizeof(pj_int16_t));
/* overflow case */
if (b->put_pos == b->get_pos && b->buf_cnt) {
if (++b->get_pos == b->max_level)
b->get_pos = 0;
b->put_pos = b->get_pos;
PJ_LOG(5,(b->obj_name,"Warning: buffer overflow"));
return PJ_ETOOMANY;
}
++b->buf_cnt;
if (++b->put_pos == b->max_level)
b->put_pos = 0;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b,
pj_int16_t frame[])
{
update(b, OP_GET);
if (b->state != STATE_RUNNING || !b->buf_cnt) {
if (b->state == STATE_RUNNING)
PJ_LOG(5,(b->obj_name,"Warning: delay buffer empty"));
pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t));
return PJ_EPENDING;
}
pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame],
b->samples_per_frame*sizeof(pj_int16_t));
if (++b->get_pos == b->max_level)
b->get_pos = 0;
--b->buf_cnt;
return PJ_SUCCESS;
}
PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b)
{
PJ_ASSERT_RETURN(b, PJ_EINVAL);
b->last_op = OP_UNDEFINED;
b->op[OP_GET].level = b->op[OP_PUT].level = 0;
b->state = STATE_LEARNING;
b->state_count = 0;
b->max_level = 0;
/* clean up buffer */
b->buf_cnt = 0;
b->put_pos = b->get_pos = 0;
PJ_LOG(5,(b->obj_name,"Delay buffer start learning"));
return PJ_SUCCESS;
}

View File

@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/sound_port.h>
#include <pjmedia/delaybuf.h>
#include <pjmedia/echo.h>
#include <pjmedia/errno.h>
#include <pjmedia/plc.h>
@ -62,6 +63,10 @@ struct pjmedia_snd_port
unsigned channel_count;
unsigned samples_per_frame;
unsigned bits_per_sample;
#if PJMEDIA_SOUND_USE_DELAYBUF
pjmedia_delay_buf *delay_buf;
#endif
};
/*
@ -93,6 +98,15 @@ static pj_status_t play_cb(/* in */ void *user_data,
frame.timestamp.u32.hi = 0;
frame.timestamp.u32.lo = timestamp;
#if PJMEDIA_SOUND_USE_DELAYBUF
status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output);
if (status != PJ_SUCCESS) {
pj_bzero(output, size);
}
pjmedia_port_put_frame(port, &frame);
#endif
status = pjmedia_port_get_frame(port, &frame);
if (status != PJ_SUCCESS)
goto no_frame;
@ -185,12 +199,19 @@ static pj_status_t rec_cb(/* in */ void *user_data,
pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0);
}
#if PJMEDIA_SOUND_USE_DELAYBUF
PJ_UNUSED_ARG(size);
PJ_UNUSED_ARG(timestamp);
PJ_UNUSED_ARG(frame);
pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input);
#else
frame.buf = (void*)input;
frame.size = size;
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.timestamp.u32.lo = timestamp;
pjmedia_port_put_frame(port, &frame);
#endif
return PJ_SUCCESS;
}
@ -324,6 +345,7 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create( pj_pool_t *pool,
pjmedia_snd_port **p_port)
{
pjmedia_snd_port *snd_port;
pj_status_t status;
PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
@ -338,6 +360,14 @@ PJ_DEF(pj_status_t) pjmedia_snd_port_create( pj_pool_t *pool,
snd_port->channel_count = channel_count;
snd_port->samples_per_frame = samples_per_frame;
snd_port->bits_per_sample = bits_per_sample;
#if PJMEDIA_SOUND_USE_DELAYBUF
status = pjmedia_delay_buf_create(pool, "snd_buff", samples_per_frame,
16, &snd_port->delay_buf);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#else
PJ_UNUSED_ARG(status);
#endif
*p_port = snd_port;