~binli/ubuntu/vivid/pulseaudio/load-extcon-module

« back to all changes in this revision

Viewing changes to src/modules/echo-cancel/speex.c

  • Committer: Bin Li
  • Date: 2016-01-23 15:04:48 UTC
  • Revision ID: bin.li@canonical.com-20160123150448-5ockvw4p5xxntda4
init the 1:6.0-0ubuntu9.15 from silo 12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***
 
2
    This file is part of PulseAudio.
 
3
 
 
4
    Copyright 2010 Wim Taymans <wim.taymans@gmail.com>
 
5
 
 
6
    Contributor: Arun Raghavan <arun.raghavan@collabora.co.uk>
 
7
 
 
8
    PulseAudio is free software; you can redistribute it and/or modify
 
9
    it under the terms of the GNU Lesser General Public License as published
 
10
    by the Free Software Foundation; either version 2.1 of the License,
 
11
    or (at your option) any later version.
 
12
 
 
13
    PulseAudio is distributed in the hope that it will be useful, but
 
14
    WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
16
    General Public License for more details.
 
17
 
 
18
    You should have received a copy of the GNU Lesser General Public License
 
19
    along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
 
20
***/
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include <config.h>
 
24
#endif
 
25
 
 
26
#include <pulsecore/core-util.h>
 
27
#include <pulsecore/modargs.h>
 
28
#include "echo-cancel.h"
 
29
 
 
30
/* should be between 10-20 ms */
 
31
#define DEFAULT_FRAME_SIZE_MS 20
 
32
/* should be between 100-500 ms */
 
33
#define DEFAULT_FILTER_SIZE_MS 200
 
34
#define DEFAULT_AGC_ENABLED true
 
35
#define DEFAULT_DENOISE_ENABLED true
 
36
#define DEFAULT_ECHO_SUPPRESS_ENABLED true
 
37
#define DEFAULT_ECHO_SUPPRESS_ATTENUATION 0
 
38
 
 
39
static const char* const valid_modargs[] = {
 
40
    "frame_size_ms",
 
41
    "filter_size_ms",
 
42
    "agc",
 
43
    "denoise",
 
44
    "echo_suppress",
 
45
    "echo_suppress_attenuation",
 
46
    "echo_suppress_attenuation_active",
 
47
    NULL
 
48
};
 
49
 
 
50
static void pa_speex_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
 
51
                                    pa_sample_spec *play_ss, pa_channel_map *play_map,
 
52
                                    pa_sample_spec *out_ss, pa_channel_map *out_map) {
 
53
    out_ss->format = PA_SAMPLE_S16NE;
 
54
 
 
55
    *play_ss = *out_ss;
 
56
    *play_map = *out_map;
 
57
    *rec_ss = *out_ss;
 
58
    *rec_map = *out_map;
 
59
}
 
60
 
 
61
static bool pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_spec *out_ss, uint32_t nframes, pa_modargs *ma) {
 
62
    bool agc;
 
63
    bool denoise;
 
64
    bool echo_suppress;
 
65
    int32_t echo_suppress_attenuation;
 
66
    int32_t echo_suppress_attenuation_active;
 
67
 
 
68
    agc = DEFAULT_AGC_ENABLED;
 
69
    if (pa_modargs_get_value_boolean(ma, "agc", &agc) < 0) {
 
70
        pa_log("Failed to parse agc value");
 
71
        goto fail;
 
72
    }
 
73
 
 
74
    denoise = DEFAULT_DENOISE_ENABLED;
 
75
    if (pa_modargs_get_value_boolean(ma, "denoise", &denoise) < 0) {
 
76
        pa_log("Failed to parse denoise value");
 
77
        goto fail;
 
78
    }
 
79
 
 
80
    echo_suppress = DEFAULT_ECHO_SUPPRESS_ENABLED;
 
81
    if (pa_modargs_get_value_boolean(ma, "echo_suppress", &echo_suppress) < 0) {
 
82
        pa_log("Failed to parse echo_suppress value");
 
83
        goto fail;
 
84
    }
 
85
 
 
86
    echo_suppress_attenuation = DEFAULT_ECHO_SUPPRESS_ATTENUATION;
 
87
    if (pa_modargs_get_value_s32(ma, "echo_suppress_attenuation", &echo_suppress_attenuation) < 0) {
 
88
        pa_log("Failed to parse echo_suppress_attenuation value");
 
89
        goto fail;
 
90
    }
 
91
    if (echo_suppress_attenuation > 0) {
 
92
        pa_log("echo_suppress_attenuation should be a negative dB value");
 
93
        goto fail;
 
94
    }
 
95
 
 
96
    echo_suppress_attenuation_active = DEFAULT_ECHO_SUPPRESS_ATTENUATION;
 
97
    if (pa_modargs_get_value_s32(ma, "echo_suppress_attenuation_active", &echo_suppress_attenuation_active) < 0) {
 
98
        pa_log("Failed to parse echo_suppress_attenuation_active value");
 
99
        goto fail;
 
100
    }
 
101
    if (echo_suppress_attenuation_active > 0) {
 
102
        pa_log("echo_suppress_attenuation_active should be a negative dB value");
 
103
        goto fail;
 
104
    }
 
105
 
 
106
    if (agc || denoise || echo_suppress) {
 
107
        spx_int32_t tmp;
 
108
 
 
109
        if (out_ss->channels != 1) {
 
110
            pa_log("AGC, denoising and echo suppression only work with channels=1");
 
111
            goto fail;
 
112
        }
 
113
 
 
114
        ec->params.priv.speex.pp_state = speex_preprocess_state_init(nframes, out_ss->rate);
 
115
 
 
116
        tmp = agc;
 
117
        speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_AGC, &tmp);
 
118
 
 
119
        tmp = denoise;
 
120
        speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
 
121
 
 
122
        if (echo_suppress) {
 
123
            if (echo_suppress_attenuation)
 
124
                speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS,
 
125
                                     &echo_suppress_attenuation);
 
126
 
 
127
            if (echo_suppress_attenuation_active) {
 
128
                speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE,
 
129
                                     &echo_suppress_attenuation_active);
 
130
            }
 
