RTP: Add support for SBC codec in RTP Player

Add optional dependancy to libsbc to play Bluetooth SBC in
A2DP payload. Also simplify RTP Player and extent codec interface.

Change-Id: I52e1fce9c82e2885736354fe73c6c37168a4fda3
Reviewed-on: https://code.wireshark.org/review/19
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Evan Huus <eapache@gmail.com>
This commit is contained in:
Michal Labedzki 2012-09-14 15:08:17 +02:00 committed by Evan Huus
parent ab3348eeb4
commit 10084c344c
17 changed files with 593 additions and 247 deletions

View File

@ -22,21 +22,67 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include "G711adecode.h"
#include "G711atable.h"
int
decodeG711a(void *input, int inputSizeBytes, void *output, int *outputSizeBytes)
void *
codec_g711a_init(void)
{
guint8 *dataIn = (guint8 *)input;
gint16 *dataOut = (gint16 *)output;
int i;
for (i=0; i<inputSizeBytes; i++)
{
dataOut[i] = alaw_exp_table[dataIn[i]];
}
*outputSizeBytes = inputSizeBytes * 2;
return 0;
return NULL;
}
void
codec_g711a_release(void *ctx _U_)
{
}
int
codec_g711a_get_channels(void *ctx _U_)
{
return 1;
}
int
codec_g711a_get_frequency(void *ctx _U_)
{
return 8000;
}
int
codec_g711a_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes)
{
const guint8 *dataIn = (const guint8 *) input;
gint16 *dataOut = (gint16 *) output;
int i;
if (!output || !outputSizeBytes) {
return inputSizeBytes * 2;
}
for (i = 0; i < inputSizeBytes; i++)
{
dataOut[i] = alaw_exp_table[dataIn[i]];
}
*outputSizeBytes = inputSizeBytes * 2;
return inputSizeBytes * 2;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -25,7 +25,24 @@
#ifndef __CODECS_G711ADECODE_H__
#define __CODECS_G711ADECODE_H__
int
decodeG711a(void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
void *codec_g711a_init(void);
void codec_g711a_release(void *ctx);
int codec_g711a_get_channels(void *ctx);
int codec_g711a_get_frequency(void *ctx);
int codec_g711a_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes);
#endif /* G711adecode.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -23,35 +23,49 @@
*/
gint16 alaw_exp_table[256] = {
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848};
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472,
-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848};
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -22,21 +22,68 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include "G711udecode.h"
#include "G711utable.h"
int
decodeG711u(void *input, int inputSizeBytes, void *output, int *outputSizeBytes)
void *
codec_g711u_init(void)
{
guint8 *dataIn = (guint8 *)input;
gint16 *dataOut = (gint16 *)output;
int i;
for (i=0; i<inputSizeBytes; i++)
{
dataOut[i] = ulaw_exp_table[dataIn[i]];
}
*outputSizeBytes = inputSizeBytes * 2;
return 0;
return NULL;
}
void
codec_g711u_release(void *ctx _U_)
{
}
int
codec_g711u_get_channels(void *ctx _U_)
{
return 1;
}
int
codec_g711u_get_frequency(void *ctx _U_)
{
return 8000;
}
int
codec_g711u_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes)
{
const guint8 *dataIn = (const guint8 *) input;
gint16 *dataOut = (gint16 *) output;
int i;
if (!output || !outputSizeBytes) {
return inputSizeBytes * 2;
}
for (i = 0; i < inputSizeBytes; i++)
{
dataOut[i] = ulaw_exp_table[dataIn[i]];
}
*outputSizeBytes = inputSizeBytes * 2;
return inputSizeBytes * 2;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -25,7 +25,24 @@
#ifndef __CODECS_G711UDECODE_H__
#define __CODECS_G711UDECODE_H__
int
decodeG711u(void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
void *codec_g711u_init(void);
void codec_g711u_release(void *ctx);
int codec_g711u_get_channels(void *ctx);
int codec_g711u_get_frequency(void *ctx);
int codec_g711u_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes);
#endif /* G711udecode.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -55,3 +55,16 @@ gint16 ulaw_exp_table[256] = {
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0};
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -33,19 +33,53 @@
static g722_decode_state_t state;
void
initG722(void)
void *
codec_g722_init(void)
{
memset (&state, 0, sizeof (state));
g722_decode_init(&state, 64000, 0);
return NULL;
}
void
codec_g722_release(void *ctx _U_)
{
}
int
decodeG722(void *input _U_NOSPANDSP_, int inputSizeBytes _U_NOSPANDSP_,
void *output _U_NOSPANDSP_, int *outputSizeBytes _U_NOSPANDSP_)
codec_g722_get_channels(void *ctx _U_)
{
return 1;
}
int
codec_g722_get_frequency(void *ctx _U_)
{
return 64000;
}
int
codec_g722_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes)
{
*outputSizeBytes = g722_decode(&state, output, input, inputSizeBytes);
return 0;
}
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -25,10 +25,24 @@
#ifndef __CODECS_G722DECODE_H__
#define __CODECS_G722DECODE_H__
void
initG722(void);
int
decodeG722(void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
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);
#endif /* G722decode.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -37,21 +37,56 @@
static g726_state_t state;
/* Currently, only G.726-32, linear encoding, left packed is supported */
void initG726_32(void)
void *
codec_g726_init(void)
{
memset (&state, 0, sizeof (state));
g726_init(&state, 32000, 0, 1);
return NULL;
}
void
codec_g726_release(void *ctx _U_)
{
}
int
codec_g726_get_channels(void *ctx _U_)
{
return 1;
}
int
codec_g726_get_frequency(void *ctx _U_)
{
return 32000;
}
/* 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
decodeG726_32(void *input, int inputSizeBytes,
void *output, int *outputSizeBytes)
codec_g726_decode(void *ctx _U_, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes)
{
*outputSizeBytes = 2 * g726_decode(&state, output, (void*) input, inputSizeBytes);
return 0;
}
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -25,10 +25,24 @@
#ifndef __CODECS_G726DECODE_H__
#define __CODECS_G726DECODE_H__
void
initG726_32(void);
int
decodeG726_32(void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
void *codec_g726_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);
#endif /* G726decode.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -37,5 +37,5 @@ noinst_HEADERS = \
G711u/G711udecode.h G711u/G711utable.h \
G722/G722decode.h \
G726/G726decode.h \
sbc/sbc.h
sbc/sbc_private.h

View File

@ -26,6 +26,14 @@
#include <glib.h>
#include "codecs.h"
#include "config.h"
#include "G711a/G711adecode.h"
#include "G711u/G711udecode.h"
#ifdef HAVE_SBC
#include "sbc/sbc_private.h"
#endif
#ifdef HAVE_PLUGINS
@ -37,7 +45,7 @@
* List of codec plugins.
*/
typedef struct {
void (*register_codec_module)(void); /* routine to call to register a codec */
void (*register_codec_module)(void); /* routine to call to register a codec */
} codec_plugin;
static GSList *codec_plugins = NULL;
@ -48,44 +56,44 @@ static GSList *codec_plugins = NULL;
static gboolean
check_for_codec_plugin(GModule *handle)
{
gpointer gp;
void (*register_codec_module)(void);
codec_plugin *plugin;
gpointer gp;
void (*register_codec_module)(void);
codec_plugin *plugin;
/*
* Do we have a register_codec_module routine?
*/
if (!g_module_symbol(handle, "register_codec_module", &gp)) {
/* No, so this isn't a codec plugin. */
return FALSE;
}
/*
* Do we have a register_codec_module routine?
*/
if (!g_module_symbol(handle, "register_codec_module", &gp)) {
/* No, so this isn't a codec plugin. */
return FALSE;
}
/*
* Yes - this plugin includes one or more codecs.
*/
register_codec_module = (void (*)(void))gp;
/*
* Yes - this plugin includes one or more codecs.
*/
register_codec_module = (void (*)(void))gp;
/*
* Add this one to the list of codec plugins.
*/
plugin = (codec_plugin *)g_malloc(sizeof (codec_plugin));
plugin->register_codec_module = register_codec_module;
codec_plugins = g_slist_append(codec_plugins, plugin);
return TRUE;
/*
* Add this one to the list of codec plugins.
*/
plugin = (codec_plugin *)g_malloc(sizeof (codec_plugin));
plugin->register_codec_module = register_codec_module;
codec_plugins = g_slist_append(codec_plugins, plugin);
return TRUE;
}
void
codec_register_plugin_types(void)
{
add_plugin_type("codec", check_for_codec_plugin);
add_plugin_type("codec", check_for_codec_plugin);
}
static void
register_codec_plugin(gpointer data, gpointer user_data _U_)
{
codec_plugin *plugin = (codec_plugin *)data;
codec_plugin *plugin = (codec_plugin *)data;
(plugin->register_codec_module)();
(plugin->register_codec_module)();
}
/*
@ -94,15 +102,32 @@ register_codec_plugin(gpointer data, gpointer user_data _U_)
void
register_all_codecs(void)
{
g_slist_foreach(codec_plugins, register_codec_plugin, NULL);
register_codec("g711U", codec_g711u_init, codec_g711u_release,
codec_g711u_get_channels, codec_g711u_get_frequency, codec_g711u_decode);
register_codec("g711A", codec_g711a_init, codec_g711a_release,
codec_g711a_get_channels, codec_g711a_get_frequency, codec_g711a_decode);
#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,
codec_g726_get_channels, codec_g726_get_frequency, codec_g726_decode);
#endif
#ifdef HAVE_SBC
register_codec("SBC", codec_sbc_init, codec_sbc_release,
codec_sbc_get_channels, codec_sbc_get_frequency, codec_sbc_decode);
#endif
g_slist_foreach(codec_plugins, register_codec_plugin, NULL);
}
#endif /* HAVE_PLUGINS */
struct codec_handle {
const char *name;
codec_init_fn init_fn;
codec_release_fn release_fn;
codec_decode_fn decode_fn;
const char *name;
codec_init_fn init_fn;
codec_release_fn release_fn;
codec_get_channels_fn channels_fn;
codec_get_frequency_fn frequency_fn;
codec_decode_fn decode_fn;
};
/*
@ -115,47 +140,76 @@ static GHashTable *registered_codecs = NULL;
codec_handle_t
find_codec(const char *name)
{
return (registered_codecs) ? (codec_handle_t)g_hash_table_lookup(registered_codecs, name) : NULL;
return (registered_codecs) ? (codec_handle_t)g_hash_table_lookup(registered_codecs, name) : NULL;
}
/* Register a codec by name. */
gboolean
register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn)
register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn,
codec_get_channels_fn channels_fn, codec_get_frequency_fn frequency_fn,
codec_decode_fn decode_fn)
{
struct codec_handle *handle;
struct codec_handle *handle;
/* Create our hash table if it doesn't already exist */
if (registered_codecs == NULL)
registered_codecs = g_hash_table_new(g_str_hash, g_str_equal);
/* Create our hash table if it doesn't already exist */
if (registered_codecs == NULL)
registered_codecs = g_hash_table_new(g_str_hash, g_str_equal);
/* Make sure the registration is unique */
if (g_hash_table_lookup(registered_codecs, name) != NULL)
return FALSE; /* report an error, or have our caller do it? */
/* Make sure the registration is unique */
if (g_hash_table_lookup(registered_codecs, name) != NULL)
return FALSE; /* report an error, or have our caller do it? */
handle = (struct codec_handle *)g_malloc(sizeof (struct codec_handle));
handle->name = name;
handle->init_fn = init_fn;
handle->release_fn = release_fn;
handle->decode_fn = decode_fn;
handle = (struct codec_handle *)g_malloc(sizeof (struct codec_handle));
handle->name = name;
handle->init_fn = init_fn;
handle->release_fn = release_fn;
handle->channels_fn = channels_fn;
handle->frequency_fn = frequency_fn;
handle->decode_fn = decode_fn;
g_hash_table_insert(registered_codecs, (gpointer)name, (gpointer) handle);
return TRUE;
g_hash_table_insert(registered_codecs, (gpointer)name, (gpointer) handle);
return TRUE;
}
void *codec_init(codec_handle_t codec)
{
if (!codec) return NULL;
return (codec->init_fn)();
if (!codec) return NULL;
return (codec->init_fn)();
}
void codec_release(codec_handle_t codec, void *context)
{
if (!codec) return;
(codec->release_fn)(context);
if (!codec) return;
(codec->release_fn)(context);
}
int codec_get_channels(codec_handle_t codec, void *context)
{
if (!codec) return 0;
return (codec->channels_fn)(context);
}
int codec_get_frequency(codec_handle_t codec, void *context)
{
if (!codec) return 0;
return (codec->frequency_fn)(context);
}
int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes)
{
if (!codec) return 0;
return (codec->decode_fn)(context, input, inputSizeBytes, output, outputSizeBytes);
if (!codec) return 0;
return (codec->decode_fn)(context, input, inputSizeBytes, output, outputSizeBytes);
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -44,16 +44,37 @@ typedef struct codec_handle *codec_handle_t;
typedef void *(*codec_init_fn)(void);
typedef void (*codec_release_fn)(void *context);
typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
typedef int (*codec_get_channels_fn)(void *context);
typedef int (*codec_get_frequency_fn)(void *context);
typedef int (*codec_decode_fn)(void *context, const void *input, int inputSizeBytes,
void *output, int *outputSizeBytes);
extern gboolean register_codec(const char *name, codec_init_fn init_fn, codec_release_fn release_fn, codec_decode_fn decode_fn);
extern gboolean register_codec(const char *name, codec_init_fn init_fn,
codec_release_fn release_fn, codec_get_channels_fn channels_fn,
codec_get_frequency_fn frequency_fn, codec_decode_fn decode_fn);
extern codec_handle_t find_codec(const char *name);
extern void *codec_init(codec_handle_t codec);
extern void codec_release(codec_handle_t codec, void *context);
extern int codec_decode(codec_handle_t codec, void *context, const void *input, int inputSizeBytes, void *output, int *outputSizeBytes);
extern int codec_get_channels(codec_handle_t codec, void *context);
extern int codec_get_frequency(codec_handle_t codec, void *context);
extern int codec_decode(codec_handle_t codec, void *context, const void *input,
int inputSizeBytes, void *output, int *outputSizeBytes);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _CODECS_H_ */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -31,7 +31,7 @@
#include <glib.h>
#include <sbc/sbc.h>
#include "sbc.h"
#include "sbc_private.h"
#define SBC_BUFFER 8192
@ -40,7 +40,7 @@ codec_sbc_init(void)
{
sbc_t *sbc;
sbc = g_malloc(sizeof(sbc_t));
sbc = (sbc_t *) g_malloc(sizeof(sbc_t));
sbc_init(sbc, 0L);
return sbc;
@ -98,16 +98,16 @@ int
codec_sbc_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes)
{
size_t size_in = (size_t) inputSizeBytes;
size_t size_out = SBC_BUFFER;
size_t len;
int framelen;
int xframe_pos = 0;
guint8 *data_in = (guint8 *) input;
guint8 *data_out = (guint8 *) output;
sbc_t *sbc = (sbc_t *) ctx;
guint8 *i_data;
guint8 tmp;
size_t size_in = (size_t) inputSizeBytes;
size_t size_out = SBC_BUFFER;
size_t len;
int framelen;
int xframe_pos = 0;
const guint8 *data_in = (const guint8 *) input;
guint8 *data_out = (guint8 *) output;
sbc_t *sbc = (sbc_t *) ctx;
guint8 *i_data;
guint8 tmp;
if (!output || !outputSizeBytes) {
return size_out;
@ -136,3 +136,16 @@ codec_sbc_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
}
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -28,10 +28,23 @@
#define __CODECS_SBC_H__
void *codec_sbc_init(void);
void codec_sbc_release(void *ctx);
int codec_sbc_get_channels(void *ctx);
int codec_sbc_get_frequency(void *ctx);
int codec_sbc_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
void codec_sbc_release(void *ctx);
int codec_sbc_get_channels(void *ctx);
int codec_sbc_get_frequency(void *ctx);
int codec_sbc_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
int *outputSizeBytes);
#endif /* sbc.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -2623,6 +2623,15 @@ AC_CHECK_FUNCS(mmap mprotect sysconf)
dnl blank for now, but will be used in future
AC_SUBST(wireshark_SUBDIRS)
# Check Bluetooth SBC codec for RTP Player
# git://git.kernel.org/pub/scm/bluetooth/sbc.git
PKG_CHECK_MODULES(SBC, sbc >= 1.0, [have_sbc=yes], [have_sbc=no])
if (test "${have_sbc}" = "yes"); then
AC_DEFINE(HAVE_SBC, 1, [Define to support playing SBC by standalone BlueZ SBC library])
CFLAGS="$CFLAGS $(pkg-config sbc --cflags)"
LIBS="$LIBS $(pkg-config sbc --libs)"
fi
dnl
dnl check whether plugins should be enabled and, if they should be,
dnl check for plugins directory - stolen from Amanda's configure.ac
@ -3053,3 +3062,4 @@ echo " Use gnutls library : $tls_message"
echo " Use POSIX capabilities library : $libcap_message"
echo " Use GeoIP library : $geoip_message"
echo " Use nl library : $libnl_message"
echo " Use SBC codec library : $have_sbc"

View File

@ -69,8 +69,7 @@
#include <codecs/codecs.h>
#include "../globals.h"
#include "../codecs/G711a/G711adecode.h"
#include "../codecs/G711u/G711udecode.h"
#include "ui/simple_dialog.h"
#include "ui/gtk/gui_utils.h"
#include "ui/gtk/dlg_utils.h"
@ -84,14 +83,6 @@
#include "ui/gtk/old-gtk-compat.h"
#include "ui/gtk/gui_utils.h"
/*define this symbol to compile with G729 and G723 codecs*/
/*#define HAVE_G729_G723 1*/
#ifdef HAVE_G729_G723
#include "codecs/G729/G729decode.h"
#include "codecs/G723/G723decode.h"
#endif /* HAVE_G729_G723 */
static gboolean initialized = FALSE;
static voip_calls_tapinfo_t *voip_calls = NULL;
@ -107,7 +98,9 @@ static GtkWidget *rtp_player_dlg_w;
static GtkWidget *channels_vb;
static GtkWidget *main_scrolled_window = NULL;
static GtkWidget *jitter_spinner;
static GtkWidget *cb_use_jitter_buffer;
static GtkWidget *cb_use_rtp_timestamp;
static GtkWidget *cb_use_uninterrupted_mode;
static GtkWidget *cb_view_as_time_of_day;
static GtkWidget *bt_decode;
static GtkWidget *bt_play;
@ -127,6 +120,7 @@ static int new_jitter_buff;
static GHashTable *rtp_channels_hash = NULL;
static int sample_rate = 8000;
static int channels = 1;
/* Port Audio stuff */
static int output_channels = 2;
@ -248,6 +242,10 @@ typedef struct _rtp_decoder_t {
} rtp_decoder_t;
typedef struct _data_info {
int current_channel;
} data_info;
/****************************************************************************/
static void
rtp_key_destroy(gpointer key)
@ -319,11 +317,15 @@ bt_state(gboolean decode, gboolean play_state, gboolean pause_state, gboolean st
gboolean false_val = FALSE;
gtk_widget_set_sensitive(bt_decode, decode);
gtk_widget_set_sensitive(cb_use_jitter_buffer, decode);
gtk_widget_set_sensitive(cb_use_rtp_timestamp, decode);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp))) {
gtk_widget_set_sensitive(jitter_spinner, FALSE);
} else {
gtk_widget_set_sensitive(cb_use_uninterrupted_mode, decode);
gtk_widget_set_sensitive(cb_view_as_time_of_day, decode);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_use_jitter_buffer))) {
gtk_widget_set_sensitive(jitter_spinner, decode);
} else {
gtk_widget_set_sensitive(jitter_spinner, FALSE);
}
if (new_jitter_buff != (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner)) {
@ -499,7 +501,13 @@ decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash
decoder = g_new(rtp_decoder_t,1);
decoder->handle = NULL;
decoder->context = NULL;
p = try_val_to_str_ext(payload_type, &rtp_payload_type_short_vals_ext);
if (rp->info->info_payload_type_str && find_codec(rp->info->info_payload_type_str)) {
p = rp->info->info_payload_type_str;
} else {
p = try_val_to_str_ext(payload_type, &rtp_payload_type_short_vals_ext);
}
if (p) {
decoder->handle = find_codec(p);
if (decoder->handle)
@ -512,57 +520,15 @@ decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash
tmp_buff = (SAMPLE *)g_malloc(tmp_buff_len);
decoded_bytes = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, tmp_buff, &tmp_buff_len);
*out_buff = tmp_buff;
channels = codec_get_channels(decoder->handle, decoder->context);
sample_rate = codec_get_frequency(decoder->handle, decoder->context);
return decoded_bytes;
}
/* Try to decode with built-in codec */
switch (payload_type) {
case PT_PCMU: /* G.711 u-law */
tmp_buff = (SAMPLE *)g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
decodeG711u(rp->payload_data, rp->info->info_payload_len,
tmp_buff, &decoded_bytes);
break;
case PT_PCMA: /* G.711 A-law */
tmp_buff = (SAMPLE *)g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
decodeG711a(rp->payload_data, rp->info->info_payload_len,
tmp_buff, &decoded_bytes);
break;
#ifdef HAVE_G729_G723
case PT_G729: /* G.729 */
/* G729 8kbps => 64kbps/8kbps = 8 */
/* Compensate for possible 2 octet SID frame (G.729B) */
tmp_buff = g_malloc(sizeof(SAMPLE) * ((rp->info->info_payload_len + 8) / 10) * 80);
decodeG729(rp->payload_data, rp->info->info_payload_len,
tmp_buff, &decoded_bytes);
break;
case PT_G723: /* G.723 */
if (rp->info->info_payload_len%24 == 0) /* G723 High 6.4kbps */
tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 10); /* G723 High 64kbps/6.4kbps = 10 */
else if (rp->info->info_payload_len%20 == 0) /* G723 Low 5.3kbps */
tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 13); /* G723 High 64kbps/5.3kbps = 13 */
else {
return 0;
}
decodeG723(rp->payload_data, rp->info->info_payload_len,
tmp_buff, &decoded_bytes);
break;
#endif /* HAVE_G729_G723 */
default:
/*
* XXX - return an error here, so the user gets told that
* we don't support this codec!
*/
break;
}
*out_buff = tmp_buff;
return decoded_bytes;
*out_buff = NULL;
return 0;
}
/****************************************************************************/
@ -582,7 +548,7 @@ update_progress_bar(gfloat fraction)
/* Decode the RTP streams and add them to the RTP channels struct
*/
static void
decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr)
{
GString *key_str = NULL;
rtp_channel_info_t *rci;
@ -620,6 +586,7 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
guint32 progbar_nextstep;
int progbar_quantum;
gfloat progbar_val;
data_info *info = (data_info *) ptr;
silence.val = 0;
silence.status = S_NORMAL;
@ -636,9 +603,9 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
* uses: src_ip:src_port dst_ip:dst_port call_num
*/
key_str = g_string_new("");
g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(rsi->src_addr)),
g_string_printf(key_str, "%s:%d %s:%d %d %u", get_addr_name(&(rsi->src_addr)),
rsi->src_port, get_addr_name(&(rsi->dest_addr)),
rsi->dest_port, rsi->call_num );
rsi->dest_port, rsi->call_num, info->current_channel);
/* create the rtp_channels_hash table if it doesn't exist */
if (!rtp_channels_hash) {
@ -729,7 +696,9 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
rp = (rtp_packet_t *)rtp_packets_list->data;
if (first == TRUE) {
start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
/* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
/* XXX: if timestamps (RTP) are missing/ignored try use packet arrive time only (see also "rtp_time") */
start_timestamp = rp->info->info_timestamp;
start_rtp_time = 0;
rtp_time_prev = start_rtp_time;
first = FALSE;
@ -767,7 +736,7 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
fflush(stdout);
#endif
/* if the jitter buffer was exceeded */
if ( diff*1000 > jitter_buff ) {
if ( diff*1000 > jitter_buff && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_use_uninterrupted_mode))) {
#ifdef DEBUG
printf("Packet drop by jitter buffer exceeded\n");
#endif
@ -779,8 +748,7 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
#ifdef DEBUG
printf("Resync...\n");
#endif
silence_frames = (gint32)((arrive_time - arrive_time_prev)*sample_rate - decoded_bytes_prev/2);
silence_frames = (gint32)((arrive_time - arrive_time_prev)*sample_rate - decoded_bytes_prev / sizeof(SAMPLE));
/* Fix for bug 4119/5902: don't insert too many silence frames.
* XXX - is there a better thing to do here?
*/
@ -797,14 +765,22 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
}
decoded_bytes_prev = 0;
start_timestamp = rp->info->info_timestamp; /* defined start_timestamp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
/* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
/* XXX: if timestamps (RTP) are missing/ignored try use packet arrive time only (see also "rtp_time") */
start_timestamp = rp->info->info_timestamp;
start_rtp_time = 0;
start_time = (double)rp->arrive_offset/1000;
rtp_time_prev = 0;
}
} else {
/* Add silence if it is necessary */
silence_frames = (gint32)((rtp_time - rtp_time_prev)*sample_rate - decoded_bytes_prev/2);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_use_uninterrupted_mode))) {
silence_frames = 0;
} else {
silence_frames = (gint32)((rtp_time - rtp_time_prev)*sample_rate - decoded_bytes_prev / sizeof(SAMPLE));
}
if (silence_frames != 0) {
rci->wrong_timestamp++;
status = S_WRONG_TIMESTAMP;
@ -824,20 +800,19 @@ decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
status = S_NORMAL;
}
if (silence_frames > 0) {
silence_frames = 0;
}
/* Add the audio */
for (i = - silence_frames; i< (decoded_bytes/2); i++) {
for (i = -silence_frames + ((info->current_channel) ? 1 : 0); i < decoded_bytes / (int) sizeof(SAMPLE); i += channels) {
sample.val = out_buff[i];
sample.status = status;
g_array_append_val(rci->samples, sample);
status = S_NORMAL;
}
rtp_time_prev = rtp_time;
pack_period = (double)(decoded_bytes/2)/sample_rate;
pack_period = (double) decoded_bytes / sizeof(SAMPLE) / sample_rate;
decoded_bytes_prev = decoded_bytes;
arrive_time_prev = arrive_time;
}
@ -1876,13 +1851,13 @@ play_channels(void)
&pa_stream,
paNoDevice, /* default input device */
0, /* no input */
PA_SAMPLE_TYPE, /* 16 bit Integer input */
PA_SAMPLE_TYPE,
NULL,
Pa_GetDefaultOutputDeviceID(),
output_channels, /* Stereo output */
PA_SAMPLE_TYPE, /* 16 bit Integer output */
output_channels,
PA_SAMPLE_TYPE,
NULL,
sample_rate, /* 8 kHz */
sample_rate,
FRAMES_PER_BUFFER,
0, /* number of buffers, if zero then use default minimum */
paClipOff, /* we won't output out of range samples so don't bother clipping them */
@ -1922,9 +1897,9 @@ play_channels(void)
err = Pa_OpenDefaultStream(
&pa_stream,
0,
output_channels, /* Stereo output */
PA_SAMPLE_TYPE, /* 16 bit Integer output */
sample_rate, /* 8 kHz */
output_channels,
PA_SAMPLE_TYPE,
sample_rate,
FRAMES_PER_BUFFER,
paCallback,
rtp_channels );
@ -1954,8 +1929,8 @@ play_channels(void)
{
PaStreamParameters stream_parameters;
stream_parameters.device = host_api_info->defaultOutputDevice;
stream_parameters.channelCount = output_channels; /* Stereo output */
stream_parameters.sampleFormat = PA_SAMPLE_TYPE; /* 16 bit Integer output */
stream_parameters.channelCount = channels;
stream_parameters.sampleFormat = PA_SAMPLE_TYPE;
stream_parameters.suggestedLatency = 0;
stream_parameters.hostApiSpecificStreamInfo = NULL;
#ifdef DEBUG
@ -1965,7 +1940,7 @@ play_channels(void)
&pa_stream,
NULL, /* no input */
&stream_parameters,
sample_rate, /* 8 kHz */
sample_rate,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
paCallback,
@ -2160,6 +2135,7 @@ decode_streams(void)
{
guint statusbar_context;
guint counter;
data_info info;
/* set the sensitive state of the buttons (decode, play, pause, stop) */
bt_state(FALSE, FALSE, FALSE, FALSE);
@ -2191,7 +2167,12 @@ decode_streams(void)
}
/* Decode the RTP streams and add them to the RTP channels to be played */
g_list_foreach( rtp_streams_list, (GFunc)decode_rtp_stream, NULL);
info.current_channel = 0;
g_list_foreach(rtp_streams_list, (GFunc) decode_rtp_stream, &info);
if (channels > 1) {
info.current_channel = 1;
g_list_foreach(rtp_streams_list, (GFunc) decode_rtp_stream, &info);
}
/* reset the number of frames to be displayed, this is used for the progress bar */
total_frames = 0;
@ -2246,7 +2227,7 @@ on_cb_view_as_time_of_day_clicked(GtkButton *button _U_, gpointer user_data _U_)
/****************************************************************************/
static void
on_cb_use_rtp_clicked(GtkToggleButton *button _U_, gpointer user_data _U_)
on_cb_use_method_group_clicked(GtkToggleButton *button _U_, gpointer user_data _U_)
{
/* set the sensitive state of the buttons (decode, play, pause, stop) */
bt_state(TRUE, FALSE, FALSE, FALSE);
@ -2337,7 +2318,7 @@ rtp_player_dlg_create(void)
gchar *win_name;
title_name_ptr = cf_get_display_name(&cfile);
win_name = g_strdup_printf("%s - VoIP - RTP Player", title_name_ptr);
win_name = g_strdup_printf("%s - RTP Player", title_name_ptr);
g_free(title_name_ptr);
rtp_player_dlg_w = dlg_window_new(win_name); /* transient_for top_level */
@ -2385,11 +2366,20 @@ rtp_player_dlg_create(void)
gtk_widget_set_tooltip_text (jitter_spinner, "The simulated jitter buffer in [ms]");
g_signal_connect(G_OBJECT (jitter_spinner_adj), "value_changed", G_CALLBACK(jitter_spinner_value_changed), NULL);
cb_use_rtp_timestamp = gtk_check_button_new_with_label("Use RTP timestamp");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp), FALSE);
cb_use_jitter_buffer = gtk_radio_button_new_with_label(NULL, "Jitter buffer");
gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), cb_use_jitter_buffer, FALSE, FALSE, 10);
g_signal_connect(cb_use_jitter_buffer, "toggled", G_CALLBACK(on_cb_use_method_group_clicked), NULL);
gtk_widget_set_tooltip_text(cb_use_jitter_buffer, "Use jitter buffer to heard RTP stream as end user");
cb_use_rtp_timestamp = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(cb_use_jitter_buffer)), "Use RTP timestamp");
gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), cb_use_rtp_timestamp, FALSE, FALSE, 10);
g_signal_connect(cb_use_rtp_timestamp, "toggled", G_CALLBACK(on_cb_use_rtp_clicked), NULL);
gtk_widget_set_tooltip_text (cb_use_rtp_timestamp, "Use RTP Timestamp instead of the arriving packet time. This will not reproduce the RTP stream as the user heard it, but is useful when the RTP is being tunneled and the original packet timing is missing");
g_signal_connect(cb_use_rtp_timestamp, "toggled", G_CALLBACK(on_cb_use_method_group_clicked), NULL);
gtk_widget_set_tooltip_text(cb_use_rtp_timestamp, "Use RTP Timestamp instead of the arriving packet time. This will not reproduce the RTP stream as the user heard it, but is useful when the RTP is being tunneled and the original packet timing is missing");
cb_use_uninterrupted_mode = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(cb_use_jitter_buffer)), "Uninterrupted mode");
gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), cb_use_uninterrupted_mode, FALSE, FALSE, 10);
g_signal_connect(cb_use_uninterrupted_mode, "toggled", G_CALLBACK(on_cb_use_method_group_clicked), NULL);
gtk_widget_set_tooltip_text(cb_use_uninterrupted_mode, "Ignore RTP Timestamp. Play stream as it is completed. It is useful when the RTP timestamp is missing.");
/* button row */
hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
@ -2478,12 +2468,6 @@ rtp_player_init(voip_calls_tapinfo_t *voip_calls_tap)
new_jitter_buff = -1;
#ifdef HAVE_G729_G723
/* Initialize the G729 and G723 decoders */
initG723();
initG729();
#endif /* HAVE_G729_G723 */
if (!rtp_channels) {
rtp_channels = g_new(rtp_play_channels_t,1);
}