summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorDavid Vossel <dvossel@digium.com>2011-04-21 18:11:40 +0000
committerDavid Vossel <dvossel@digium.com>2011-04-21 18:11:40 +0000
commit7f23115ad2faeee58865afbec6bc11a43210fde7 (patch)
tree3be8de1bbbce5eb12a63028caa39167d69b54e96 /main
parentb8f253161b0bc60953fdd5a82b495dd0ddbf61a3 (diff)
New HD ConfBridge conferencing application.
Includes a new highly optimized and customizable ConfBridge application capable of mixing audio at sample rates ranging from 8khz-192khz. Review: https://reviewboard.asterisk.org/r/1147/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314598 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/bridging.c231
-rw-r--r--main/channel.c23
-rw-r--r--main/dsp.c130
3 files changed, 262 insertions, 122 deletions
diff --git a/main/bridging.c b/main/bridging.c
index f988d9694..444eea8d5 100644
--- a/main/bridging.c
+++ b/main/bridging.c
@@ -123,9 +123,9 @@ void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast
/* Only poke the channel's thread if it is not us */
if (!pthread_equal(pthread_self(), bridge_channel->thread)) {
pthread_kill(bridge_channel->thread, SIGURG);
- ast_mutex_lock(&bridge_channel->lock);
+ ao2_lock(bridge_channel);
ast_cond_signal(&bridge_channel->cond);
- ast_mutex_unlock(&bridge_channel->lock);
+ ao2_unlock(bridge_channel);
}
return;
@@ -273,6 +273,15 @@ static int bridge_drop_control_frame(int subclass)
}
}
+void ast_bridge_notify_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, int started_talking)
+{
+ if (started_talking) {
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_START_TALKING);
+ } else {
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_STOP_TALKING);
+ }
+}
+
void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd)
{
/* If no bridge channel has been provided and the actual channel has been provided find it */
@@ -290,14 +299,21 @@ void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
} else if (frame->frametype == AST_FRAME_CONTROL && bridge_drop_control_frame(frame->subclass.integer)) {
ast_debug(1, "Dropping control frame from bridge channel %p\n", bridge_channel);
- } else {
+ } else if (frame->frametype == AST_FRAME_DTMF_BEGIN || frame->frametype == AST_FRAME_DTMF_END) {
+ int dtmf_passthrough = bridge_channel->features ?
+ bridge_channel->features->dtmf_passthrough :
+ bridge->features.dtmf_passthrough;
+
if (frame->frametype == AST_FRAME_DTMF_BEGIN) {
frame = bridge_handle_dtmf(bridge, bridge_channel, frame);
}
- /* Simply write the frame out to the bridge technology if it still exists */
- if (frame) {
+
+ if (frame && dtmf_passthrough) {
bridge->technology->write(bridge, bridge_channel, frame);
}
+ } else {
+ /* Simply write the frame out to the bridge technology if it still exists */
+ bridge->technology->write(bridge, bridge_channel, frame);
}
if (frame) {
@@ -681,9 +697,9 @@ static int smart_bridge_operation(struct ast_bridge *bridge, struct ast_bridge_c
/* Fourth we tell them to wake up so they become aware that they above has happened */
pthread_kill(bridge_channel2->thread, SIGURG);
- ast_mutex_lock(&bridge_channel2->lock);
+ ao2_lock(bridge_channel2);
ast_cond_signal(&bridge_channel2->cond);
- ast_mutex_unlock(&bridge_channel2->lock);
+ ao2_unlock(bridge_channel2);
}
/* Now that all the channels have been moved over we need to get rid of all the information the old technology may have left around */
@@ -724,10 +740,10 @@ static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct as
ast_debug(10, "Going into a multithreaded waitfor for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
chan = ast_waitfor_nandfds(&bridge_channel->chan, 1, fds, nfds, NULL, &outfd, &ms);
} else {
- ast_mutex_lock(&bridge_channel->lock);
+ ao2_lock(bridge_channel);
ast_debug(10, "Going into a multithreaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
- ast_cond_wait(&bridge_channel->cond, &bridge_channel->lock);
- ast_mutex_unlock(&bridge_channel->lock);
+ ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
+ ao2_unlock(bridge_channel);
}
ao2_lock(bridge_channel->bridge);
@@ -743,12 +759,12 @@ static enum ast_bridge_channel_state bridge_channel_join_multithreaded(struct as
static enum ast_bridge_channel_state bridge_channel_join_singlethreaded(struct ast_bridge_channel *bridge_channel)
{
ao2_unlock(bridge_channel->bridge);
- ast_mutex_lock(&bridge_channel->lock);
+ ao2_lock(bridge_channel);
if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
ast_debug(1, "Going into a single threaded signal wait for bridge channel %p of bridge %p\n", bridge_channel, bridge_channel->bridge);
- ast_cond_wait(&bridge_channel->cond, &bridge_channel->lock);
+ ast_cond_wait(&bridge_channel->cond, ao2_object_get_lockaddr(bridge_channel));
}
- ast_mutex_unlock(&bridge_channel->lock);
+ ao2_unlock(bridge_channel);
ao2_lock(bridge_channel->bridge);
return bridge_channel->state;
@@ -782,7 +798,11 @@ static void bridge_channel_unsuspend(struct ast_bridge *bridge, struct ast_bridg
return;
}
-/*! \brief Internal function that executes a feature on a bridge channel */
+/*!
+ * \brief Internal function that executes a feature on a bridge channel
+ * \note Neither the bridge nor the bridge_channel locks should be held when entering
+ * this function.
+ */
static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
@@ -819,6 +839,7 @@ static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_
/* If this hook matches just break out now */
if (!strcmp(hook->dtmf, dtmf)) {
ast_debug(1, "DTMF feature hook %p matched DTMF string '%s' on bridge channel %p\n", hook, dtmf, bridge_channel);
+ look_for_dtmf = 0;
break;
} else if (!strncmp(hook->dtmf, dtmf, dtmf_len)) {
ast_debug(1, "DTMF feature hook %p can match DTMF string '%s', it wants '%s', on bridge channel %p\n", hook, dtmf, hook->dtmf, bridge_channel);
@@ -842,12 +863,26 @@ static void bridge_channel_feature(struct ast_bridge *bridge, struct ast_bridge_
hook->callback(bridge, bridge_channel, hook->hook_pvt);
} else {
ast_bridge_dtmf_stream(bridge, dtmf, bridge_channel->chan);
+ }
+
+ /* if the channel is still in feature state, revert it back to wait state */
+ if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
}
return;
}
+static void bridge_channel_talking(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_bridge_features *features = (bridge_channel->features ? bridge_channel->features : &bridge->features);
+
+ if (features && features->talker_cb) {
+ features->talker_cb(bridge, bridge_channel, features->talker_pvt_data);
+ }
+ ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
+}
+
/*! \brief Internal function that plays back DTMF on a bridge channel */
static void bridge_channel_dtmf_stream(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
@@ -890,7 +925,10 @@ static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_chann
if (bridge_channel->swap) {
struct ast_bridge_channel *bridge_channel2 = NULL;
- /* If we are performing a swap operation we do not need to execute the smart bridge operation as the actual number of channels involved will not have changed, we just need to tell the other channel to leave */
+ /* If we are performing a swap operation we do not need
+ * to execute the smart bridge operation as the actual number
+ * of channels involved will not have changed, we just need to
+ * tell the other channel to leave */
if ((bridge_channel2 = find_bridge_channel(bridge_channel->bridge, bridge_channel->swap))) {
ast_debug(1, "Swapping bridge channel %p out from bridge %p so bridge channel %p can slip in\n", bridge_channel2, bridge_channel->bridge, bridge_channel);
ast_bridge_change_state(bridge_channel2, AST_BRIDGE_CHANNEL_STATE_HANGUP);
@@ -931,14 +969,27 @@ static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_chann
/* Execute the threading model */
state = (bridge_channel->bridge->technology->capabilities & AST_BRIDGE_CAPABILITY_MULTITHREADED ? bridge_channel_join_multithreaded(bridge_channel) : bridge_channel_join_singlethreaded(bridge_channel));
/* Depending on the above state see what we need to do */
- if (state == AST_BRIDGE_CHANNEL_STATE_FEATURE) {
+ switch (state) {
+ case AST_BRIDGE_CHANNEL_STATE_FEATURE:
bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
+ ao2_unlock(bridge_channel->bridge);
bridge_channel_feature(bridge_channel->bridge, bridge_channel);
+ ao2_lock(bridge_channel->bridge);
bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
- } else if (state == AST_BRIDGE_CHANNEL_STATE_DTMF) {
+ break;
+ case AST_BRIDGE_CHANNEL_STATE_DTMF:
bridge_channel_suspend(bridge_channel->bridge, bridge_channel);
bridge_channel_dtmf_stream(bridge_channel->bridge, bridge_channel);
bridge_channel_unsuspend(bridge_channel->bridge, bridge_channel);
+ break;
+ case AST_BRIDGE_CHANNEL_STATE_START_TALKING:
+ case AST_BRIDGE_CHANNEL_STATE_STOP_TALKING:
+ ao2_unlock(bridge_channel->bridge);
+ bridge_channel_talking(bridge_channel->bridge, bridge_channel);
+ ao2_lock(bridge_channel->bridge);
+ break;
+ default:
+ break;
}
}
@@ -987,29 +1038,63 @@ static enum ast_bridge_channel_state bridge_channel_join(struct ast_bridge_chann
return bridge_channel->state;
}
-enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
+static void bridge_channel_destroy(void *obj)
{
- struct ast_bridge_channel bridge_channel = {
- .chan = chan,
- .swap = swap,
- .bridge = bridge,
- .features = features,
- };
- enum ast_bridge_channel_state state;
+ struct ast_bridge_channel *bridge_channel = obj;
- /* Initialize various other elements of the bridge channel structure that we can't do above */
- ast_mutex_init(&bridge_channel.lock);
- ast_cond_init(&bridge_channel.cond, NULL);
+ if (bridge_channel->bridge) {
+ ao2_ref(bridge_channel->bridge, -1);
+ bridge_channel->bridge = NULL;
+ }
+ /* Destroy elements of the bridge channel structure and the bridge channel structure itself */
+ ast_cond_destroy(&bridge_channel->cond);
+}
+
+static struct ast_bridge_channel *bridge_channel_alloc(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *bridge_channel = ao2_alloc(sizeof(struct ast_bridge_channel), bridge_channel_destroy);
+ if (!(bridge_channel)) {
+ return NULL;
+ }
+ ast_cond_init(&bridge_channel->cond, NULL);
+ if (bridge) {
+ bridge_channel->bridge = bridge;
+ ao2_ref(bridge_channel->bridge, +1);
+ }
+ return bridge_channel;
+}
- ao2_ref(bridge_channel.bridge, +1);
+enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge,
+ struct ast_channel *chan,
+ struct ast_channel *swap,
+ struct ast_bridge_features *features,
+ struct ast_bridge_tech_optimizations *tech_args)
+{
+ struct ast_bridge_channel *bridge_channel = bridge_channel_alloc(bridge);
+ enum ast_bridge_channel_state state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
- state = bridge_channel_join(&bridge_channel);
+ if (!bridge_channel) {
+ return state;
+ }
+ if (tech_args) {
+ memcpy(&bridge_channel->tech_args, tech_args, sizeof(bridge_channel->tech_args));
+ }
- ao2_ref(bridge_channel.bridge, -1);
+ /* Initialize various other elements of the bridge channel structure that we can't do above */
+ bridge_channel->chan = chan;
+ bridge_channel->swap = swap;
+ bridge_channel->features = features;
- /* Destroy some elements of the bridge channel structure above */
- ast_mutex_destroy(&bridge_channel.lock);
- ast_cond_destroy(&bridge_channel.cond);
+ state = bridge_channel_join(bridge_channel);
+
+ /* Cleanup all the data in the bridge channel after it leaves the bridge. */
+ ao2_lock(bridge_channel);
+ bridge_channel->chan = NULL;
+ bridge_channel->swap = NULL;
+ bridge_channel->features = NULL;
+ ao2_unlock(bridge_channel);
+
+ ao2_ref(bridge_channel, -1);
return state;
}
@@ -1022,49 +1107,39 @@ static void *bridge_channel_thread(void *data)
state = bridge_channel_join(bridge_channel);
- ao2_ref(bridge_channel->bridge, -1);
-
/* If no other thread is going to take the channel then hang it up, or else we would have to service it until something else came along */
if (state == AST_BRIDGE_CHANNEL_STATE_END || state == AST_BRIDGE_CHANNEL_STATE_HANGUP) {
ast_hangup(bridge_channel->chan);
}
- /* Destroy elements of the bridge channel structure and the bridge channel structure itself */
- ast_mutex_destroy(&bridge_channel->lock);
- ast_cond_destroy(&bridge_channel->cond);
- ast_free(bridge_channel);
+ /* cleanup */
+ ao2_lock(bridge_channel);
+ bridge_channel->chan = NULL;
+ bridge_channel->swap = NULL;
+ bridge_channel->features = NULL;
+ ao2_unlock(bridge_channel);
+
+ ao2_ref(bridge_channel, -1);
return NULL;
}
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
{
- struct ast_bridge_channel *bridge_channel = NULL;
-
+ struct ast_bridge_channel *bridge_channel = bridge_channel_alloc(bridge);
/* Try to allocate a structure for the bridge channel */
- if (!(bridge_channel = ast_calloc(1, sizeof(*bridge_channel)))) {
+ if (!(bridge_channel)) {
return -1;
}
/* Setup various parameters */
bridge_channel->chan = chan;
bridge_channel->swap = swap;
- bridge_channel->bridge = bridge;
bridge_channel->features = features;
- /* Initialize our mutex lock and condition */
- ast_mutex_init(&bridge_channel->lock);
- ast_cond_init(&bridge_channel->cond, NULL);
-
- /* Bump up the reference count on the bridge, it'll get decremented later */
- ao2_ref(bridge, +1);
-
/* Actually create the thread that will handle the channel */
if (ast_pthread_create(&bridge_channel->thread, NULL, bridge_channel_thread, bridge_channel)) {
- ao2_ref(bridge, -1);
- ast_cond_destroy(&bridge_channel->cond);
- ast_mutex_destroy(&bridge_channel->lock);
- ast_free(bridge_channel);
+ ao2_ref(bridge_channel, -1);
return -1;
}
@@ -1181,9 +1256,9 @@ int ast_bridge_merge(struct ast_bridge *bridge0, struct ast_bridge *bridge1)
/* Poke the bridge channel, this will cause it to wake up and execute the proper threading model for the new bridge it is in */
pthread_kill(bridge_channel->thread, SIGURG);
- ast_mutex_lock(&bridge_channel->lock);
+ ao2_lock(bridge_channel);
ast_cond_signal(&bridge_channel->cond);
- ast_mutex_unlock(&bridge_channel->lock);
+ ao2_unlock(bridge_channel);
}
ast_debug(1, "Merged channels from bridge %p into bridge %p\n", bridge1, bridge0);
@@ -1268,7 +1343,11 @@ int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
return 0;
}
-int ast_bridge_features_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_features_hook_callback callback, void *hook_pvt)
+int ast_bridge_features_hook(struct ast_bridge_features *features,
+ const char *dtmf,
+ ast_bridge_features_hook_callback callback,
+ void *hook_pvt,
+ ast_bridge_features_hook_pvt_destructor destructor)
{
struct ast_bridge_features_hook *hook = NULL;
@@ -1279,6 +1358,7 @@ int ast_bridge_features_hook(struct ast_bridge_features *features, const char *d
ast_copy_string(hook->dtmf, dtmf, sizeof(hook->dtmf));
hook->callback = callback;
+ hook->destructor = destructor;
hook->hook_pvt = hook_pvt;
/* Once done we add it onto the list. Now it will be picked up when DTMF is used */
@@ -1289,6 +1369,17 @@ int ast_bridge_features_hook(struct ast_bridge_features *features, const char *d
return 0;
}
+int ast_bridge_features_set_talk_detector(struct ast_bridge_features *features,
+ ast_bridge_talking_indicate_callback talker_cb,
+ ast_bridge_talking_indicate_destructor talker_destructor,
+ void *pvt_data)
+{
+ features->talker_cb = talker_cb;
+ features->talker_destructor_cb = talker_destructor;
+ features->talker_pvt_data = pvt_data;
+ return 0;
+}
+
int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config)
{
/* If no alternate DTMF stream was provided use the default one */
@@ -1306,7 +1397,7 @@ int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_br
}
/* The rest is basically pretty easy. We create another hook using the built in feature's callback and DTMF, easy as pie. */
- return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config);
+ return ast_bridge_features_hook(features, dtmf, builtin_features_handlers[feature], config, NULL);
}
int ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag)
@@ -1333,8 +1424,15 @@ int ast_bridge_features_cleanup(struct ast_bridge_features *features)
/* This is relatively simple, hooks are kept as a list on the features structure so we just pop them off and free them */
while ((hook = AST_LIST_REMOVE_HEAD(&features->hooks, entry))) {
+ if (hook->destructor) {
+ hook->destructor(hook->hook_pvt);
+ }
ast_free(hook);
}
+ if (features->talker_destructor_cb && features->talker_pvt_data) {
+ features->talker_destructor_cb(features->talker_pvt_data);
+ features->talker_pvt_data = NULL;
+ }
return 0;
}
@@ -1357,3 +1455,18 @@ int ast_bridge_dtmf_stream(struct ast_bridge *bridge, const char *dtmf, struct a
return 0;
}
+
+void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
+{
+ ao2_lock(bridge);
+ bridge->internal_mixing_interval = mixing_interval;
+ ao2_unlock(bridge);
+}
+
+void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
+{
+
+ ao2_lock(bridge);
+ bridge->internal_sample_rate = sample_rate;
+ ao2_unlock(bridge);
+}
diff --git a/main/channel.c b/main/channel.c
index bb815e728..09be9395d 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3011,6 +3011,15 @@ void ast_deactivate_generator(struct ast_channel *chan)
ast_channel_unlock(chan);
}
+static void generator_write_format_change(struct ast_channel *chan)
+{
+ ast_channel_lock(chan);
+ if (chan->generator && chan->generator->write_format_change) {
+ chan->generator->write_format_change(chan, chan->generatordata);
+ }
+ ast_channel_unlock(chan);
+}
+
static int generator_force(const void *data)
{
/* Called if generator doesn't have data */
@@ -5035,10 +5044,9 @@ static int set_format(struct ast_channel *chan,
ast_debug(1, "Channel driver natively set channel %s to %s format %s\n", chan->name,
direction ? "write" : "read", ast_getformatname(&best_set_fmt));
+ ast_channel_lock(chan);
ast_format_copy(format, &best_set_fmt);
ast_format_copy(rawformat, &best_set_fmt);
-
- ast_channel_lock(chan);
ast_format_cap_set(chan->nativeformats, &best_set_fmt);
ast_channel_unlock(chan);
@@ -5046,6 +5054,11 @@ static int set_format(struct ast_channel *chan,
ast_translator_free_path(*trans);
}
*trans = NULL;
+ /* If there is a generator on the channel, it needs to know about this
+ * change if it is the write format. */
+ if (direction && chan->generatordata) {
+ generator_write_format_change(chan);
+ }
return 0;
}
@@ -5110,6 +5123,12 @@ static int set_format(struct ast_channel *chan,
chan->name,
direction ? "write" : "read",
ast_getformatname(&best_set_fmt));
+
+ /* If there is a generator on the channel, it needs to know about this
+ * change if it is the write format. */
+ if (direction && chan->generatordata) {
+ generator_write_format_change(chan);
+ }
return res;
}
diff --git a/main/dsp.c b/main/dsp.c
index a83adc2a0..5d5d1a2c2 100644
--- a/main/dsp.c
+++ b/main/dsp.c
@@ -192,15 +192,7 @@ enum gsamp_thresh {
#define FAX_TONE_CED_DURATION 2600
#define FAX_TONE_CED_DB 16
-#define SAMPLE_RATE 8000
-
-/* How many samples a frame has. This constant is used when calculating
- * Goertzel block size for tone_detect. It is only important if we want to
- * remove (squelch) the tone. In this case it is important to have block
- * size not to exceed size of voice frame. Otherwise by the moment the tone
- * is detected it is too late to squelch it from previous frames.
- */
-#define SAMPLES_IN_FRAME 160
+#define DEFAULT_SAMPLE_RATE 8000
/* MF goertzel size */
#define MF_GSIZE 120
@@ -339,10 +331,10 @@ static inline float goertzel_result(goertzel_state_t *s)
return (float)r.value * (float)(1 << r.power);
}
-static inline void goertzel_init(goertzel_state_t *s, float freq, int samples)
+static inline void goertzel_init(goertzel_state_t *s, float freq, int samples, unsigned int sample_rate)
{
s->v2 = s->v3 = s->chunky = 0.0;
- s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE));
+ s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / sample_rate));
s->samples = samples;
}
@@ -394,6 +386,7 @@ struct ast_dsp {
int display_inband_dtmf_warning;
float genergy;
int mute_fragments;
+ unsigned int sample_rate;
fragment_t mute_data[5];
digit_detect_state_t digit_state;
tone_detect_state_t cng_tone_state;
@@ -410,7 +403,7 @@ static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment)
dsp->mute_data[dsp->mute_fragments++] = *fragment;
}
-static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp)
+static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp, unsigned int sample_rate)
{
int duration_samples;
float x;
@@ -419,16 +412,16 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration,
s->freq = freq;
/* Desired tone duration in samples */
- duration_samples = duration * SAMPLE_RATE / 1000;
+ duration_samples = duration * sample_rate / 1000;
/* We want to allow 10% deviation of tone duration */
duration_samples = duration_samples * 9 / 10;
/* If we want to remove tone, it is important to have block size not
to exceed frame size. Otherwise by the moment tone is detected it is too late
- to squelch it from previous frames */
- s->block_size = SAMPLES_IN_FRAME;
+ to squelch it from previous frames. Block size is 20ms at the given sample rate.*/
+ s->block_size = (20 * sample_rate) / 1000;
- periods_in_block = s->block_size * freq / SAMPLE_RATE;
+ periods_in_block = s->block_size * freq / sample_rate;
/* Make sure we will have at least 5 periods at target frequency for analisys.
This may make block larger than expected packet and will make squelching impossible
@@ -437,7 +430,7 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration,
periods_in_block = 5;
/* Now calculate final block size. It will contain integer number of periods */
- s->block_size = periods_in_block * SAMPLE_RATE / freq;
+ s->block_size = periods_in_block * sample_rate / freq;
/* tone_detect is currently only used to detect fax tones and we
do not need suqlching the fax tones */
@@ -447,7 +440,7 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration,
and thus no tone will be detected in them */
s->hits_required = (duration_samples - (s->block_size - 1)) / s->block_size;
- goertzel_init(&s->tone, freq, s->block_size);
+ goertzel_init(&s->tone, freq, s->block_size, sample_rate);
s->samples_pending = s->block_size;
s->hit_count = 0;
@@ -472,19 +465,19 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration,
static void ast_fax_detect_init(struct ast_dsp *s)
{
- ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB);
- ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB);
+ ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB, s->sample_rate);
+ ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB, s->sample_rate);
}
-static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
+static void ast_dtmf_detect_init (dtmf_detect_state_t *s, unsigned int sample_rate)
{
int i;
s->lasthit = 0;
s->current_hit = 0;
for (i = 0; i < 4; i++) {
- goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE);
- goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE);
+ goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE, sample_rate);
+ goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE, sample_rate);
s->energy = 0.0;
}
s->current_sample = 0;
@@ -495,18 +488,18 @@ static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
s->misses_to_end = DTMF_MISSES_TO_END;
}
-static void ast_mf_detect_init (mf_detect_state_t *s)
+static void ast_mf_detect_init (mf_detect_state_t *s, unsigned int sample_rate)
{
int i;
s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0;
for (i = 0; i < 6; i++) {
- goertzel_init (&s->tone_out[i], mf_tones[i], 160);
+ goertzel_init (&s->tone_out[i], mf_tones[i], 160, sample_rate);
}
s->current_sample = 0;
s->current_hit = 0;
}
-static void ast_digit_detect_init(digit_detect_state_t *s, int mf)
+static void ast_digit_detect_init(digit_detect_state_t *s, int mf, unsigned int sample_rate)
{
s->current_digits = 0;
s->detected_digits = 0;
@@ -514,9 +507,9 @@ static void ast_digit_detect_init(digit_detect_state_t *s, int mf)
s->digits[0] = '\0';
if (mf) {
- ast_mf_detect_init(&s->td.mf);
+ ast_mf_detect_init(&s->td.mf, sample_rate);
} else {
- ast_dtmf_detect_init(&s->td.dtmf);
+ ast_dtmf_detect_init(&s->td.dtmf, sample_rate);
}
}
@@ -1105,7 +1098,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf)
ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n");
return 0;
}
- if (inf->subclass.format.id != AST_FORMAT_SLINEAR) {
+ if (!ast_format_is_slinear(&inf->subclass.format)) {
ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n");
return 0;
}
@@ -1128,7 +1121,7 @@ static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int *
accum /= len;
if (accum < dsp->threshold) {
/* Silent */
- dsp->totalsilence += len / 8;
+ dsp->totalsilence += len / (dsp->sample_rate / 1000);
if (dsp->totalnoise) {
/* Move and save history */
memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicnoise[0]));
@@ -1142,7 +1135,7 @@ static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int *
res = 1;
} else {
/* Not silent */
- dsp->totalnoise += len / 8;
+ dsp->totalnoise += len / (dsp->sample_rate / 1000);
if (dsp->totalsilence) {
int silence1 = dsp->historicsilence[DSP_HISTORY - 1];
int silence2 = dsp->historicsilence[DSP_HISTORY - 2];
@@ -1321,7 +1314,7 @@ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n");
return 0;
}
- if (f->subclass.format.id != AST_FORMAT_SLINEAR) {
+ if (!ast_format_is_slinear(&f->subclass.format)) {
ast_log(LOG_WARNING, "Can only calculate silence on signed-linear frames :(\n");
return 0;
}
@@ -1339,7 +1332,7 @@ int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise)
ast_log(LOG_WARNING, "Can't calculate noise on a non-voice frame\n");
return 0;
}
- if (f->subclass.format.id != AST_FORMAT_SLINEAR) {
+ if (!ast_format_is_slinear(&f->subclass.format)) {
ast_log(LOG_WARNING, "Can only calculate noise on signed-linear frames :(\n");
return 0;
}
@@ -1370,30 +1363,31 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
odata = af->data.ptr;
len = af->datalen;
/* Make sure we have short data */
- switch (af->subclass.format.id) {
- case AST_FORMAT_SLINEAR:
+ if (ast_format_is_slinear(&af->subclass.format)) {
shortdata = af->data.ptr;
len = af->datalen / 2;
- break;
- case AST_FORMAT_ULAW:
- case AST_FORMAT_TESTLAW:
- shortdata = alloca(af->datalen * 2);
- for (x = 0;x < len; x++) {
- shortdata[x] = AST_MULAW(odata[x]);
- }
- break;
- case AST_FORMAT_ALAW:
- shortdata = alloca(af->datalen * 2);
- for (x = 0; x < len; x++) {
- shortdata[x] = AST_ALAW(odata[x]);
+ } else {
+ switch (af->subclass.format.id) {
+ case AST_FORMAT_ULAW:
+ case AST_FORMAT_TESTLAW:
+ shortdata = alloca(af->datalen * 2);
+ for (x = 0;x < len; x++) {
+ shortdata[x] = AST_MULAW(odata[x]);
+ }
+ break;
+ case AST_FORMAT_ALAW:
+ shortdata = alloca(af->datalen * 2);
+ for (x = 0; x < len; x++) {
+ shortdata[x] = AST_ALAW(odata[x]);
+ }
+ break;
+ default:
+ /*Display warning only once. Otherwise you would get hundreds of warnings every second */
+ if (dsp->display_inband_dtmf_warning)
+ ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format));
+ dsp->display_inband_dtmf_warning = 0;
+ return af;
}
- break;
- default:
- /*Display warning only once. Otherwise you would get hundreds of warnings every second */
- if (dsp->display_inband_dtmf_warning)
- ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format));
- dsp->display_inband_dtmf_warning = 0;
- return af;
}
/* Initially we do not want to mute anything */
@@ -1454,7 +1448,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp,
if (dsp->features & DSP_FEATURE_DIGIT_DETECT) {
event = AST_FRAME_DTMF_END;
event_digit = dsp->digit_state.digits[0];
- event_len = dsp->digit_state.digitlen[0] * 1000 / SAMPLE_RATE;
+ event_len = dsp->digit_state.digitlen[0] * 1000 / dsp->sample_rate;
}
memmove(&dsp->digit_state.digits[0], &dsp->digit_state.digits[1], dsp->digit_state.current_digits);
memmove(&dsp->digit_state.digitlen[0], &dsp->digit_state.digitlen[1], dsp->digit_state.current_digits * sizeof(dsp->digit_state.digitlen[0]));
@@ -1521,8 +1515,6 @@ done:
}
switch (af->subclass.format.id) {
- case AST_FORMAT_SLINEAR:
- break;
case AST_FORMAT_ULAW:
for (x = 0; x < len; x++) {
odata[x] = AST_LIN2MU((unsigned short) shortdata[x]);
@@ -1557,7 +1549,7 @@ static void ast_dsp_prog_reset(struct ast_dsp *dsp)
dsp->gsamps = 0;
for (x = 0; x < ARRAY_LEN(modes[dsp->progmode].freqs); x++) {
if (modes[dsp->progmode].freqs[x]) {
- goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size);
+ goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size, dsp->sample_rate);
max = x + 1;
}
}
@@ -1565,7 +1557,12 @@ static void ast_dsp_prog_reset(struct ast_dsp *dsp)
dsp->ringtimeout= 0;
}
-struct ast_dsp *ast_dsp_new(void)
+unsigned int ast_dsp_get_sample_rate(const struct ast_dsp *dsp)
+{
+ return dsp->sample_rate;
+}
+
+static struct ast_dsp *__ast_dsp_new(unsigned int sample_rate)
{
struct ast_dsp *dsp;
@@ -1575,8 +1572,9 @@ struct ast_dsp *ast_dsp_new(void)
dsp->busycount = DSP_HISTORY;
dsp->digitmode = DSP_DIGITMODE_DTMF;
dsp->faxmode = DSP_FAXMODE_DETECT_CNG;
+ dsp->sample_rate = sample_rate;
/* Initialize digit detector */
- ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF);
+ ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF, dsp->sample_rate);
dsp->display_inband_dtmf_warning = 1;
/* Initialize initial DSP progress detect parameters */
ast_dsp_prog_reset(dsp);
@@ -1586,6 +1584,16 @@ struct ast_dsp *ast_dsp_new(void)
return dsp;
}
+struct ast_dsp *ast_dsp_new(void)
+{
+ return __ast_dsp_new(DEFAULT_SAMPLE_RATE);
+}
+
+struct ast_dsp *ast_dsp_new_with_rate(unsigned int sample_rate)
+{
+ return __ast_dsp_new(sample_rate);
+}
+
void ast_dsp_set_features(struct ast_dsp *dsp, int features)
{
dsp->features = features;
@@ -1672,7 +1680,7 @@ int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode)
new = digitmode & (DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX);
if (old != new) {
/* Must initialize structures if switching from MF to DTMF or vice-versa */
- ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF);
+ ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF, dsp->sample_rate);
}
dsp->digitmode = digitmode;
return 0;