131
 
 
132
            speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_STATE,
 
133
                                 ec->params.priv.speex.state);
 
134
        }
 
135
 
 
136
        pa_log_info("Loaded speex preprocessor with params: agc=%s, denoise=%s, echo_suppress=%s", pa_yes_no(agc),
 
137
                    pa_yes_no(denoise), pa_yes_no(echo_suppress));
 
138
    } else
 
139
        pa_log_info("All preprocessing options are disabled");
 
140
 
 
141
    return true;
 
142
 
 
143
fail:
 
144
    return false;
 
145
}
 
146
 
 
147
bool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
 
148
                      pa_sample_spec *rec_ss, pa_channel_map *rec_map,
 
149
                      pa_sample_spec *play_ss, pa_channel_map *play_map,
 
150
                      pa_sample_spec *out_ss, pa_channel_map *out_map,
 
151
                      uint32_t *nframes, const char *args) {
 
152
    int rate;
 
153
    uint32_t frame_size_ms, filter_size_ms;
 
154
    pa_modargs *ma;
 
155
 
 
156
    if (!(ma = pa_modargs_new(args, valid_modargs))) {
 
157
        pa_log("Failed to parse submodule arguments.");
 
158
        goto fail;
 
159
    }
 
160
 
 
161
    filter_size_ms = DEFAULT_FILTER_SIZE_MS;
 
162
    if (pa_modargs_get_value_u32(ma, "filter_size_ms", &filter_size_ms) < 0 || filter_size_ms < 1 || filter_size_ms > 2000) {
 
163
        pa_log("Invalid filter_size_ms specification");
 
164
        goto fail;
 
165
    }
 
166
 
 
167
    frame_size_ms = DEFAULT_FRAME_SIZE_MS;
 
168
    if (pa_modargs_get_value_u32(ma, "frame_size_ms", &frame_size_ms) < 0 || frame_size_ms < 1 || frame_size_ms > 200) {
 
169
        pa_log("Invalid frame_size_ms specification");
 
170
        goto fail;
 
171
    }
 
172
 
 
173
    pa_speex_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
 
174
 
 
175
    rate = out_ss->rate;
 
176
    *nframes = pa_echo_canceller_blocksize_power2(rate, frame_size_ms);
 
177
 
 
178
    pa_log_debug ("Using nframes %d, channels %d, rate %d", *nframes, out_ss->channels, out_ss->rate);
 
179
    ec->params.priv.speex.state = speex_echo_state_init_mc(*nframes, (rate * filter_size_ms) / 1000, out_ss->channels, out_ss->channels);
 
180
 
 
181
    if (!ec->params.priv.speex.state)
 
182
        goto fail;
 
183
 
 
184
    speex_echo_ctl(ec->params.priv.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);
 
185
 
 
186
    if (!pa_speex_ec_preprocessor_init(ec, out_ss, *nframes, ma))
 
187
        goto fail;
 
188
 
 
189
    pa_modargs_free(ma);
 
190
    return true;
 
191
 
 
192
fail:
 
193
    if (ma)
 
194
        pa_modargs_free(ma);
 
195
    if (ec->params.priv.speex.pp_state) {
 
196
        speex_preprocess_state_destroy(ec->params.priv.speex.pp_state);
 
197
        ec->params.priv.speex.pp_state = NULL;
 
198
    }
 
199
    if (ec->params.priv.speex.state) {
 
200
        speex_echo_state_destroy(ec->params.priv.speex.state);
 
201
        ec->params.priv.speex.state = NULL;
 
202
    }
 
203
    return false;
 
204
}
 
205
 
 
206
void pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
 
207
    speex_echo_cancellation(ec->params.priv.speex.state, (const spx_int16_t *) rec, (const spx_int16_t *) play,
 
208
                            (spx_int16_t *) out);
 
209
 
 
210
    /* preprecessor is run after AEC. This is not a mistake! */
 
211
    if (ec->params.priv.speex.pp_state)
 
212
        speex_preprocess_run(ec->params.priv.speex.pp_state, (spx_int16_t *) out);
 
213
}
 
214
 
 
215
void pa_speex_ec_done(pa_echo_canceller *ec) {
 
216
    if (ec->params.priv.speex.pp_state) {
 
217
        speex_preprocess_state_destroy(ec->params.priv.speex.pp_state);
 
218
        ec->params.priv.speex.pp_state = NULL;
 
219
    }
 
220
 
 
221
    if (ec->params.priv.speex.state) {
 
222
        speex_echo_state_destroy(ec->params.priv.speex.state);
 
223
        ec->params.priv.speex.state = NULL;
 
224
    }
 
225
}