diff options
author | Peter Wu <peter@lekensteyn.nl> | 2016-11-24 00:27:14 +0100 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2016-12-06 17:51:47 +0000 |
commit | f5e22a14877922aa7b907d2e434958c86efd6875 (patch) | |
tree | 33439d1a8cd3322faa9ce8b0f6b12a08427d47fb /codecs | |
parent | d8cdb550445a1bc86626bd9d45da1ce958d1592b (diff) |
codecs: Add support for G.722 and G.726
Integrate the Spandsp library for G.722 and G.726 support. Adds support
for G.722 and all eight variants of G.726.
Note: this also fixes a crash in Qt (buffer overrun, reading too much
data) caused by confusion of the larger output buffer (resample_buff)
with the smaller input buffer (decode_buff). It was not triggered before
because the sample rate was always 8k, but with the addition of the new
codecs, a different sample rate became possible (16k).
Fix also a crash which occurs when the RTP_STREAM_DEBUG macro is enabled
and the VOIP Calls dialog is opened (the begin frame, start_fd, is not
yet known and therfore a NULL dereference could occur).
Passes testing (plays normally without bad RTP timing errors) with
SampleCaptures files: sip-rtp-g722.pcap and sip-rtp-g726.pcap. Tested
with cmake (Qt), autotools (Qt and GTK+) with ASAN enabled.
Bug: 5619
Change-Id: I5661908d193927bba50901079119eeff0c04991f
Reviewed-on: https://code.wireshark.org/review/18939
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'codecs')
-rw-r--r-- | codecs/CMakeLists.txt | 9 | ||||
-rw-r--r-- | codecs/G722/G722decode.c | 55 | ||||
-rw-r--r-- | codecs/G722/G722decode.h | 10 | ||||
-rw-r--r-- | codecs/G726/G726decode.c | 86 | ||||
-rw-r--r-- | codecs/G726/G726decode.h | 19 | ||||
-rw-r--r-- | codecs/Makefile.am | 10 | ||||
-rw-r--r-- | codecs/codecs.c | 21 |
7 files changed, 148 insertions, 62 deletions
diff --git a/codecs/CMakeLists.txt b/codecs/CMakeLists.txt index 34bd7be885..4595054059 100644 --- a/codecs/CMakeLists.txt +++ b/codecs/CMakeLists.txt @@ -23,10 +23,6 @@ set(WSCODECS_FILES codecs.c G711a/G711adecode.c G711u/G711udecode.c - # These are wrapped in "#ifdef HAVE_SPANDSP", which we don't currently - # handle or define. - # G722/G722decode.c - # G726/G726decode.c speex/resample.c ) @@ -51,6 +47,11 @@ set(wscodecs_LIBS wsutil ) +if(HAVE_SPANDSP) + list(APPEND WSCODECS_FILES G722/G722decode.c G726/G726decode.c) + list(APPEND wscodecs_LIBS ${SPANDSP_LIBRARIES}) +endif() + add_library(wscodecs ${LINK_MODE_LIB} ${WSCODECS_FILES} ${CMAKE_BINARY_DIR}/image/libwscodecs.rc diff --git a/codecs/G722/G722decode.c b/codecs/G722/G722decode.c index af45520d08..fae16c0626 100644 --- a/codecs/G722/G722decode.c +++ b/codecs/G722/G722decode.c @@ -1,5 +1,5 @@ /* G722decode.c - * A-law G.711 codec + * G.722 codec * * Wireshark - Network traffic analyzer * By Gerald Combs <gerald@wireshark.org> @@ -25,45 +25,66 @@ #include <glib.h> #ifdef HAVE_SPANDSP -#include "telephony.h" -#include "g722.h" +#include "spandsp.h" #include "G722decode.h" -static g722_decode_state_t state; - void * codec_g722_init(void) { - memset (&state, 0, sizeof (state)); - g722_decode_init(&state, 64000, 0); + g722_decode_state_t *state; + + /* Valid values for bit_rate for G.722 are 48000, 56000, 64000, but RTP/AVP + * profile requires 64kbps, aligned at octets. */ + state = g722_decode_init(NULL, 64000, 0); - return NULL; + return state; } void -codec_g722_release(void *ctx _U_) +codec_g722_release(void *ctx) { + g722_decode_state_t *state = (g722_decode_state_t *)ctx; + + if (!state) { + return; /* out-of-memory; */ + } + /* Note: replaces g722_decode_release since spandsp 20090211 */ + g722_decode_free(state); } -int +unsigned codec_g722_get_channels(void *ctx _U_) { + /* G.722 has only one channel. */ return 1; } -int +unsigned codec_g722_get_frequency(void *ctx _U_) { - return 64000; + /* Note: RTP Clock rate is 8kHz due to a historic error, but actual sampling + * rate is 16kHz (RFC 3551, section 4.5.2). */ + return 16000; } -int -codec_g722_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output, - int *outputSizeBytes) +size_t +codec_g722_decode(void *ctx, const void *input, size_t inputSizeBytes, void *output, + size_t *outputSizeBytes) { - *outputSizeBytes = g722_decode(&state, output, input, inputSizeBytes); - return 0; + g722_decode_state_t *state = (g722_decode_state_t *)ctx; + + if (!state) { + return 0; /* out-of-memory; */ + } + + if (!output || !outputSizeBytes) { + return 4 * inputSizeBytes; + } + + /* g722_decode returns the number of 16-bit samples. */ + *outputSizeBytes = 2 * g722_decode(state, (int16_t *)output, (const uint8_t *)input, (int)inputSizeBytes); + return *outputSizeBytes; } #endif diff --git a/codecs/G722/G722decode.h b/codecs/G722/G722decode.h index fa30a092c0..46502632a7 100644 --- a/codecs/G722/G722decode.h +++ b/codecs/G722/G722decode.h @@ -1,5 +1,5 @@ /* G722decode.h - * Definitions for A-law G.722 codec + * Definitions for G.722 codec * * Wireshark - Network traffic analyzer * By Gerald Combs <gerald@wireshark.org> @@ -25,10 +25,10 @@ void *codec_g722_init(void); void codec_g722_release(void *ctx); -int codec_g722_get_channels(void *ctx); -int codec_g722_get_frequency(void *ctx); -int codec_g722_decode(void *ctx, const void *input, int inputSizeBytes, void *output, - int *outputSizeBytes); +unsigned codec_g722_get_channels(void *ctx); +unsigned codec_g722_get_frequency(void *ctx); +size_t codec_g722_decode(void *ctx, const void *input, size_t inputSizeBytes, void *output, + size_t *outputSizeBytes); #endif /* G722decode.h */ diff --git a/codecs/G726/G726decode.c b/codecs/G726/G726decode.c index e454be5ac8..cb157d6c46 100644 --- a/codecs/G726/G726decode.c +++ b/codecs/G726/G726decode.c @@ -24,53 +24,89 @@ #include <glib.h> #ifdef HAVE_SPANDSP -#include "telephony.h" -#include "bitstream.h" -#include "g726.h" +#include "spandsp.h" #include "G726decode.h" -/* this isn't reentrant. Making it might involve quite a few changes to be able to pass a g726 state - * variable to the various functions involved in G.726 decoding. - */ -static g726_state_t state; +typedef struct _g726_codec_ctx { + g726_state_t *state; + int bit_rate; +} g726_codec_ctx; -/* Currently, only G.726-32, linear encoding, left packed is supported */ -void * -codec_g726_init(void) +static inline void * +codec_g726_init(int bit_rate, int packing) { - memset (&state, 0, sizeof (state)); - g726_init(&state, 32000, 0, 1); + g726_state_t *decoder = g726_init(NULL, bit_rate, G726_ENCODING_LINEAR, packing); + + if (!decoder) { + return NULL; /* out-of-memory; */ + } + + g726_codec_ctx *state = g_new(g726_codec_ctx, 1); + state->state = decoder; + state->bit_rate = bit_rate; - return NULL; + return state; } +void *codec_g726_16_init(void) { return codec_g726_init(16000, G726_PACKING_RIGHT); } +void *codec_g726_24_init(void) { return codec_g726_init(24000, G726_PACKING_RIGHT); } +void *codec_g726_32_init(void) { return codec_g726_init(32000, G726_PACKING_RIGHT); } +void *codec_g726_40_init(void) { return codec_g726_init(40000, G726_PACKING_RIGHT); } +void *codec_aal2_g726_16_init(void) { return codec_g726_init(16000, G726_PACKING_LEFT); } +void *codec_aal2_g726_24_init(void) { return codec_g726_init(24000, G726_PACKING_LEFT); } +void *codec_aal2_g726_32_init(void) { return codec_g726_init(32000, G726_PACKING_LEFT); } +void *codec_aal2_g726_40_init(void) { return codec_g726_init(40000, G726_PACKING_LEFT); } + void -codec_g726_release(void *ctx _U_) +codec_g726_release(void *ctx) { + g726_codec_ctx *state = (g726_codec_ctx *)ctx; + + if (!state) { + return; /* out-of-memory; */ + } + /* Note: replaces g726_release since spandsp 20090211 */ + g726_free(state->state); + g_free(state); } -int +unsigned codec_g726_get_channels(void *ctx _U_) { return 1; } -int +unsigned codec_g726_get_frequency(void *ctx _U_) { - return 32000; + return 8000; } -/* Packing should be user defined (via the decode dialog) since due to historical reasons two diverging - * de facto standards are in use today (see RFC3551). - */ -int -codec_g726_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output, - int *outputSizeBytes) +size_t +codec_g726_decode(void *ctx, const void *input, size_t inputSizeBytes, void *output, + size_t *outputSizeBytes) { - *outputSizeBytes = 2 * g726_decode(&state, output, (void*) input, inputSizeBytes); - return 0; + g726_codec_ctx *state = (g726_codec_ctx *)ctx; + + if (!state) { + return 0; /* out-of-memory; */ + } + + if (!output || !outputSizeBytes) { + /* + * sample rate 8kHz, for bitrate 16kHz we have 16/8 = 2 bits/sample, so + * 1 input byte (8 bits) will expand to four 16-bit samples. Likewise, + * for bitrate 40kHz we have 40/8 = 5 bits/sample. Alternatively: + * bitsPerSample = bitRate / sampleRate (8kHz). + * outputBytes = (inputBits / bitsPerSample) * sizeof(sample) + */ + return inputSizeBytes * 8 / (state->bit_rate / 8000) * 2; + } + + /* g726_decode returns the number of 16-bit samples. */ + *outputSizeBytes = 2 * g726_decode(state->state, (int16_t *)output, (const uint8_t *) input, (int)inputSizeBytes); + return *outputSizeBytes; } #endif diff --git a/codecs/G726/G726decode.h b/codecs/G726/G726decode.h index f795c73a14..1ac36eec7f 100644 --- a/codecs/G726/G726decode.h +++ b/codecs/G726/G726decode.h @@ -1,5 +1,5 @@ /* G726decode.h - * Definitions for A-law G.722 codec + * Definitions for G.726 codec * * Wireshark - Network traffic analyzer * By Gerald Combs <gerald@wireshark.org> @@ -23,12 +23,19 @@ #ifndef __CODECS_G726DECODE_H__ #define __CODECS_G726DECODE_H__ -void *codec_g726_init(void); +void *codec_g726_16_init(void); +void *codec_g726_24_init(void); +void *codec_g726_32_init(void); +void *codec_g726_40_init(void); +void *codec_aal2_g726_16_init(void); +void *codec_aal2_g726_24_init(void); +void *codec_aal2_g726_32_init(void); +void *codec_aal2_g726_40_init(void); void codec_g726_release(void *ctx); -int codec_g726_get_channels(void *ctx); -int codec_g726_get_frequency(void *ctx); -int codec_g726_decode(void *ctx, const void *input, int inputSizeBytes, void *output, - int *outputSizeBytes); +unsigned codec_g726_get_channels(void *ctx); +unsigned codec_g726_get_frequency(void *ctx); +size_t codec_g726_decode(void *ctx, const void *input, size_t inputSizeBytes, void *output, + size_t *outputSizeBytes); #endif /* G726decode.h */ diff --git a/codecs/Makefile.am b/codecs/Makefile.am index da74a8d87f..46c4190a99 100644 --- a/codecs/Makefile.am +++ b/codecs/Makefile.am @@ -30,14 +30,16 @@ lib_LTLIBRARIES = libwscodecs.la libwscodecs_la_SOURCES = \ codecs.c \ G711a/G711adecode.c \ - G711u/G711udecode.c \ - G722/G722decode.c \ - G726/G726decode.c + G711u/G711udecode.c if HAVE_SBC libwscodecs_la_SOURCES += sbc/sbc.c endif +if HAVE_SPANDSP +libwscodecs_la_SOURCES += G722/G722decode.c G726/G726decode.c +endif + if !HAVE_SPEEXDSP libwscodecs_la_SOURCES += speex/resample.c endif @@ -45,7 +47,7 @@ endif # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html libwscodecs_la_LDFLAGS = -version-info 0:0:0 @LDFLAGS_SHAREDLIB@ -libwscodecs_la_LIBADD = $(top_builddir)/wsutil/libwsutil.la $(GLIB_LIBS) $(SBC_LIBS) +libwscodecs_la_LIBADD = $(top_builddir)/wsutil/libwsutil.la $(GLIB_LIBS) $(SBC_LIBS) $(SPANDSP_LIBS) libwscodecs_la_DEPENDENCIES = $(top_builddir)/wsutil/libwsutil.la diff --git a/codecs/codecs.c b/codecs/codecs.c index 8b6fcb3efc..447ee67793 100644 --- a/codecs/codecs.c +++ b/codecs/codecs.c @@ -32,6 +32,11 @@ #include "sbc/sbc_private.h" #endif +#ifdef HAVE_SPANDSP +#include "G722/G722decode.h" +#include "G726/G726decode.h" +#endif + #ifdef HAVE_PLUGINS #include <gmodule.h> @@ -108,7 +113,21 @@ register_all_codecs(void) #ifdef HAVE_SPANDSP register_codec("g722", codec_g722_init, codec_g722_release, codec_g722_get_channels, codec_g722_get_frequency, codec_g722_decode); - register_codec("g726", codec_g726_init, codec_g726_release, + register_codec("G726-16", codec_g726_16_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("G726-24", codec_g726_24_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("G726-32", codec_g726_32_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("G726-40", codec_g726_40_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("AAL2-G726-16", codec_aal2_g726_16_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("AAL2-G726-24", codec_aal2_g726_24_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("AAL2-G726-32", codec_aal2_g726_32_init, codec_g726_release, + codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); + register_codec("AAL2-G726-40", codec_aal2_g726_40_init, codec_g726_release, codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode); #endif #ifdef HAVE_SBC |