aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/codecs/G726/G726decode.c
blob: 439e9a039cdaba4058c502ae9a840216bf7b7703 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* G726decode.c
 * G.726 codec
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "config.h"

#include <glib.h>

#include "spandsp.h"
#include "wsutil/codecs.h"
#include "ws_attributes.h"

typedef struct _g726_codec_ctx {
    g726_state_t *state;
    int bit_rate;
} g726_codec_ctx;

static void *
codec_g726_init(int bit_rate, int packing)
{
    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 state;
}

static void *codec_g726_16_init(void) { return codec_g726_init(16000, G726_PACKING_RIGHT); }
static void *codec_g726_24_init(void) { return codec_g726_init(24000, G726_PACKING_RIGHT); }
static void *codec_g726_32_init(void) { return codec_g726_init(32000, G726_PACKING_RIGHT); }
static void *codec_g726_40_init(void) { return codec_g726_init(40000, G726_PACKING_RIGHT); }
static void *codec_aal2_g726_16_init(void) { return codec_g726_init(16000, G726_PACKING_LEFT); }
static void *codec_aal2_g726_24_init(void) { return codec_g726_init(24000, G726_PACKING_LEFT); }
static void *codec_aal2_g726_32_init(void) { return codec_g726_init(32000, G726_PACKING_LEFT); }
static void *codec_aal2_g726_40_init(void) { return codec_g726_init(40000, G726_PACKING_LEFT); }

static void
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);
}

static unsigned
codec_g726_get_channels(void *ctx _U_)
{
    return 1;
}

static unsigned
codec_g726_get_frequency(void *ctx _U_)
{
    return 8000;
}

static size_t
codec_g726_decode(void *ctx, const void *input, size_t inputSizeBytes, void *output,
        size_t *outputSizeBytes)
{
    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;
}

void
codec_register_g726(void)
{
    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);
}

/*
 * Editor modelines  -  https://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:
 */