aboutsummaryrefslogtreecommitdiffstats
path: root/codecs
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2016-11-24 00:27:14 +0100
committerPeter Wu <peter@lekensteyn.nl>2016-12-06 17:51:47 +0000
commitf5e22a14877922aa7b907d2e434958c86efd6875 (patch)
tree33439d1a8cd3322faa9ce8b0f6b12a08427d47fb /codecs
parentd8cdb550445a1bc86626bd9d45da1ce958d1592b (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.txt9
-rw-r--r--codecs/G722/G722decode.c55
-rw-r--r--codecs/G722/G722decode.h10
-rw-r--r--codecs/G726/G726decode.c86
-rw-r--r--codecs/G726/G726decode.h19
-rw-r--r--codecs/Makefile.am10
-rw-r--r--codecs/codecs.c21
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