From: <do...@us...> - 2008-08-06 00:48:49
|
Revision: 1449 http://iaxclient.svn.sourceforge.net/iaxclient/?rev=1449&view=rev Author: dohpaz Date: 2008-08-06 00:48:54 +0000 (Wed, 06 Aug 2008) Log Message: ----------- Merge up to trunk of r1448 Modified Paths: -------------- branches/team/elbunce/iaxclient/contrib/tcl/Makefile.macosx branches/team/elbunce/iaxclient/lib/audio_encode.c branches/team/elbunce/iaxclient/lib/audio_portaudio.c branches/team/elbunce/iaxclient/lib/iaxclient_lib.c branches/team/elbunce/iaxclient/lib/libiax2/src/frame.h branches/team/elbunce/iaxclient/lib/libiax2/src/iax.c branches/team/elbunce/iaxclient/lib/libiax2/src/iax2-parser.c branches/team/elbunce/iaxclient/lib/libiax2/src/iax2-parser.h branches/team/elbunce/iaxclient/lib/unixfuncs.c branches/team/elbunce/iaxclient/simpleclient/stresstest/file.c branches/team/elbunce/iaxclient/simpleclient/stresstest/file.h branches/team/elbunce/iaxclient/simpleclient/stresstest/stresstest.c branches/team/elbunce/iaxclient/simpleclient/tkphone/Makefile.am Modified: branches/team/elbunce/iaxclient/contrib/tcl/Makefile.macosx =================================================================== --- branches/team/elbunce/iaxclient/contrib/tcl/Makefile.macosx 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/contrib/tcl/Makefile.macosx 2008-08-06 00:48:54 UTC (rev 1449) @@ -9,7 +9,6 @@ CFLAGS:= $(CFLAGS) -g -Wall -O2 # debug flags -# CFLAGS := $(CFLAGS) -DDEBUG_SUPPORT -DDEBUG_DEFAULT -DEXTREME_DEBUG -D_DEBUG # CFLAGS := $(CFLAGS) -DDEBUG_SUPPORT -DDEBUG_DEFAULT -D_DEBUG OBJS=\ Modified: branches/team/elbunce/iaxclient/lib/audio_encode.c =================================================================== --- branches/team/elbunce/iaxclient/lib/audio_encode.c 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/lib/audio_encode.c 2008-08-06 00:48:54 UTC (rev 1449) @@ -41,7 +41,7 @@ #include "codec_ilbc.h" #endif -float iaxci_silence_threshold = AUDIO_ENCODE_SILENCE_DB; +static float iaxci_silence_threshold = AUDIO_ENCODE_SILENCE_DB; static float input_level = 0.0f; static float output_level = 0.0f; @@ -51,7 +51,11 @@ static SpeexPreprocessState *st = NULL; static int speex_state_size = 0; static int speex_state_rate = 0; -int iaxci_filters = IAXC_FILTER_AGC|IAXC_FILTER_DENOISE|IAXC_FILTER_AAGC|IAXC_FILTER_CN; +static int iaxci_filters = + IAXC_FILTER_AGC | + IAXC_FILTER_DENOISE | + IAXC_FILTER_AAGC | + IAXC_FILTER_CN; static MUTEX audio_lock; @@ -72,16 +76,6 @@ static char outRingBuf[EC_RING_SIZE]; #endif -/* AAGC threshold */ -#define AAGC_VERY_HOT 16 -#define AAGC_HOT 8 -#define AAGC_COLD 4 - -/* AAGC increments */ -#define AAGC_RISE_SLOW 0.10f -#define AAGC_DROP_SLOW 0.15f -#define AAGC_DROP_FAST 0.20f - /* use to measure time since last audio was processed */ static struct timeval timeLastInput ; static struct timeval timeLastOutput ; @@ -178,11 +172,17 @@ static int input_postprocess(short * audio, int len, int rate) { - static float lowest_volume = 1.0f; - float volume; - int silent = 0; + static int aagc_frame_count = 0; + static int aagc_periods_to_skip = 0; + const int using_vad = iaxci_silence_threshold > 0.0f; + const int aagc_period = rate / len; /* 1 second */ + + int speaking = 1; + int loudness = 0; + MUTEXLOCK(&audio_lock); + if ( !st || speex_state_size != len || speex_state_rate != rate ) { if (st) @@ -199,75 +199,114 @@ i = ECHO_SUPPRESS_ACTIVE; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE, &i); } -#endif +#endif speex_state_size = len; speex_state_rate = rate; set_speex_filters(); } + + /* go through the motions only if we need at least one of the + * preprocessor filters */ + if ( using_vad || (iaxci_filters & + (IAXC_FILTER_DENOISE | + IAXC_FILTER_AGC | + IAXC_FILTER_DEREVERB | + IAXC_FILTER_ECHO)) ) + { + speaking = speex_preprocess_run(st, audio); + speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_LOUDNESS, + &loudness); + } + MUTEXUNLOCK(&audio_lock); - calculate_level(audio, len, &input_level); + /* If we are using the VAD test and if speex indicates non-speaking, + * ignore the computed input level and indicate to the user that the + * input level was zero. + */ + if ( using_vad && !speaking ) + input_level = 0.0f; + else + calculate_level(audio, len, &input_level); - /* go through the motions only if we need at least one of the preprocessor filters */ - if ( (iaxci_filters & (IAXC_FILTER_DENOISE | IAXC_FILTER_AGC | IAXC_FILTER_DEREVERB | IAXC_FILTER_ECHO)) || - iaxci_silence_threshold > 0.0f ) - silent = !speex_preprocess(st, (spx_int16_t *)audio, NULL); - - /* Analog AGC: Bring speex AGC gain out to mixer, with lots of hysteresis */ - /* use a higher continuation threshold for AAGC than for VAD itself */ - if ( !silent && - iaxci_silence_threshold != 0.0f && - (iaxci_filters & IAXC_FILTER_AGC) && - (iaxci_filters & IAXC_FILTER_AAGC) - ) + /* Analog Automatic Gain Control, AAGC. */ + if ( speaking && iaxci_silence_threshold != 0.0f && + (iaxci_filters & IAXC_FILTER_AGC) && + (iaxci_filters & IAXC_FILTER_AAGC) && + ++aagc_frame_count % aagc_period == 0 && + !aagc_periods_to_skip-- ) { - static int i = 0; + /* This heuristic uses the loudness value from the speex + * preprocessor to determine a new mixer level. The loudness + * ranges from 0 to up over 80. When mixer level, speex AGC, + * and the actual speaker's level are in equilibrium, the + * loudness tends to be from 4 to 16. When the loudness goes + * above this comfortable range, there is a risk of the input + * signal being clipped. AAGC's primary purpose is to avoid + * clipping. + * + * After a loud event (think cough), the loudness level will + * spike and then decay over time (assuming the speaker + * speaking at a relatively constant level). To avoid + * over-adjusting, we skip some number of aagc sampling periods + * before making any more adjustments. This gives the loudness + * value time to normalize after one-time spikes in the input + * level. + */ - i++; + /* The mixer level is a percentage ranging from 0.00 to 1.00 */ + const float mixer_level = iaxc_input_level_get(); + float new_mixer_level = mixer_level; - if ( (i & 0x3f) == 0 ) + if ( loudness > 40 ) { - int loudness; - speex_preprocess_ctl(st, SPEEX_PREPROCESS_GET_AGC_LOUDNESS, &loudness); - if ( loudness > AAGC_HOT || loudness < AAGC_COLD ) - { - const float level = iaxc_input_level_get(); + new_mixer_level -= 0.20f; + aagc_periods_to_skip = 8; + } + else if ( loudness > 25 ) + { + new_mixer_level -= 0.15f; + aagc_periods_to_skip = 4; + } + else if ( loudness > 15 ) + { + new_mixer_level -= 0.10f; + aagc_periods_to_skip = 2; + } + else if ( loudness > 12 ) + { + new_mixer_level -= 0.05f; + aagc_periods_to_skip = 4; + } + else if ( loudness < 2 ) + { + new_mixer_level += 0.15f; + aagc_periods_to_skip = 4; + } + else if ( loudness < 4 ) + { + new_mixer_level += 0.10f; + aagc_periods_to_skip = 4; + } + else + { + aagc_periods_to_skip = 0; + } - if ( loudness > AAGC_VERY_HOT && level > 0.5f ) - { - /* lower quickly if we're really too hot */ - iaxc_input_level_set(level - AAGC_DROP_FAST); - } - else if ( loudness > AAGC_HOT && level >= 0.15f ) - { - /* lower less quickly if we're a bit too hot */ - iaxc_input_level_set(level - AAGC_DROP_SLOW); - } - else if ( loudness < AAGC_COLD && level <= 0.9f ) - { - /* raise slowly if we're cold */ - iaxc_input_level_set(level + AAGC_RISE_SLOW); - } - } - } + /* Normalize the proposed new mixer level */ + if ( new_mixer_level < 0.05f ) + new_mixer_level = 0.05f; + else if ( new_mixer_level > 1.00f ) + new_mixer_level = 1.00f; + + if ( new_mixer_level != mixer_level ) + iaxc_input_level_set(new_mixer_level); } - /* This is ugly. Basically just don't get volume level if speex thought - * we were silent. Just set it to 0 in that case */ - if ( iaxci_silence_threshold > 0.0f && silent ) - input_level = 0.0f; - do_level_callback(); - volume = vol_to_db(input_level); - - if ( volume < lowest_volume ) - lowest_volume = volume; - - if ( iaxci_silence_threshold > 0.0f ) - return silent; - else - return volume < iaxci_silence_threshold; + return using_vad ? !speaking : + vol_to_db(input_level) < iaxci_silence_threshold; } static int output_postprocess(const short * audio, int len) @@ -517,6 +556,36 @@ rb_ReadRingBuffer(&ecOutRing, delayedBuf, SAMPLES_PER_FRAME * 2); + /* TODO: speex_echo_cancellation() and speex_preprocess_run() operate + * on the same state and thus must be serialized. Because the audio + * lock is not held, this call has the potential to mess-up the + * preprocessor (which is serialized by the audio lock). I believe the + * net effect of this problem is to break residual echo cancellation + * when these calls overlap. Unfortunately, just serializing this + * speex_echo_cancellation() call with the audio lock may not be + * sufficient since the next call to speex_preprocess_run() is counting + * on operating on this cancelledBuffer -- since we buffer the input + * audio (cancelledBuffer), we are actually explicitly decoupling the + * calls to speex_echo_cancellation() and speex_preprocess_run(). Oops. + * + * In other words, it should go like this: + * + * speex_echo_cancellation(A) + * speex_preprocess_run(A) + * speex_echo_cancellation(B) + * speex_preprocess_run(B) + * speex_echo_cancellation(C) + * speex_preprocess_run(C) + * + * but it actually may be going like this: + * + * speex_echo_cancellation(A) + * speex_echo_cancellation(B) + * speex_preprocess_run(A) -- bad, residual echo from B is applied to A + * speex_echo_cancellation(C) + * speex_preprocess_run(B) -- bad, residual echo from C is applied to B + * speex_preprocess_run(C) + */ speex_echo_cancellation(ec, inputBuffer, delayedBuf, cancelledBuffer); memcpy(inputBuffer, cancelledBuffer, samples * sizeof(short)); Modified: branches/team/elbunce/iaxclient/lib/audio_portaudio.c =================================================================== --- branches/team/elbunce/iaxclient/lib/audio_portaudio.c 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/lib/audio_portaudio.c 2008-08-06 00:48:54 UTC (rev 1449) @@ -739,8 +739,6 @@ static int pa_start(struct iaxc_audio_driver *d) { - static int errcnt = 0; - if ( running ) return 0; @@ -757,29 +755,13 @@ oMixer = NULL; } - if ( errcnt > 5 ) - { - iaxci_usermsg(IAXC_TEXT_TYPE_FATALERROR, - "iaxclient audio: Can't open Audio Device. " - "Perhaps you do not have an input or output device?"); - /* OK, we'll give the application the option to abort or - * not here, but we will throw a fatal error anyway */ - iaxc_millisleep(1000); - //return -1; // Give Up. Too many errors. - } - /* flush the ringbuffers */ rb_InitializeRingBuffer(&inRing, INRBSZ, inRingBuf); rb_InitializeRingBuffer(&outRing, OUTRBSZ, outRingBuf); if ( pa_openstreams(d) ) - { - errcnt++; return -1; - } - errcnt = 0; // only count consecutive errors. - if ( Pa_StartStream(iStream) != paNoError ) return -1; Modified: branches/team/elbunce/iaxclient/lib/iaxclient_lib.c =================================================================== --- branches/team/elbunce/iaxclient/lib/iaxclient_lib.c 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/lib/iaxclient_lib.c 2008-08-06 00:48:54 UTC (rev 1449) @@ -416,7 +416,7 @@ return count; } -EXPORT int iaxc_first_free_call() +EXPORT int iaxc_first_free_call(void) { int i; for ( i = 0; i < max_calls; i++ ) @@ -784,10 +784,13 @@ } } -#define LOOP_SLEEP 5 // In ms static THREADFUNCDECL(main_proc_thread_func) { + const int sleep_ms = 5; + const int counts_per_second = 1000 / sleep_ms; static int refresh_registration_count = 0; + static int audio_error_count = 0; + static int audio_error_state = 0; THREADFUNCRET(ret); @@ -799,11 +802,31 @@ get_iaxc_lock(); service_network(); - if ( !test_mode ) - service_audio(); + if ( !test_mode && + (!audio_error_state || + audio_error_count++ % counts_per_second == 0) ) + { + /* There are cases when service audio fails such + * as when there is no audio devices present in + * the system. In these cases, only call + * service_audio() once per second until it + * succeeds. + */ + if ( (audio_error_state = service_audio()) ) + { + iaxci_usermsg(IAXC_NOTICE, + "failed to service audio"); + + if ( audio_error_count / counts_per_second == 5 ) + iaxci_usermsg(IAXC_TEXT_TYPE_FATALERROR, + "cannot open audio device" + " after several tries"); + } + } + // Check registration refresh once a second - if ( refresh_registration_count++ > 1000/LOOP_SLEEP ) + if ( refresh_registration_count++ > counts_per_second ) { iaxc_refresh_registrations(); refresh_registration_count = 0; @@ -811,7 +834,7 @@ put_iaxc_lock(); - iaxc_millisleep(LOOP_SLEEP); + iaxc_millisleep(sleep_ms); } /* Decrease priority */ @@ -868,7 +891,8 @@ int to_read; int cmin; - audio_driver.start(&audio_driver); + if ( audio_driver.start(&audio_driver) ) + return -1; /* check and report if pointers are not good here */ if ( !((unsigned int)call & 0xffffff00) ) @@ -966,7 +990,7 @@ } /* handle IAX URL events */ -void handle_url_event( struct iax_event *e, int callNo ) +static void handle_url_event( struct iax_event *e, int callNo ) { iaxc_event ev; @@ -1195,6 +1219,7 @@ iaxc_clear_call(callNo); break; case IAX_EVENT_ACCEPT: + calls[callNo].state |= IAXC_CALL_STATE_ACTIVE; calls[callNo].format = e->ies.format & IAXC_AUDIO_FORMAT_MASK; calls[callNo].vformat = e->ies.format & IAXC_VIDEO_FORMAT_MASK; #if USE_VIDEO @@ -1204,6 +1229,7 @@ "Failed video codec negotiation."); } #endif + iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS,"Call %d accepted", callNo); break; case IAX_EVENT_ANSWER: @@ -1373,7 +1399,7 @@ } else { // use selected call if not active, otherwise, get a new appearance - if ( calls[selected_call].state & IAXC_CALL_STATE_ACTIVE ) + if ( calls[selected_call].state & IAXC_CALL_STATE_ACTIVE ) { callNo = iaxc_first_free_call(); } else @@ -1427,7 +1453,7 @@ strncpy(calls[callNo].local , calls[callNo].callerid_name, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].local_context, "default", IAXC_EVENT_BUFSIZ); - calls[callNo].state = IAXC_CALL_STATE_ACTIVE | IAXC_CALL_STATE_OUTGOING; + calls[callNo].state = IAXC_CALL_STATE_OUTGOING; /* reset activity and ping "timers" */ iaxc_note_activity(callNo); @@ -1534,9 +1560,12 @@ EXPORT void iaxc_dump_call_number( int callNo ) { - get_iaxc_lock(); - iaxc_dump_one_call(callNo); - put_iaxc_lock(); + if ( callNo >= 0 && callNo < max_calls ) + { + get_iaxc_lock(); + iaxc_dump_one_call(callNo); + put_iaxc_lock(); + } } EXPORT void iaxc_dump_call(void) Modified: branches/team/elbunce/iaxclient/lib/libiax2/src/frame.h =================================================================== --- branches/team/elbunce/iaxclient/lib/libiax2/src/frame.h 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/lib/libiax2/src/frame.h 2008-08-06 00:48:54 UTC (rev 1449) @@ -21,124 +21,70 @@ #endif /* Frame types */ -#define AST_FRAME_DTMF 1 /* A DTMF digit, subclass is the digit */ -#define AST_FRAME_VOICE 2 /* Voice data, subclass is AST_FORMAT_* */ -#define AST_FRAME_VIDEO 3 /* Video frame, maybe?? :) */ -#define AST_FRAME_CONTROL 4 /* A control frame, subclass is AST_CONTROL_* */ -#define AST_FRAME_NULL 5 /* An empty, useless frame */ -#define AST_FRAME_IAX 6 /* Inter Aterisk Exchange private frame type */ -#define AST_FRAME_TEXT 7 /* Text messages */ -#define AST_FRAME_IMAGE 8 /* Image Frames */ -#define AST_FRAME_HTML 9 /* HTML Frames */ -#define AST_FRAME_CNG 10 /* Comfort Noise frame (subclass is level of CNG in -dBov) */ +#define AST_FRAME_DTMF 1 /* A DTMF digit, subclass is the digit */ +#define AST_FRAME_VOICE 2 /* Voice data, subclass is AST_FORMAT_* */ +#define AST_FRAME_VIDEO 3 /* Video frame, maybe?? :) */ +#define AST_FRAME_CONTROL 4 /* A control frame, subclass is AST_CONTROL_* */ +#define AST_FRAME_NULL 5 /* An empty, useless frame */ +#define AST_FRAME_IAX 6 /* Inter Aterisk Exchange private frame type */ +#define AST_FRAME_TEXT 7 /* Text messages */ +#define AST_FRAME_IMAGE 8 /* Image Frames */ +#define AST_FRAME_HTML 9 /* HTML Frames */ +#define AST_FRAME_CNG 10 /* Comfort Noise frame (subclass is level of CNG in -dBov) */ /* HTML subclasses */ -#define AST_HTML_URL 1 /* Sending a URL */ -#define AST_HTML_DATA 2 /* Data frame */ -#define AST_HTML_BEGIN 4 /* Beginning frame */ -#define AST_HTML_END 8 /* End frame */ -#define AST_HTML_LDCOMPLETE 16 /* Load is complete */ -#define AST_HTML_NOSUPPORT 17 /* Peer is unable to support HTML */ -#define AST_HTML_LINKURL 18 /* Send URL and track */ -#define AST_HTML_UNLINK 19 /* Request no more linkage */ -#define AST_HTML_LINKREJECT 20 /* Reject LINKURL */ +#define AST_HTML_URL 1 /* Sending a URL */ +#define AST_HTML_DATA 2 /* Data frame */ +#define AST_HTML_BEGIN 4 /* Beginning frame */ +#define AST_HTML_END 8 /* End frame */ +#define AST_HTML_LDCOMPLETE 16 /* Load is complete */ +#define AST_HTML_NOSUPPORT 17 /* Peer is unable to support HTML */ +#define AST_HTML_LINKURL 18 /* Send URL and track */ +#define AST_HTML_UNLINK 19 /* Request no more linkage */ +#define AST_HTML_LINKREJECT 20 /* Reject LINKURL */ /* Data formats for capabilities and frames alike */ -/*! G.723.1 compression */ -#define AST_FORMAT_G723_1 (1 << 0) - /*! GSM compression */ -#define AST_FORMAT_GSM (1 << 1) - /*! Raw mu-law data (G.711) */ -#define AST_FORMAT_ULAW (1 << 2) - /*! Raw A-law data (G.711) */ -#define AST_FORMAT_ALAW (1 << 3) - /*! ADPCM (G.726, 32kbps) */ -#define AST_FORMAT_G726 (1 << 4) - /*! ADPCM (IMA) */ -#define AST_FORMAT_ADPCM (1 << 5) - /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ -#define AST_FORMAT_SLINEAR (1 << 6) - /*! LPC10, 180 samples/frame */ -#define AST_FORMAT_LPC10 (1 << 7) - /*! G.729A audio */ -#define AST_FORMAT_G729A (1 << 8) - /*! SpeeX Free Compression */ -#define AST_FORMAT_SPEEX (1 << 9) - /*! iLBC Free Compression */ -#define AST_FORMAT_ILBC (1 << 10) - /*! Maximum audio format */ -#define AST_FORMAT_MAX_AUDIO (1 << 15) - /*! JPEG Images */ -#define AST_FORMAT_JPEG (1 << 16) - /*! PNG Images */ -#define AST_FORMAT_PNG (1 << 17) - /*! H.261 Video */ -#define AST_FORMAT_H261 (1 << 18) - /*! H.263 Video */ -#define AST_FORMAT_H263 (1 << 19) - /*! H.263+ Video */ -#define AST_FORMAT_H263p (1 << 20) - /*! H.264 Video*/ -#define AST_FORMAT_H264 (1 << 21) - /*! MPEG4 Video*/ -#define AST_FORMAT_MPEG4 (1 << 22) - /*! Theora Video */ -#define AST_FORMAT_THEORA (1 << 24) - /*! Max one */ -#define AST_FORMAT_MAX_VIDEO (1 << 24) +#define AST_FORMAT_G723_1 (1 << 0) /*! G.723.1 compression */ +#define AST_FORMAT_GSM (1 << 1) /*! GSM compression */ +#define AST_FORMAT_ULAW (1 << 2) /*! Raw mu-law data (G.711) */ +#define AST_FORMAT_ALAW (1 << 3) /*! Raw A-law data (G.711) */ +#define AST_FORMAT_G726 (1 << 4) /*! ADPCM (G.726, 32kbps) */ +#define AST_FORMAT_ADPCM (1 << 5) /*! ADPCM (IMA) */ +#define AST_FORMAT_SLINEAR (1 << 6) /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ +#define AST_FORMAT_LPC10 (1 << 7) /*! LPC10, 180 samples/frame */ +#define AST_FORMAT_G729A (1 << 8) /*! G.729A audio */ +#define AST_FORMAT_SPEEX (1 << 9) /*! SpeeX Free Compression */ +#define AST_FORMAT_ILBC (1 << 10) /*! iLBC Free Compression */ +#define AST_FORMAT_MAX_AUDIO (1 << 15) /*! Maximum audio format */ +#define AST_FORMAT_JPEG (1 << 16) /*! JPEG Images */ +#define AST_FORMAT_PNG (1 << 17) /*! PNG Images */ +#define AST_FORMAT_H261 (1 << 18) /*! H.261 Video */ +#define AST_FORMAT_H263 (1 << 19) /*! H.263 Video */ +#define AST_FORMAT_H263p (1 << 20) /*! H.263+ Video */ +#define AST_FORMAT_H264 (1 << 21) /*! H.264 Video*/ +#define AST_FORMAT_MPEG4 (1 << 22) /*! MPEG4 Video*/ +#define AST_FORMAT_THEORA (1 << 24) /*! Theora Video */ +#define AST_FORMAT_MAX_VIDEO (1 << 24) /*! Maximum video format */ /* Control frame types */ -#define AST_CONTROL_HANGUP 1 /* Other end has hungup */ -#define AST_CONTROL_RING 2 /* Local ring */ -#define AST_CONTROL_RINGING 3 /* Remote end is ringing */ -#define AST_CONTROL_ANSWER 4 /* Remote end has answered */ -#define AST_CONTROL_BUSY 5 /* Remote end is busy */ -#define AST_CONTROL_TAKEOFFHOOK 6 /* Make it go off hook */ -#define AST_CONTROL_OFFHOOK 7 /* Line is off hook */ -#define AST_CONTROL_CONGESTION 8 /* Congestion (circuits busy) */ -#define AST_CONTROL_FLASH 9 /* Flash hook */ -#define AST_CONTROL_WINK 10 /* Wink */ -#define AST_CONTROL_OPTION 11 /* Set an option */ -#define AST_CONTROL_KEY 12 /* Key Radio */ -#define AST_CONTROL_UNKEY 13 /* Unkey Radio */ +#define AST_CONTROL_HANGUP 1 /* Other end has hungup */ +#define AST_CONTROL_RING 2 /* Local ring */ +#define AST_CONTROL_RINGING 3 /* Remote end is ringing */ +#define AST_CONTROL_ANSWER 4 /* Remote end has answered */ +#define AST_CONTROL_BUSY 5 /* Remote end is busy */ +#define AST_CONTROL_TAKEOFFHOOK 6 /* Make it go off hook */ +#define AST_CONTROL_OFFHOOK 7 /* Line is off hook */ +#define AST_CONTROL_CONGESTION 8 /* Congestion (circuits busy) */ +#define AST_CONTROL_FLASH 9 /* Flash hook */ +#define AST_CONTROL_WINK 10 /* Wink */ +#define AST_CONTROL_OPTION 11 /* Set an option */ +#define AST_CONTROL_KEY 12 /* Key Radio */ +#define AST_CONTROL_UNKEY 13 /* Unkey Radio */ -#define AST_FRIENDLY_OFFSET 64 /* Reserved header space */ +#define AST_FRIENDLY_OFFSET 64 /* Reserved header space */ -struct ast_frame { - /*! Kind of frame */ - int frametype; - /*! Subclass, frame dependent */ - int subclass; - /*! Length of data */ - int datalen; - /*! Number of 8khz samples in this frame */ - int samples; - /*! Was the data malloc'd? i.e. should we free it when we discard the f -rame? */ - int mallocd; - /*! How far into "data" the data really starts */ - int offset; - /*! Optional source of frame for debugging */ - char *src; - /*! Pointer to actual data */ - void *data; - /*! Next/Prev for linking stand alone frames */ - struct ast_frame *prev; - /*! Next/Prev for linking stand alone frames */ - struct ast_frame *next; - /* Unused except - if debugging is turned on, but left - in the struct - so that it can be turned on without - requiring a r -ecompile of the whole thing */ -}; - - - #if defined(__cplusplus) || defined(c_plusplus) } #endif - #endif Modified: branches/team/elbunce/iaxclient/lib/libiax2/src/iax.c =================================================================== --- branches/team/elbunce/iaxclient/lib/libiax2/src/iax.c 2008-07-02 22:49:16 UTC (rev 1448) +++ branches/team/elbunce/iaxclient/lib/libiax2/src/iax.c 2008-08-06 00:48:54 UTC (rev 1449) @@ -364,6 +364,44 @@ static struct iax_session *sessions = NULL; static int callnums = 1; +static inline struct timeval iax_tvadd_ms(struct timeval tv, int ms) +{ + const int million = 1000000; + tv.tv_sec += ms / 1000; + ms %= 1000; + tv.tv_usec += ms * 1000; + if ( tv.tv_usec > million ) + { + tv.tv_sec += 1; + tv.tv_usec -= million; + } + return tv; +} + +static inline int iax_tvdiff_ms(struct timeval end, struct timeval start) +{ + return ((end.tv_sec - start.tv_sec) * 1000) + + (((1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000); +} + +static inline int iax_tvcmp(struct timeval a, struct timeval b) +{ + if ( a.tv_sec < b.tv_sec ) + return -1; + if ( a.tv_sec > b.tv_sec ) + return 1; + if ( a.tv_usec < b.tv_usec ) + return -1; + if ( a.tv_usec > b.tv_usec ) + return 1; + return 0; +} + +static inline int iax_tvzero(const struct timeval t) +{ + return t.tv_sec == 0 && t.tv_usec == 0; +} + unsigned int iax_session_get_capability(struct iax_session *s) { return s->capability; @@ -376,65 +414,56 @@ static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int ms) { + /* Schedule event to be delivered to the client in ms milliseconds from + * now, or a reliable frame to be retransmitted */ + struct iax_sched *sched; + struct iax_sched *cur = schedq; + struct iax_sched *prev = NULL; - /* Schedule event to be delivered to the client - in ms milliseconds from now, or a reliable frame to be retransmitted */ - struct iax_sched *sched, *cur, *prev = NULL; - if (!event && !frame && !func) { DEBU(G "No event, no frame, no func? what are we scheduling?\n"); return -1; } - //fprintf(stderr, "scheduling event %d ms from now\n", ms); - sched = (struct iax_sched*)malloc(sizeof(struct iax_sched)); - if (sched) { - memset(sched, 0, sizeof(struct iax_sched)); - sched->when = iax_tvnow(); - sched->when.tv_sec += (ms / 1000); - ms = ms % 1000; - sched->when.tv_usec += (ms * 1000); - if (sched->when.tv_usec > 1000000) { - sched->when.tv_usec -= 1000000; - sched->when.tv_sec++; - } - sched->event = event; - sched->frame = frame; - sched->func = func; - sched->arg = arg; - /* Put it in the list, in order */ - cur = schedq; - while(cur && ((cur->when.tv_sec < sched->when.tv_sec) || - ((cur->when.tv_usec <= sched->when.tv_usec) && - (cur->when.tv_sec == sched->when.tv_sec)))) { - prev = cur; - cur = cur->next; - } - sched->next = cur; - if (prev) { - prev->next = sched; - } else { - schedq = sched; - } - return 0; - } else { + sched = calloc(1, sizeof(struct iax_sched)); + if (!sched) { DEBU(G "Out of memory!\n"); return -1; } + + sched->when = iax_tvadd_ms(iax_tvnow(), ms); + sched->event = event; + sched->frame = frame; + sched->func = func; + sched->arg = arg; + + /* Put it in the list, in order */ + while (cur && iax_tvcmp(cur->when, sched->when) <= 0) { + prev = cur; + cur = cur->next; + } + sched->next = cur; + if (prev) { + prev->next = sched; + } else { + schedq = sched; + } + + return 0; } static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all) { - struct iax_sched *cur, *tmp, *prev = NULL; + struct iax_sched *cur = schedq; + struct iax_sched *prev = NULL; - cur = schedq; while (cur) { if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) { + struct iax_sched *tmp = cur; if (prev) prev->next = cur->next; else schedq = cur->next; - tmp = cur; cur = cur->next; free(tmp); if (!all) @@ -447,27 +476,25 @@ return 0; } - int iax_time_to_next_event(void) { - struct timeval tv; + struct timeval now; struct iax_sched *cur = schedq; - int ms, min = 999999999; + int min = 999999999; /* If there are no pending events, we don't need to timeout */ if (!cur) return -1; - tv = iax_tvnow(); + + now = iax_tvnow(); + while(cur) { - ms = (cur->when.tv_sec - tv.tv_sec) * 1000 + - (cur->when.tv_usec - tv.tv_usec) / 1000; + int ms = iax_tvdiff_ms(cur->when, now); if (ms < min) min = ms; cur = cur->next; } - if (min < 0) - min = 0; - return min; + return min < 0 ? 0 : min; } struct iax_session *iax_session_new(void) @@ -542,7 +569,8 @@ local->jitter = stats.jitter; /* XXX: should be short-term loss pct.. */ - if(stats.frames_in == 0) stats.frames_in = 1; + if(stats.frames_in == 0) + stats.frames_in = 1; local->losspct = stats.losspct/1000; local->losscnt = stats.frames_lost; local->packets = stats.frames_in; @@ -553,74 +581,29 @@ return 0; } -#ifdef USE_VOICE_TS_PREDICTION -static void add_ms(struct timeval *tv, int ms) +static int calc_timestamp(struct iax_session *session, int frametype, int samples) { - tv->tv_usec += ms * 1000; - if (tv->tv_usec > 999999) { - tv->tv_sec += tv->tv_usec / 1000000; - tv->tv_usec %= 1000000; - } - - if (tv->tv_usec < 0) { - tv->tv_sec += (tv->tv_usec / 1000000 - 1); - tv->tv_usec = (tv->tv_usec % 1000000) + 1000000; - } -} -#endif - -static int calc_timestamp(struct iax_session *session, unsigned int ts, struct ast_frame *f) -{ - int ms; - struct timeval tv; - int voice = 0; - int video = 0; - int genuine = 0; - - if ( f && f->frametype == AST_FRAME_VOICE ) - { - voice = 1; - } else if ( f && f->frametype == AST_FRAME_VIDEO ) - { - video = 1; - } else if (!f || f->frametype == AST_FRAME_IAX) - { - genuine = 1; - } - - /* If this is the first packet we're sending, get our - offset now. */ - if (!session->offset.tv_sec && !session->offset.tv_usec) - session->offset = iax_tvnow(); - - /* If the timestamp is specified, just use their specified - timestamp no matter what. Usually this is done for - special cases. */ - if (ts) - { - if ( f && session ) - session->lastsent = ts; - return ts; - } - - /* Otherwise calculate the timestamp from the current time */ - tv = iax_tvnow(); - /* Calculate the number of milliseconds since we sent the first packet */ - ms = (tv.tv_sec - session->offset.tv_sec) * 1000 + - (tv.tv_usec - session->offset.tv_usec) / 1000; + int ms = iax_tvdiff_ms(iax_tvnow(), session->offset); + int genuine = !frametype || frametype == AST_FRAME_IAX; + int voice = frametype == AST_FRAME_VOICE; + int video = frametype == AST_FRAME_VIDEO; - if (ms < 0) + if (ms < 0) { + fprintf(stderr, "iax2: calc_timestamp: negative time delta " + "ms => %d\n", ms); ms = 0; + } - if(voice) { + if (voice) { #ifdef USE_VOICE_TS_PREDICTION /* If we haven't most recently sent silence, and we're * close in time, use predicted time */ if(session->notsilenttx && abs(ms - session->nextpred) <= 240) { /* Adjust our txcore, keeping voice and non-voice * synchronized */ - add_ms(&session->offset, (int)(ms - session->nextpred)/10); + session->offset = iax_tvadd_ms(session->offset, + (int)(ms - session->nextpred) / 10); if(!session->nextpred) session->nextpred = ms; @@ -632,30 +615,34 @@ * time. Also, round ms to the next multiple of * frame size (so our silent periods are multiples * of frame size too) */ - int diff = ms % (f->samples / 8); + int diff = ms % (samples / 8); if(diff) - ms += f->samples/8 - diff; + ms += samples / 8 - diff; session->nextpred = ms; } session->notsilenttx = 1; + + /* set next predicted ts based on 8khz samples */ + session->nextpred += samples / 8; #else if(ms <= session->lastsent) ms = session->lastsent + 3; #endif } else if ( video ) { - /* - * IAX2 draft 03 says that timestamps MUST be in order. - * It does not say anything about several frames having the same timestamp - * When transporting video, we can have a frame that spans multiple iax packets - * (so called slices), so it would make sense to use the same timestamp for all of - * them - * We do want to make sure that frames don't go backwards though + /* IAX2 draft 03 says that timestamps MUST be in order. It + * does not say anything about several frames having the same + * timestamp. When transporting video, we can have a frame + * that spans multiple iax packets (so called slices), so it + * would make sense to use the same timestamp for all of them. + * We do want to make sure that frames don't go backwards + * though. */ if ( (unsigned int)ms < session->lastsent ) ms = session->lastsent; } else { - /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) - if appropriate unless it's a genuine frame */ + /* On a dataframe, use last value + 3 (to accomodate jitter + * buffer shrinking) if appropriate unless it's a genuine frame + */ if (genuine) { if ((unsigned int)ms <= session->lastsent) ms = session->lastsent + 3; @@ -665,21 +652,10 @@ } - /* Record the last sent packet for future reference */ - /* unless an AST_FRAME_IAX */ - if (!genuine) - session->lastsent = ms; - -#ifdef USE_VOICE_TS_PREDICTION - /* set next predicted ts based on 8khz samples */ - if(voice) - session->nextpred += f->samples / 8; -#endif - return ms; } -static unsigned char get_n_bits_at(unsigned char *data, int n, int bit) +static unsigned char get_n_bits_at(const unsigned char *data, const int n, const int bit) { int byte = bit / 8; /* byte containing first bit */ int rem = 8 - (bit % 8); /* remaining bits in first byte */ @@ -698,101 +674,106 @@ return (ret & (0xff >> (8 - n))); } -static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) +static int speex_get_wb_sz_at(const unsigned char *data, const int len, const int bit) { - static int SpeexWBSubModeSz[] = { - 0, 36, 112, 192, - 352, 0, 0, 0 }; + static const int wb_skip_table[] = { + 0, 36, 112, 192, 352, 0, 0, 0 + }; + const int bit_len = len * 8; int off = bit; - unsigned char c; + int wideband; + if (bit_len - off < 5) + return -5; + + wideband = get_n_bits_at(data, 1, off); + /* skip up to two wideband frames */ - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; + if (wideband) + { + int submode = get_n_bits_at(data, 3, off + 1); + off += wb_skip_table[submode]; - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; + if (bit_len - off < 5) + return -6; - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { + wideband = get_n_bits_at(data, 1, off); + + if (wideband) + { + submode = get_n_bits_at(data, 3, off + 1); + off += wb_skip_table[submode]; + + if (bit_len - off < 5) + return -7; + + wideband = get_n_bits_at(data, 1, off); + if (wideband) /* too many in a row */ - DEBU(G "\tCORRUPT too many wideband streams in a row\n"); - return -1; - } + return -8; } } return off - bit; } -static int speex_get_samples(unsigned char *data, int len) +static int speex_get_samples(const unsigned char *data, const int len) { - static int SpeexSubModeSz[] = { + static const int SpeexSubModeSz[] = { 0, 43, 119, 160, 220, 300, 364, 492, 79, 0, 0, 0, 0, 0, 0, 0 }; - static int SpeexInBandSz[] = { + static const int SpeexInBandSz[] = { 1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 }; + const int bit_len = len * 8; int bit = 0; int cnt = 0; - int off = 0; - unsigned char c; - DEBU(G "speex_get_samples(%d)\n", len); - while ((len * 8 - bit) >= 5) { + while (bit_len - bit >= 5) { + unsigned char c; + /* skip wideband frames */ - off = speex_get_wb_sz_at(data, len, bit); - if (off < 0) { - DEBU(G "\tERROR reading wideband frames\n"); - break; - } - bit += off; + const int advance = speex_get_wb_sz_at(data, len, bit); + if (advance < 0) + return advance; - if ((len * 8 - bit) < 5) { - DEBU(G "\tERROR not enough bits left after wb\n"); - break; - } + bit += advance; + if (bit_len - bit < 5) + return -1; + /* get control bits */ c = get_n_bits_at(data, 5, bit); - DEBU(G "\tCONTROL: %d at %d\n", c, bit); bit += 5; if (c == 15) { - DEBU(G "\tTERMINATOR\n"); + /* terminator */ break; } else if (c == 14) { /* in-band signal; next 4 bits contain signal id */ + if (bit_len - bit < 4) + return -3; c = get_n_bits_at(data, 4, bit); - bit += 4; - DEBU(G "\tIN-BAND %d bits\n", SpeexInBandSz[c]); - bit += SpeexInBandSz[c]; + bit += 4 + SpeexInBandSz[c]; } else if (c == 13) { /* user in-band; next 5 bits contain msg len */ + if (bit_len - bit < 5) + return -4; c = get_n_bits_at(data, 5, bit); - bit += 5; - DEBU(G "\tUSER-BAND %d bytes\n", c); - bit += c * 8; + bit += 5 + c * 8; } else if (c > 8) { - DEBU(G "\tUNKNOWN sub-mode %d\n", c); - break; + /* unknown submode */ + return -2; } else { /* skip number bits for submode (less the 5 control bits) */ - DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]); bit += SpeexSubModeSz[c] - 5; - cnt += 160; /* new frame */ } } - DEBU(G "\tSAMPLES: %d\n", cnt); return cnt; } @@ -853,17 +834,17 @@ int res; #ifdef DEBUG_SUPPORT if (debug) { - struct ast_iax2_full_hdr *h = (struct ast_iax2_full_hdr *)(f->data); + struct ast_iax2_full_hdr *h = (struct ast_iax2_full_hdr *)(f->rawdata); if (ntohs(h->scallno) & IAX_FLAG_FULL) iax_showframe(f, NULL, 0, f->transfer ? &(f->session->transfer) : &(f->session->peeraddr), - f->datalen - sizeof(struct ast_iax2_full_hdr)); + f->rawdatalen - sizeof(struct ast_iax2_full_hdr)); } #endif /* Send the frame raw */ - res = f->session->sendto(netfd, (const char *) f->data, f->datalen, + res = f->session->sendto(netfd, f->rawdata, f->rawdatalen, IAX_SOCKOPTS, f->transfer ? (struct sockaddr *)&(f->session->transfer) : (struct sockaddr *)&(f->session->peeraddr), @@ -873,34 +854,13 @@ static int iax_reliable_xmit(struct iax_frame *f) { - struct iax_frame *fc; - struct ast_iax2_full_hdr *fh; - fh = (struct ast_iax2_full_hdr *) f->data; - if (!fh->type) { + struct ast_iax2_full_hdr *fh = f->rawdata; + + if (!fh->type) return -2; - } - fc = (struct iax_frame *)malloc(sizeof(struct iax_frame)); - if (fc) { - /* Make a copy of the frame */ - memcpy(fc, f, sizeof(struct iax_frame)); - /* And a copy of the data if applicable */ - if (!fc->data || !fc->datalen) { - IAXERROR "No frame data?"); - DEBU(G "No frame data?\n"); - return -1; - } else { - fc->data = (char *)malloc(fc->datalen); - if (!fc->data) { - DEBU(G "Out of memory\n"); - IAXERROR "Out of memory\n"); - return -1; - } - memcpy(fc->data, f->data, f->datalen); - iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime); - return iax_xmit_frame(fc); - } - } else - return -1; + + iax_sched_add(NULL, f, NULL, NULL, f->retrytime); + return iax_xmit_frame(f); } void iax_set_networking(iax_sendto_t st, iax_recvfrom_t rf) @@ -1065,22 +1025,25 @@ return power | IAX_FLAG_SC_LOG; } -static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final, int fullframe) +static int iax_send(struct iax_session *pvt, + int frametype, + int subclass, + const unsigned char *data, + const size_t datalen, + unsigned int ts, + int seqno, + int immediate, + int transfer, + int final, + int fullframe, + int samples) { - /* Queue a packet for delivery on a given private structure. Use "ts" for - timestamp, or calculate if ts is 0. Send immediately without retransmission - or delayed, with retransmission */ - struct ast_iax2_full_hdr *fh; - struct ast_iax2_mini_hdr *mh; - struct ast_iax2_video_hdr *vh; - //unsigned char buf[5120]; //fd: changed max packet size[5120]; - unsigned char buf[32 * 1024]; //Mihai: let's see if this is where it crashes - + /* Queue a packet for delivery on a given private structure. Use "ts" + * for timestamp, or calculate if ts is 0. Send immediately without + * retransmission or delayed, with retransmission */ + char buf[8192]; struct iax_frame *fr; - int res; - int sendmini=0; - unsigned int lastsent; - unsigned int fts; + int sendmini = 0; if (!pvt) { @@ -1088,115 +1051,116 @@ return -1; } - /* this must come before the next call to calc_timestamp() since - calc_timestamp() will change lastsent to the returned value */ - lastsent = pvt->lastsent; + /* If this is the first packet we're sending, get our offset now. */ + if (iax_tvzero(pvt->offset)) + pvt->offset = iax_tvnow(); - /* Calculate actual timestamp */ - fts = calc_timestamp(pvt, ts, f); - - if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) - /* High two bits are the same on timestamp, or sending on a trunk */ && - (f->frametype == AST_FRAME_VOICE) - /* is a voice frame */ && - (f->subclass == pvt->svoiceformat) - /* is the same type */ ) + if (!ts) { - /* Force immediate rather than delayed transmission */ - now = 1; - /* Mark that mini-style frame is appropriate */ - sendmini = 1; + /* Calculate actual timestamp */ + ts = calc_timestamp(pvt, frametype, samples); + + if (!ts) + { + IAXERROR "timestamp is 0?\n"); + return -1; + } } - /* Bitmask taken from chan_iax2.c... I must ask Mark Spencer for this? I think not... */ - if ( f->frametype == AST_FRAME_VIDEO ) + if ( frametype == AST_FRAME_VOICE ) { - /* Check if the timestamp has rolled over or if the video codec has changed */ - if ( ((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) && - (f->subclass == pvt->svideoformat) - ) + /* High two bits are the same on timestamp, or sending on a trunk */ + if ((ts & 0xFFFF0000L) == (pvt->lastsent & 0xFFFF0000L) && + subclass == pvt->svoiceformat) { + /* Force immediate rather than delayed transmission */ + immediate = 1; + /* Mark that mini-style frame is appropriate */ + sendmini = 1; + } + + pvt->lastsent = ts; + } + else if ( frametype == AST_FRAME_VIDEO ) + { + /* Check if the timestamp has rolled over or if the video codec + * has changed */ + if ( (ts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L) && + subclass == pvt->svideoformat ) + { /* send a mini video frame immediately */ - now = 1; + immediate = 1; sendmini = 1; - } else + } + else { - /* we want to send a fullframe and be able to retransmit it */ - now = 0; + /* we want to send a fullframe and be able to + * retransmit it */ + immediate = 0; sendmini = 0; } - pvt->lastvsent = fts; + + pvt->lastvsent = ts; + pvt->lastsent = ts; } /* if requested, force a full frame */ if ( fullframe ) { - now = 0; + immediate = 0; sendmini = 0; } - + /* Allocate an iax_frame */ - if (now) + if (immediate) { + if ( sizeof(*fr) + datalen > sizeof(buf) ) + { + IAXERROR "frame buffer too small"); + return -1; + } fr = (struct iax_frame *) buf; - } else + } + else { - fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen); + fr = iax_frame_new(datalen); if ( fr == NULL ) { IAXERROR "Out of memory\n"); return -1; } } - - /* Copy our prospective frame into our immediate or retransmitted wrapper */ - iax_frame_wrap(fr, f); - fr->ts = fts; - if (!fr->ts) - { - IAXERROR "timestamp is 0?\n"); - if (!now) - iax_frame_free(fr); - return -1; - } - + fr->ts = ts; fr->callno = pvt->callno; fr->transfer = transfer; fr->final = final; fr->session = pvt; + if (!sendmini) { /* We need a full frame */ - if (seqno > -1) - fr->oseqno = seqno; - else - fr->oseqno = pvt->oseqno++; + struct ast_iax2_full_hdr *fh; + + iax_frame_specialize(fr, ast_iax2_full_hdr, data, datalen); + + fh = fr->rawdata; + + fr->oseqno = seqno > -1 ? seqno : pvt->oseqno++; fr->iseqno = pvt->iseqno; - fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr)); fh->scallno = htons(fr->callno | IAX_FLAG_FULL); fh->ts = htonl(fr->ts); fh->oseqno = fr->oseqno; - if (transfer) - { - fh->iseqno = 0; - } else - fh->iseqno = fr->iseqno; - /* Keep track of the last thing we've acknowledged */ + fh->iseqno = transfer ? 0 : fr->iseqno; + /* Keep track of the last thing we've acknowledged */ pvt->aseqno = fr->iseqno; - fh->type = fr->af.frametype & 0xFF; - if (f->frametype == AST_FRAME_VIDEO) - fh->csub = compress_subclass(fr->af.subclass & ~0x1) | ((fr->af.subclass & 0x1) << 6); + fh->type = frametype & 0xFF; + if (frametype == AST_FRAME_VIDEO) + fh->csub = compress_subclass(subclass & ~0x1) | ((subclass & 0x1) << 6); else - fh->csub = compress_subclass(fr->af.subclass); - if (transfer) - { - fr->dcallno = pvt->transfercallno; - } else - fr->dcallno = pvt->peercallno; + fh->csub = compress_subclass(subclass); + fr->dcallno = transfer ? pvt->transfercallno : pvt->peercallno; fh->dcallno = htons(fr->dcallno); - fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr); - fr->data = fh; fr->retries = maxretries; /* Retry after 2x the ping time has passed */ fr->retrytime = pvt->pingtime * 2; @@ -1205,54 +1169,47 @@ if (fr->retrytime > MAX_RETRY_TIME) fr->retrytime = MAX_RETRY_TIME; /* Acks' don't get retried */ - if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK)) + if (frametype == AST_FRAME_IAX && subclass == IAX_COMMAND_ACK) fr->retries = -1; - if (f->frametype == AST_FRAME_VOICE) - { - pvt->svoiceformat = f->subclass; - } - else if (f->frametype == AST_FRAME_VIDEO) - { - pvt->svideoformat = f->subclass & ~0x1; - } - if (now) - { - res = iax_xmit_frame(fr); - } else - res = iax_reliable_xmit(fr); - } else + if (frametype == AST_FRAME_VOICE) + pvt->svoiceformat = subclass; + else if (frametype == AST_FRAME_VIDEO) + pvt->svideoformat = subclass & ~0x1; + } + else { - if (fr->af.frametype == AST_FRAME_VIDEO) + /* Mini-frames have no sequence number */ + fr->oseqno = -1; + fr->iseqno = -1; + fr->retries = -1; + + if (frametype == AST_FRAME_VIDEO) { - /* Video frame have no sequence number */ - fr->oseqno = -1; - fr->iseqno = -1; - vh = (struct ast_iax2_video_hdr *)(((char* )fr->af.data) - sizeof(struct ast_iax2_video_hdr)); + struct ast_iax2_video_hdr *vh; + + iax_frame_specialize(fr, ast_iax2_video_hdr, data, datalen); + + vh = fr->rawdata; vh->zeros = 0; vh->callno = htons(IAX_FLAG_FULL | fr->callno); - vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass & 0x1 ? 0x8000 : 0)); - fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr); - fr->data = vh; - fr->retries = -1; - res = iax_xmit_frame(fr); - } else + vh->ts = htons((fr->ts & 0x7FFF) | (subclass & 0x1 ? 0x8000 : 0)); + } + else { - /* Mini-frames have no sequence number */ - fr->oseqno = -1; - fr->iseqno = -1; /* Mini frame will do */ - mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr)); + struct ast_iax2_mini_hdr *mh; + + iax_frame_specialize(fr, ast_iax2_mini_hdr, data, datalen); + + mh = fr->rawdata; mh->callno = htons(fr->callno); mh->ts = htons(fr->ts & 0xFFFF); - fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr); - fr->data = mh; - fr->retries = -1; - res = iax_xmit_frame(fr); } } - if( !now && fr!=NULL ) - iax_frame_free( fr ); - return res; + + return immediate ? + iax_xmit_frame(fr) : + iax_reliable_xmit(fr); } #if 0 @@ -1281,61 +1238,78 @@ } #endif -static int __send_command(struct iax_session *i, char type, int command, - unsigned int ts, unsigned char *data, int datalen, int seqno, - int now, int transfer, int final, int fullframe, int samples) +static int send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen) { - struct ast_frame f; - f.frametype = type; - f.subclass = command; - f.datalen = datalen; - f.samples = samples; - f.mallocd = 0; - f.offset = 0; -#ifdef __GNUC__ - f.src = (char *) __FUNCTION__; -#else - f.src = (char *) __FILE__; -#endif - f.data = data; - return iax_send(i, &f, ts, seqno, now, transfer, final, fullframe); + return iax_send(i, type, command, data, datalen, ts, + -1, /* seqno */ + 0, /* immediate */ + 0, /* transfer */ + 0, /* final */ + 0, /* fullframe */ + 0 /* samples */ + ); } -static int send_command(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno) +static int send_command_video(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int fullframe) { - return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0, 0); + return iax_send(i, type, command, data, datalen, ts, + -1, /* seqno */ + 1, /* immediate */ + 0, /* transfer */ + 0, /* final */ + fullframe, + 0); /* samples */ } -static int send_command_video(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int fullframe) +static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen) { - return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, fullframe, 0); -} - -static int send_command_final(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno) -{ #if 0 /* It is assumed that the callno has already been locked */ iax_predestroy(i); #endif - int r; - r = __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0, 0); - if (r >= 0) destroy_session(i); + int r = iax_send(i, type, command, data, datalen, ts, + -1, /* seqno */ + 1, /* immediate */ + 0, /* transfer */ + 1, /* final */ + 0, /* fullframe */ + 0); /* samples */ + if (r >= 0) + destroy_session(i); return r; } static int send_command_immediate(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno) { - return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0, 0); + return iax_send(i, type, command, data, datalen, ts, seqno, + 1, /* immediate */ + 0, /* transfer */ + 0, /* final */ + 0, /* fullframe */ + 0); /* samples */ } -static int send_command_transfer(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen) +static int send_command_transfer(struct iax_session *i, char type, int command, unsigned char *data, int datalen) { - return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0, 0); + return iax_send(i, type, command, data, datalen, + 0, /* ts */ + 0, /* seqno */ + 0, /* immediate */ + 1, /* transfer */ + 0, /* final */ + 0, /* fullframe */ + 0); /* samples */ } -static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int seqno, int samples) +static int send_command_samples(struct iax_session *i, char type, int command, unsigned int ts, unsigned char *data, int datalen, int samples) { - return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0, samples); + return iax_send(i, type, command, data, datalen, ts, + -1, /* seqno */ + 0, /* immediate */ + 0, /* transfer */ + 0, /* final */ + 0, /* fullframe */ + samples); } @@ -1351,7 +1325,7 @@ iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, number); // Send The Transfer Command - Asterisk Will Handle The Rest! - res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1); + res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos); // Return Success return 0; @@ -1363,11 +1337,11 @@ sch = schedq; while(sch) { - if (sch->frame && (sch->frame->session == session)) - sch->frame->retries = -1; + if (sch->frame && sch->frame->session == session) + sch->frame->retries = -1; sch = sch->next; } -} /* stop_transfer */ +} static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq) { @@ -1458,12 +1432,12 @@ } #endif - res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1); + res = send_command(s0, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos); if (res < 0) { return -1; } - res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1); + res = send_command(s1, AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos); if (res < 0) { return -1; } @@ -1480,7 +1454,7 @@ iax_ie_append_short(&ied, IAX_IE_CALLNO, new_peer); - res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos, -1); + res = send_command(s, AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied.buf, ied.pos); complete_transfer(s, new_peer, 0, 1); @@ -1564,7 +1538,6 @@ { struct iax_session *cur, *prev=NULL; struct iax_sched *curs, *prevs=NULL, *nexts=NULL; - int loop_cnt=0; curs = schedq; while(curs) { nexts = curs->next; @@ -1583,7 +1556,6 @@ prevs = curs; } curs = nexts; - loop_cnt++; } cur = sessions; @@ -1673,14 +1645,14 @@ int iax_send_dtmf(struct iax_session *session, char digit) { - return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_DTMF, digit, 0, NULL, 0); } int iax_send_voice(struct iax_session *session, int format, unsigned char *data, int datalen, int samples) { /* Send a (possibly compressed) voice frame */ if (!session->quelch) - return send_command_samples(session, AST_FRAME_VOICE, format, 0, data, datalen, -1, samples); + return send_command_samples(session, AST_FRAME_VOICE, format, 0, data, datalen, samples); return 0; } @@ -1690,14 +1662,14 @@ #ifdef USE_VOICE_TS_PREDICTION session->notsilenttx = 0; #endif - return send_command(session, AST_FRAME_CNG, level, 0, data, datalen, -1); + return send_command(session, AST_FRAME_CNG, level, 0, data, datalen); } int iax_send_image(struct iax_session *session, int format, unsigned char *data, int datalen) { /* Send an image frame */ - return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen, -1); + return send_command(session, AST_FRAME_IMAGE, format, 0, data, datalen); } int iax_send_video(struct iax_session *session, int format, unsigned char *data, @@ -1706,7 +1678,7 @@ if (!session->quelch) { int res = send_command_video(session, AST_FRAME_VIDEO, format, - 0, data, datalen, -1, fullframe); + 0, data, datalen, fullframe); return res; } return 0; @@ -1718,12 +1690,12 @@ static int my_lastts = 0; if ( ntrunk == 0 ) - my_lastts = calc_timestamp(session, 0, NULL); + my_lastts = calc_timestamp(session, 0, 0); if ( !session->quelch ) { return send_command_video(session, AST_FRAME_VIDEO, format, - my_lastts, (unsigned char *)data, datalen, -1, + my_lastts, (unsigned char *)data, datalen, fullframe); } return 0; @@ -1774,7 +1746,7 @@ session->refresh = refresh; iax_ie_append_str(&ied, IAX_IE_USERNAME, peer); iax_ie_append_short(&ied, IAX_IE_REFRESH, refresh); - res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos, -1); + res = send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREQ, 0, ied.buf, ied.pos); return res; } @@ -1818,7 +1790,7 @@ strncpy(session->username, peer, sizeof(session->username) - 1); iax_ie_append_str(&ied, IAX_IE_USERNAME, peer); iax_ie_append_str(&ied, IAX_IE_CAUSE, session->unregreason); - return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREL, 0, ied.buf, ied.pos, -1); + return send_command(session, AST_FRAME_IAX, IAX_COMMAND_REGREL, 0, ied.buf, ied.pos); } int iax_reject(struct iax_session *session, char *reason) @@ -1826,7 +1798,7 @@ struct iax_ie_data ied; memset(&ied, 0, sizeof(ied)); iax_ie_append_str(&ied, IAX_IE_CAUSE, reason ? reason : "Unspecified"); - return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos, -1); + return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied.buf, ied.pos); } int iax_hangup(struct iax_session *session, char *byemsg) @@ -1835,33 +1807,33 @@ iax_sched_del(NULL, NULL, send_ping, (void *) session, 1); memset(&ied, 0, sizeof(ied)); iax_ie_append_str(&ied, IAX_IE_CAUSE, byemsg ? byemsg : "Normal clearing"); - return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos, -1); + return send_command_final(session, AST_FRAME_IAX, IAX_COMMAND_HANGUP, 0, ied.buf, ied.pos); } int iax_sendurl(struct iax_session *session, char *url) { return send_command(session, AST_FRAME_HTML, AST_HTML_URL, 0, - (unsigned char *)url, (int)strlen(url), -1); + (unsigned char *)url, (int)strlen(url)); } int iax_ring_announce(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_RINGING, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_RINGING, 0, NULL, 0); } int iax_lag_request(struct iax_session *session) { - return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0); } int iax_busy(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_BUSY, 0, NULL, 0); } int iax_congestion(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_CONGESTION, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_CONGESTION, 0, NULL, 0); } @@ -1870,50 +1842,50 @@ struct iax_ie_data ied; memset(&ied, 0, sizeof(ied)); iax_ie_append_int(&ied, IAX_IE_FORMAT, format); - return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied.buf, ied.pos, -1); + return send_command(session, AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied.buf, ied.pos); } int iax_answer(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0); } int iax_key_radio(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_KEY, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_KEY, 0, NULL, 0); } int iax_unkey_radio(struct iax_session *session) { - return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_UNKEY, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_CONTROL, AST_CONTROL_UNKEY, 0, NULL, 0); } int iax_load_complete(struct iax_session *session) { - return send_command(session, AST_FRAME_HTML, AST_HTML_LDCOMPLETE, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_HTML, AST_HTML_LDCOMPLETE, 0, NULL, 0); } int iax_send_url(struct iax_session *session, const char *url, int link) { return send_command(session, AST_FRAME_HTML, link ? AST_HTML_LINKURL : AST_HTML_URL, 0, - (unsigned char *)url, (int)strlen(url), -1); + (unsigned char *)url, (int)strlen(url)); } int iax_send_text(struct iax_session *session, const char *text) { return send_command(session, AST_FRAME_TEXT, 0, 0, - (unsigned char *)text, (int)strlen(text) + 1, -1); + (unsigned char *)text, (int)strlen(text) + 1); } int iax_send_unlink(struct iax_session *session) { - return send_command(session, AST_FRAME_HTML, AST_HTML_UNLINK, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_HTML, AST_HTML_UNLINK, 0, NULL, 0); } int iax_send_link_reject(struct iax_session *session) { - return send_command(session, AST_FRAME_HTML, AST_HTML_LINKREJECT, 0, NULL, 0, -1); + return send_command(session, AST_FRAME_HTML, AST_HTML_LINKREJECT, 0, NULL, 0); } static int iax_send_pong(struct iax_session *session, unsigned int ts) @@ -1937,13 +1909,13 @@ iax_ie_append_int(&ied,IAX_IE_RR_DROPPED, stats.frames_dropped); iax_ie_append_int(&ied,IAX_IE_RR_OOO, stats.frames_ooo); - return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, ied.buf, ied.pos, -1); + return send_command(session, AST_FRAME_IAX, IAX_COMMAND_PONG, ts, ied.buf, ied.pos); } /* external API; deprecat... [truncated message content] |