|
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] |