diff --git a/apps/app_rpt.c b/apps/app_rpt.c
index 26b2036b8..3a9919c7e 100644
--- a/apps/app_rpt.c
+++ b/apps/app_rpt.c
@@ -260,7 +260,6 @@
tonezone
res_curl
curl
- dahdi
extended
***/
@@ -289,6 +288,8 @@
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
+#include "asterisk/bridge.h"
+#include "asterisk/bridge_channel.h"
#include "asterisk/channel.h"
#include "asterisk/callerid.h"
#include "asterisk/pbx.h"
@@ -305,6 +306,7 @@
#include "asterisk/format.h"
#include "asterisk/dsp.h"
#include "asterisk/audiohook.h"
+#include "asterisk/core_unreal.h"
#include "app_rpt/app_rpt.h"
@@ -1060,6 +1062,7 @@ static void *perform_statpost(void *data)
struct ast_str *response_msg;
struct statpost *sp = (struct statpost *) data;
struct rpt *myrpt = sp->myrpt;
+ char *url = ast_str_buffer(sp->stats_url);
if (!curl) {
ast_free(sp->stats_url);
@@ -1067,7 +1070,7 @@ static void *perform_statpost(void *data)
return NULL;
}
- response_msg = ast_str_create(50);
+ response_msg = ast_str_create(RPT_AST_STR_INIT_SIZE);
if (!response_msg) {
ast_free(sp->stats_url);
ast_free(sp);
@@ -1075,9 +1078,9 @@ static void *perform_statpost(void *data)
return NULL;
}
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunction);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &response_msg);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_msg);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- curl_easy_setopt(curl, CURLOPT_URL, sp->stats_url);
+ curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
@@ -1086,12 +1089,12 @@ static void *perform_statpost(void *data)
if (*error_buffer) { /* Anything in the error buffer? */
failed = 1;
if (!myrpt->last_statpost_failed) {
- ast_log(LOG_WARNING, "statpost to URL '%s' failed with error: %s\n", sp->stats_url, error_buffer);
+ ast_log(LOG_WARNING, "statpost to URL '%s' failed with error: %s\n", url, error_buffer);
}
} else {
failed = 1;
if (!myrpt->last_statpost_failed) {
- ast_log(LOG_WARNING, "statpost to URL '%s' failed with error: %s\n", sp->stats_url, curl_easy_strerror(res));
+ ast_log(LOG_WARNING, "statpost to URL '%s' failed with error: %s\n", url, curl_easy_strerror(res));
}
}
} else {
@@ -1099,13 +1102,13 @@ static void *perform_statpost(void *data)
if (!is_http_success(rescode)) {
failed = 1;
if (!myrpt->last_statpost_failed) {
- ast_log(LOG_WARNING, "statpost to URL '%s' failed with code %ld: %s\n", sp->stats_url, rescode, http_status_text(rescode));
+ ast_log(LOG_WARNING, "statpost to URL '%s' failed with code %ld: %s\n", url, rescode, http_status_text(rescode));
}
}
}
myrpt->last_statpost_failed = ((failed) ? 1 : 0);
- ast_debug(3, "Response: %s\n", ast_str_buffer(response_msg));
+ ast_debug(5, "Response: %s\n", ast_str_buffer(response_msg));
ast_free(sp->stats_url); /* Free here since parent is not responsible for it. */
ast_free(sp);
ast_free(response_msg);
@@ -1113,11 +1116,11 @@ static void *perform_statpost(void *data)
return NULL;
}
-static void statpost(struct rpt *myrpt, char *pairs)
+static void statpost(struct rpt *myrpt, struct ast_str *pairs)
{
time_t now;
unsigned int seq;
- int res, len;
+ int res;
pthread_t statpost_thread;
struct statpost *sp;
@@ -1129,20 +1132,22 @@ static void statpost(struct rpt *myrpt, char *pairs)
return;
}
- len = strlen(pairs) + strlen(myrpt->p.statpost_url) + 200;
- sp->stats_url = ast_malloc(len);
-
+ sp->stats_url = ast_str_create(RPT_AST_STR_INIT_SIZE);
+ if (!sp->stats_url) {
+ ast_free(sp);
+ return;
+ }
ast_mutex_lock(&myrpt->statpost_lock);
seq = ++myrpt->statpost_seqno;
ast_mutex_unlock(&myrpt->statpost_lock);
time(&now);
sp->myrpt = myrpt;
- snprintf(sp->stats_url, len, "%s?node=%s&time=%u&seqno=%u%s%s", myrpt->p.statpost_url, myrpt->name, (unsigned int) now, seq,
- pairs ? "&" : "", S_OR(pairs, ""));
+ ast_str_set(&sp->stats_url, 0, "%s?node=%s&time=%u&seqno=%u%s", myrpt->p.statpost_url, myrpt->name, (unsigned int) now, seq,
+ ast_str_buffer(pairs));
/* Make the actual cURL call in a separate thread, so we can continue without blocking. */
- ast_debug(4, "Making statpost to %s\n", sp->stats_url);
+ ast_debug(4, "Making statpost to %s\n", ast_str_buffer(sp->stats_url));
res = ast_pthread_create_detached(&statpost_thread, NULL, perform_statpost, sp);
if (res) {
ast_log(LOG_ERROR, "Error creating statpost thread: %s\n", strerror(res));
@@ -1262,7 +1267,7 @@ struct rpt_autopatch {
};
/*!
- * \brief Create an autopatch specific pbx run thread with no_hangup_chan = 1 arg.
+ * \brief Create an autopatch specific pbx run thread.
* \param data Structure of rpt_autopatch
*/
static void *rpt_pbx_autopatch_run(void *data)
@@ -1270,9 +1275,8 @@ static void *rpt_pbx_autopatch_run(void *data)
struct rpt_autopatch *autopatch = data;
struct rpt *myrpt = autopatch->myrpt;
enum ast_pbx_result res;
- struct ast_pbx_args pbx_args = { .no_hangup_chan = 1 };
- res = ast_pbx_run_args(autopatch->mychannel, &pbx_args);
+ res = ast_pbx_run(autopatch->mychannel);
if (res) { /* could not start PBX */
rpt_mutex_lock(&myrpt->lock);
myrpt->callmode = CALLMODE_FAILED;
@@ -1295,6 +1299,19 @@ static void *rpt_pbx_autopatch_run(void *data)
return NULL;
}
+static int rpt_handle_talker_cb(struct ast_bridge_channel *bridge_cannel, void *hook_pvt, int talking)
+{
+ struct rpt *myrpt = hook_pvt;
+
+ if (!myrpt) {
+ return 1;
+ }
+ ast_debug(1, "Autopatch callback triggered: talking=%d\n", talking);
+ rpt_mutex_lock(&myrpt->lock);
+ myrpt->patch_talking = talking;
+ rpt_mutex_unlock(&myrpt->lock);
+ return 0;
+}
/*
*
* WARNING: YOU ARE NOW HEADED INTO ONE GIANT MAZE OF SWITCH STATEMENTS THAT DO MOST OF THE WORK FOR
@@ -1317,69 +1334,55 @@ void *rpt_call(void *this)
struct ast_channel *mychannel, *genchannel;
struct ast_format_cap *cap;
struct rpt_autopatch *patch_thread_data;
+ struct ast_bridge_channel *bridge_chan;
+ struct ast_unreal_pvt *p;
+
pthread_t threadid;
cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!cap) {
ast_log(LOG_ERROR, "Failed to alloc cap\n");
myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ return NULL;
}
ast_format_cap_append(cap, ast_format_slin, 0);
-
myrpt->mydtmf = 0;
- mychannel = rpt_request_pseudo_chan(cap);
+ mychannel = rpt_request_local_chan(cap, "Autopatch");
if (!mychannel) {
- ast_log(LOG_WARNING, "Unable to obtain pseudo channel\n");
+ ast_log(LOG_WARNING, "Unable to obtain AutoPatch local channel\n");
ao2_ref(cap, -1);
myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ return NULL;
}
ast_debug(1, "Requested channel %s\n", ast_channel_name(mychannel));
- if (rpt_conf_add_speaker(mychannel, myrpt)) {
- ast_hangup(mychannel);
- myrpt->callmode = CALLMODE_DOWN;
- ao2_ref(cap, -1);
- pthread_exit(NULL);
- }
- genchannel = rpt_request_pseudo_chan(cap);
+ genchannel = rpt_request_local_chan(cap, "GenChannel");
ao2_ref(cap, -1);
if (!genchannel) {
- ast_log(LOG_WARNING, "Unable to obtain pseudo channel\n");
+ ast_log(LOG_WARNING, "Unable to obtain Gen local channel\n");
ast_hangup(mychannel);
myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ return NULL;
}
- ast_debug(1, "Requested channel %s\n", ast_channel_name(genchannel));
-
- /* first put the channel on the conference */
- if (rpt_conf_add_speaker(genchannel, myrpt)) {
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ if (rpt_conf_add(genchannel, myrpt, RPT_CONF)) {
+ ast_log(LOG_WARNING, "Unable to place Gen local channel on conference\n");
+ goto cleanup;
}
+
+ ast_autoservice_start(genchannel);
+ ast_debug(1, "Created Gen channel '%s' and added to conference bridge '%s'\n", ast_channel_name(genchannel), RPT_CONF_NAME);
+
if (myrpt->p.tonezone && rpt_set_tone_zone(mychannel, myrpt->p.tonezone)) {
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ goto cleanup;
}
if (myrpt->p.tonezone && rpt_set_tone_zone(genchannel, myrpt->p.tonezone)) {
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ goto cleanup;
}
/* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
if (!myrpt->patchquiet && !myrpt->patchexten[0] && rpt_play_dialtone(genchannel) < 0) {
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- myrpt->callmode = CALLMODE_DOWN;
- pthread_exit(NULL);
+ goto cleanup;
}
stopped = 0;
congstarted = 0;
@@ -1433,16 +1436,11 @@ void *rpt_call(void *this)
rpt_play_congestion(genchannel);
}
}
- res = ast_safe_sleep(mychannel, MSWAIT);
- if (res < 0) {
- ast_debug(1, "ast_safe_sleep=%i\n", res);
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- rpt_mutex_lock(&myrpt->lock);
- myrpt->callmode = CALLMODE_DOWN;
- rpt_mutex_unlock(&myrpt->lock);
- pthread_exit(NULL);
- }
+
+ /* At this point, genchannel is in autoservice, and mychannel is not connected to any frame generation.
+ * safesleep is not necessary.
+ */
+ usleep(MSWAIT * 1000);
dialtimer += MSWAIT;
}
@@ -1453,16 +1451,42 @@ void *rpt_call(void *this)
if (myrpt->callmode == CALLMODE_DOWN) {
ast_debug(1, "callmode==0\n");
ast_hangup(mychannel);
+ ast_autoservice_stop(genchannel);
ast_hangup(genchannel);
rpt_mutex_lock(&myrpt->lock);
myrpt->macropatch = 0;
- channel_revert(myrpt);
rpt_mutex_unlock(&myrpt->lock);
if ((!myrpt->patchquiet) && aborted)
rpt_telemetry(myrpt, TERM, NULL);
- pthread_exit(NULL);
+ return NULL;
}
+ /* First we add mychannel to the conference */
+ if (rpt_conf_add(mychannel, myrpt, RPT_CONF)) {
+ ast_log(LOG_WARNING, "Unable to place AutoPatch local channel on conference\n");
+ goto cleanup;
+ }
+ ast_debug(1, "Autopatch channel %s placed on CONF", ast_channel_name(mychannel));
+
+ /* Next, add talker callback */
+ myrpt->patch_talking = 0; /* Initialize patch_talking flag */
+ p = ast_channel_tech_pvt(mychannel);
+ ast_debug(1, "Adding talker callback to channel %s, private data %p\n", ast_channel_name(mychannel), p);
+ if (p) {
+ bridge_chan = ast_channel_get_bridge_channel(p->chan);
+ if (bridge_chan) {
+ bridge_chan->tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD;
+ bridge_chan->tech_args.silence_threshold = VOX_OFF_DEBOUNCE_COUNT * 20; /* VOX is in 20ms count */
+ ast_bridge_talk_detector_hook(bridge_chan->features, rpt_handle_talker_cb, myrpt, NULL, AST_BRIDGE_HOOK_REMOVE_ON_PULL);
+ ast_debug(1, "Got Bridge channel %p\n", bridge_chan);
+ ao2_ref(bridge_chan, -1);
+ } else {
+ ast_log(LOG_WARNING, "Failed to get Bridge channel");
+ }
+ } else {
+ ast_log(LOG_WARNING, "Failed to get channel tech private");
+ }
+ /* Now we can set the caller id and extension for the PBX to use */
if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid) {
char *name, *loc, *instr;
instr = ast_strdup(myrpt->p.ourcallerid);
@@ -1479,34 +1503,18 @@ void *rpt_call(void *this)
ast_channel_accountcode_set(mychannel, myrpt->p.acctcode);
ast_channel_priority_set(mychannel, 1);
ast_channel_undefer_dtmf(mychannel);
- if (rpt_call_bridge_setup(myrpt, mychannel)) {
- rpt_mutex_lock(&myrpt->lock);
- myrpt->callmode = CALLMODE_DOWN;
- rpt_mutex_unlock(&myrpt->lock);
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- pthread_exit(NULL);
- }
patch_thread_data = ast_calloc(1, sizeof(struct rpt_autopatch));
if (!patch_thread_data) {
- rpt_mutex_lock(&myrpt->lock);
- myrpt->callmode = CALLMODE_DOWN;
- rpt_mutex_unlock(&myrpt->lock);
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- pthread_exit(NULL);
+ goto cleanup;
}
+ /* Finally, we can start the call */
patch_thread_data->myrpt = myrpt;
patch_thread_data->mychannel = mychannel;
res = ast_pthread_create(&threadid, NULL, rpt_pbx_autopatch_run, patch_thread_data);
if (res < 0) {
ast_log(LOG_ERROR, "Unable to start PBX!\n");
- rpt_mutex_lock(&myrpt->lock);
- myrpt->callmode = CALLMODE_DOWN;
- rpt_mutex_unlock(&myrpt->lock);
- ast_hangup(mychannel);
- ast_hangup(genchannel);
- pthread_exit(NULL);
+ ast_free(patch_thread_data);
+ goto cleanup;
}
rpt_mutex_lock(&myrpt->lock);
@@ -1563,24 +1571,26 @@ void *rpt_call(void *this)
if (!patch_thread_data->pbx_exited) {
ast_softhangup(mychannel, AST_SOFTHANGUP_DEV);
- } else {
- ast_hangup(mychannel);
}
+ ast_autoservice_stop(genchannel);
pthread_join(threadid, NULL);
ast_hangup(genchannel);
rpt_mutex_lock(&myrpt->lock);
myrpt->callmode = CALLMODE_DOWN;
myrpt->macropatch = 0;
- channel_revert(myrpt);
rpt_mutex_unlock(&myrpt->lock);
-
- /* first put the channel on the conference in announce mode */
- if (myrpt->p.duplex == 2 || myrpt->p.duplex == 4) {
- rpt_conf_add_announcer_monitor(myrpt->pchannel, myrpt);
- }
ast_free(patch_thread_data);
- pthread_exit(NULL);
+ return NULL;
+
+cleanup:
+ rpt_mutex_lock(&myrpt->lock);
+ myrpt->callmode = CALLMODE_DOWN;
+ rpt_mutex_unlock(&myrpt->lock);
+ ast_autoservice_stop(genchannel);
+ ast_hangup(mychannel);
+ ast_hangup(genchannel);
+ return NULL;
}
/*
@@ -1785,6 +1795,8 @@ static inline void handle_callmode_dialing(struct rpt *myrpt, char c)
if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
/* call has failed, inform user */
myrpt->callmode = CALLMODE_FAILED;
+ } else { /* otherwise, reset timer */
+ myrpt->calldigittimer = 1;
}
}
@@ -2444,6 +2456,7 @@ static void *attempt_reconnect(void *data)
rpt_mutex_lock(&myrpt->lock);
ao2_ref(l, +1); /* We don't want the link to free after removing from the list */
rpt_link_remove(myrpt->links, l); /* remove from queue */
+ ast_autoservice_start(l->pchan); /* We need to dump audio on l->chan while redialing or we receive long voice queue warnings */
rpt_mutex_unlock(&myrpt->lock);
parse_node_format(tmp, &s1, sx, sizeof(sx));
snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
@@ -2467,13 +2480,14 @@ static void *attempt_reconnect(void *data)
while ((f1 = AST_LIST_REMOVE_HEAD(&l->textq, frame_list)))
ast_frfree(f1);
if (l->chan) {
- rpt_make_call(l->chan, tele, 999, deststr, "(Remote Rx)", "attempt_reconnect", myrpt->name);
+ rpt_make_call(l->chan, tele, 999, deststr, "Remote Rx", "attempt_reconnect", myrpt->name);
} else {
ast_verb(3, "Unable to place call to %s/%s\n", deststr, tele);
rpt_mutex_lock(&myrpt->lock);
l->retrytimer = RETRY_TIMER_MS;
rpt_mutex_unlock(&myrpt->lock);
}
+ ast_autoservice_stop(l->pchan);
rpt_mutex_lock(&myrpt->lock);
rpt_link_add(myrpt->links, l); /* put back in queue */
ao2_ref(l, -1); /* and drop the extra ref we're holding */
@@ -2817,6 +2831,7 @@ static void _load_rpt_vars_by_rpt(struct rpt *myrpt, int force)
}
#define rpt_hangup_rx_tx(myrpt) \
+ ast_autoservice_stop(myrpt->rxchannel); \
rpt_hangup(myrpt, RPT_RXCHAN); \
if (myrpt->txchannel) { \
rpt_hangup(myrpt, RPT_TXCHAN); \
@@ -2827,104 +2842,133 @@ static void _load_rpt_vars_by_rpt(struct rpt *myrpt, int force)
static int rpt_setup_channels(struct rpt *myrpt, struct ast_format_cap *cap)
{
- int res;
+ int res = 0;
- if (rpt_request(myrpt, cap, RPT_RXCHAN)) {
+ /* make a conference for the tx */
+ if (rpt_conf_create(myrpt, RPT_TXCONF)) {
+ return -1;
+ }
+
+ res = rpt_conf_create(myrpt, RPT_CONF);
+ if (res) {
return -1;
}
+ if (IS_PSEUDO_NAME(myrpt->rxchanname)) {
+ ast_log(LOG_ERROR, "Using DAHDI/Pseudo channel %s is deprecated. Update your rpt.conf to use Local/Pseudo.\n", myrpt->rxchanname);
+ ast_free(myrpt->rxchanname);
+ myrpt->rxchanname = ast_strdup("Local/pseudo");
+ if (!myrpt->rxchanname) {
+ return -1;
+ }
+ }
+ if (rpt_request(myrpt, cap, RPT_RXCHAN)) {
+ return -1;
+ }
+ ast_autoservice_start(myrpt->rxchannel);
if (myrpt->txchanname) {
if (rpt_request(myrpt, cap, RPT_TXCHAN)) {
+ ast_autoservice_stop(myrpt->rxchannel);
rpt_hangup(myrpt, RPT_RXCHAN);
return -1;
}
} else {
myrpt->txchannel = myrpt->rxchannel;
- myrpt->dahditxchannel = IS_DAHDI_CHAN_NAME(myrpt->rxchanname) && !IS_PSEUDO_NAME(myrpt->rxchanname) ? myrpt->txchannel : NULL;
+ /* If it is a DAHDI hardware channel (Not PSEUDO), use the configured txchannel. */
+ myrpt->localtxchannel = IS_DAHDI_CHAN_NAME(myrpt->rxchanname) && !IS_PSEUDO_NAME(myrpt->rxchanname) ? myrpt->txchannel : NULL;
}
- if (rpt_request_pseudo(myrpt, cap, RPT_PCHAN)) {
+ if (rpt_request_local(myrpt, cap, RPT_PCHAN, "PChan")) {
rpt_hangup_rx_tx(myrpt);
return -1;
}
- if (!myrpt->dahditxchannel) {
- if (rpt_request_pseudo(myrpt, cap, RPT_DAHDITXCHAN)) {
+ if (IS_LOCAL_NAME(ast_channel_name(myrpt->txchannel))) {
+ /* IF we have a local channel setup in txchannel this is a hub
+ * there is no "real" hardware and there is no listener.
+ * Autoservice is required to "dump" audio frames.
+ */
+ struct ast_unreal_pvt *p = ast_channel_tech_pvt(myrpt->txchannel);
+ if (!p || !p->chan) {
+ ast_log(LOG_WARNING, "Local channel %s missing endpoints\n", ast_channel_name(myrpt->txchannel));
+ rpt_hangup_rx_tx(myrpt);
+ rpt_hangup(myrpt, RPT_PCHAN);
+ return -1;
+ }
+ ast_raw_answer(p->chan);
+ ast_autoservice_start(p->chan);
+ }
+
+ if (!myrpt->localtxchannel) {
+ if (rpt_request_local(myrpt, cap, RPT_LOCALTXCHAN, "LocalTX")) { /* Listen only link */
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
return -1;
}
}
- if (rpt_request_pseudo(myrpt, cap, RPT_MONCHAN)) {
+ if (rpt_conf_add(myrpt->localtxchannel, myrpt, RPT_TXCONF)) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
- rpt_hangup(myrpt, RPT_DAHDITXCHAN);
+ rpt_hangup(myrpt, RPT_LOCALTXCHAN);
return -1;
}
- /* make a conference for the tx */
- if (rpt_conf_create(myrpt->dahditxchannel, myrpt, RPT_TXCONF, RPT_CONF_CONF | RPT_CONF_LISTENER)) {
+ if (rpt_request_local(myrpt, cap, RPT_MONCHAN, "MonChan")) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
- rpt_hangup(myrpt, RPT_MONCHAN);
+ rpt_hangup(myrpt, RPT_LOCALTXCHAN);
return -1;
}
- if (myrpt->p.duplex == 2 || myrpt->p.duplex == 4) {
- res = rpt_conf_create(myrpt->pchannel, myrpt, RPT_CONF, RPT_CONF_CONFANNMON);
- } else {
- res = rpt_conf_create(myrpt->pchannel, myrpt, RPT_CONF, RPT_CONF_CONF | RPT_CONF_LISTENER | RPT_CONF_TALKER);
- }
- if (res) {
+ if (rpt_request_local(myrpt, cap, RPT_RXPCHAN, "RXPChan")) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
return -1;
}
- if (rpt_mon_setup(myrpt)) {
+ if (rpt_conf_add(myrpt->pchannel, myrpt, RPT_CONF)) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
return -1;
}
- if (rpt_request_pseudo(myrpt, cap, RPT_PARROTCHAN)) {
+ if (rpt_conf_add(myrpt->rxpchannel, myrpt, RPT_CONF)) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
return -1;
}
- if (rpt_request_pseudo(myrpt, cap, RPT_VOXCHAN)) {
+ /*! \todo Need to verify always setting MONCHAN to TXCONF is "ok" or how to deal at dialtime*/
+
+ if (rpt_conf_add(myrpt->monchannel, myrpt, RPT_TXCONF)) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
- rpt_hangup(myrpt, RPT_PARROTCHAN);
return -1;
}
- if (rpt_request_pseudo(myrpt, cap, RPT_TXPCHAN)) {
+ if (rpt_request_local(myrpt, cap, RPT_TXPCHAN, "TXPChan")) {
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
- rpt_hangup(myrpt, RPT_PARROTCHAN);
- rpt_hangup(myrpt, RPT_VOXCHAN);
return -1;
}
-
- /* make a conference for the tx */
- if (rpt_conf_add(myrpt->txpchannel, myrpt, RPT_TXCONF, RPT_CONF_CONF | RPT_CONF_TALKER)) {
+ if (rpt_conf_add(myrpt->txpchannel, myrpt, RPT_TXCONF)) {
rpt_hangup_rx_tx(myrpt);
+ rpt_hangup(myrpt, RPT_TXPCHAN);
rpt_hangup(myrpt, RPT_PCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
rpt_hangup(myrpt, RPT_MONCHAN);
- rpt_hangup(myrpt, RPT_PARROTCHAN);
- rpt_hangup(myrpt, RPT_VOXCHAN);
- rpt_hangup(myrpt, RPT_TXPCHAN);
return -1;
}
-
return 0;
}
@@ -3030,16 +3074,13 @@ static inline int rpt_any_hangups(struct rpt *myrpt)
if (ast_check_hangup(myrpt->monchannel)) {
return -1;
}
- if (myrpt->parrotchannel && ast_check_hangup(myrpt->parrotchannel)) {
- return -1;
- }
- if (myrpt->voxchannel && ast_check_hangup(myrpt->voxchannel)) {
+ if (ast_check_hangup(myrpt->txpchannel)) {
return -1;
}
- if (ast_check_hangup(myrpt->txpchannel)) {
+ if (ast_check_hangup(myrpt->rxpchannel)) {
return -1;
}
- if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) {
+ if (myrpt->localtxchannel && ast_check_hangup(myrpt->localtxchannel)) {
return -1;
}
return 0;
@@ -3084,7 +3125,7 @@ static inline void log_keyed(struct rpt *myrpt)
myrpt->dailykeyups++;
myrpt->totalkeyups++;
rpt_mutex_unlock(&myrpt->lock);
- if (!IS_PSEUDO(myrpt->txchannel)) {
+ if (!IS_LOCAL(myrpt->txchannel)) {
ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
}
rpt_mutex_lock(&myrpt->lock);
@@ -3100,7 +3141,7 @@ static inline void log_unkeyed(struct rpt *myrpt)
myrpt->txkeyed = 0;
time(&myrpt->lasttxkeyedtime);
rpt_mutex_unlock(&myrpt->lock);
- if (!IS_PSEUDO(myrpt->txchannel)) {
+ if (!IS_LOCAL(myrpt->txchannel)) {
ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
}
rpt_mutex_lock(&myrpt->lock);
@@ -3410,13 +3451,17 @@ static inline void periodic_process_links(struct rpt *myrpt, const int elap)
*/
static inline void do_key_post(struct rpt *myrpt)
{
- char str[100];
+ struct ast_str *str = ast_str_create(RPT_AST_STR_INIT_SIZE);
time_t now;
+ if (!str) {
+ return;
+ }
time(&now);
- snprintf(str, sizeof(str), "keyed=%d&keytime=%d", myrpt->keyed, myrpt->lastkeyedtime ? ((int) (now - myrpt->lastkeyedtime)) : 0);
+ ast_str_set(&str, 0, "&keyed=%d&keytime=%d", myrpt->keyed, myrpt->lastkeyedtime ? ((int) (now - myrpt->lastkeyedtime)) : 0);
rpt_mutex_unlock(&myrpt->lock);
statpost(myrpt, str);
+ ast_free(str);
rpt_mutex_lock(&myrpt->lock);
}
@@ -3441,7 +3486,7 @@ static inline int do_link_post(struct rpt *myrpt)
return -1;
}
nstr = 0;
- ast_str_set(&str, 0, "%s", "nodes=");
+ ast_str_set(&str, 0, "%s", "&nodes=");
RPT_LIST_TRAVERSE(myrpt->links, l, l_it) {
/* if is not a real link, ignore it */
if (l->name[0] == '0') {
@@ -3469,7 +3514,7 @@ static inline int do_link_post(struct rpt *myrpt)
(int) myrpt->totaltxtime / 1000, myrpt->timeouts, myrpt->totalexecdcommands, myrpt->keyed,
myrpt->lastkeyedtime ? ((int) (now - myrpt->lastkeyedtime)) : 0);
rpt_mutex_unlock(&myrpt->lock);
- statpost(myrpt, ast_str_buffer(str));
+ statpost(myrpt, str);
rpt_mutex_lock(&myrpt->lock);
ast_free(str);
return 0;
@@ -3552,7 +3597,9 @@ static inline int update_timers(struct rpt *myrpt, const int elap, const int tot
return 0;
}
-
+/*!
+ * \brief Update parrot channel -> parrot record timer is complete OR parrot mode changed to off
+ */
static inline int update_parrot(struct rpt *myrpt)
{
union {
@@ -3561,10 +3608,6 @@ static inline int update_parrot(struct rpt *myrpt)
char _filler[8];
} pu;
- if (rpt_parrot_add(myrpt)) {
- return -1;
- }
-
if (myrpt->parrotstream) {
ast_closestream(myrpt->parrotstream);
}
@@ -3688,6 +3731,22 @@ static int rxchannel_qwrite_cb(void *obj, void *arg, int flags)
return 0;
}
+/*! \brief Check and close parrot files if needed */
+static inline void check_parrot(struct rpt *myrpt)
+{
+ if (!(myrpt->p.parrotmode != PARROT_MODE_OFF || myrpt->parrotonce)) {
+ char myfname[300];
+
+ if (myrpt->parrotstream) {
+ ast_closestream(myrpt->parrotstream);
+ myrpt->parrotstream = NULL;
+ }
+
+ snprintf(myfname, sizeof(myfname), PARROTFILE ".wav", myrpt->name, myrpt->parrotcnt);
+ unlink(myfname);
+ }
+}
+
static inline int rxchannel_read(struct rpt *myrpt, const int lasttx)
{
int ismuted;
@@ -3699,7 +3758,7 @@ static inline int rxchannel_read(struct rpt *myrpt, const int lasttx)
ast_debug(1, "@@@@ rpt:Hung Up\n");
return -1;
}
-
+ check_parrot(myrpt);
if (f->frametype == AST_FRAME_TEXT && myrpt->rxchankeyed) {
char myrxrssi[RSSI_SZ + 1];
if (sscanf((char *) f->data.ptr, "R " S_FMT(RSSI_SZ), myrxrssi) == 1) {
@@ -3856,7 +3915,7 @@ static inline int rxchannel_read(struct rpt *myrpt, const int lasttx)
RPT_MUTE_FRAME(f);
}
- ismuted = dtmfed || rpt_conf_get_muted(myrpt->dahdirxchannel, myrpt);
+ ismuted = dtmfed || rpt_conf_get_muted(myrpt->localrxchannel, myrpt);
dtmfed = 0;
if (myrpt->p.votertype == 1) {
@@ -3887,9 +3946,14 @@ static inline int rxchannel_read(struct rpt *myrpt, const int lasttx)
}
f1 = rpt_frame_queue_helper(&myrpt->frame_queue, f, ismuted);
if (f1) {
- ast_write(myrpt->localoverride ? myrpt->txpchannel : myrpt->pchannel, f1);
- if (((myrpt->p.duplex < 2 && !myrpt->txkeyed) || myrpt->p.duplex == 3) && myrpt->monstream && myrpt->keyed) {
- ast_writestream(myrpt->monstream, f1);
+ ast_write(myrpt->localoverride ? myrpt->txpchannel : myrpt->rxpchannel, f1);
+ if (((myrpt->p.duplex < 2 && !myrpt->txkeyed) || myrpt->p.duplex == 3) && myrpt->keyed) {
+ if (myrpt->monstream) {
+ ast_writestream(myrpt->monstream, f1);
+ }
+ if (myrpt->parrotstream) {
+ ast_writestream(myrpt->parrotstream, f1);
+ }
}
if ((myrpt->p.duplex < 2) && myrpt->keyed && myrpt->p.outstreamcmd && (myrpt->outstreampipe[1] != -1)) {
outstream_write(myrpt, f1);
@@ -4106,15 +4170,17 @@ static inline int pchannel_read(struct rpt *myrpt)
return -1;
}
if (f->frametype == AST_FRAME_VOICE) {
- if (!myrpt->localoverride) {
+ if (!myrpt->localoverride && ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4))) {
+ /* We are in full duplex mode, send pchannel audio to txpchannel
+ * this audio includes the rxaudio frames to be retransmitted
+ * In DAHDI this was conference join in ANNOUNCER and MONITOR
+ */
ast_write(myrpt->txpchannel, f);
}
}
if (f->frametype == AST_FRAME_CONTROL) {
if (f->subclass.integer == AST_CONTROL_HANGUP) {
ast_debug(1, "@@@@ rpt:Hung Up\n");
- ast_frfree(f);
- return 0;
}
}
ast_frfree(f);
@@ -4149,9 +4215,9 @@ static inline int txchannel_read(struct rpt *myrpt)
return wait_for_hangup_helper(myrpt->txchannel, "txchannel");
}
-static inline int dahditxchannel_read(struct rpt *myrpt, char *restrict myfirst)
+static inline int localtxchannel_read(struct rpt *myrpt, char *restrict myfirst)
{
- struct ast_frame *f = ast_read(myrpt->dahditxchannel);
+ struct ast_frame *f = ast_read(myrpt->localtxchannel);
if (!f) {
ast_debug(1, "@@@@ rpt:Hung Up\n");
return -1;
@@ -4199,7 +4265,7 @@ static inline int dahditxchannel_read(struct rpt *myrpt, char *restrict myfirst)
}
ast_write(myrpt->txchannel, f);
}
- return hangup_frame_helper(myrpt->dahditxchannel, "dahditxchannel", f);
+ return hangup_frame_helper(myrpt->localtxchannel, "localtxchannel", f);
}
/*! \brief Safely hang up any channel, even if a PBX could be running on it */
@@ -4330,7 +4396,21 @@ static inline int process_link_channels(struct rpt *myrpt, struct ast_channel *w
struct timeval now;
if (l->disctime) {
- continue;
+ /* We are disconnected but still need to read and discard frames */
+ if (who == l->pchan) {
+ struct ast_frame *f;
+
+ rpt_mutex_unlock(&myrpt->lock);
+ f = ast_read(l->pchan);
+ if (!f) {
+ ast_debug(1, "@@@@ rpt:Hung Up\n");
+ return -1;
+ }
+ ast_frfree(f);
+ return 0;
+ } else {
+ continue;
+ }
}
remrx = 0;
@@ -4397,8 +4477,6 @@ static inline int process_link_channels(struct rpt *myrpt, struct ast_channel *w
int ismuted, n1;
float fac;
- dahdi_bump_buffers(l->pchan, f->samples); /* Make room if needed */
-
fac = 1.0;
if (l->chan) {
if (CHAN_TECH(l->chan, "echolink")) {
@@ -4644,11 +4722,18 @@ static inline int monchannel_read(struct rpt *myrpt)
ast_debug(1, "@@@@ rpt:Hung Up\n");
return -1;
}
+ check_parrot(myrpt);
+
if (f->frametype == AST_FRAME_VOICE) {
struct rpt_link *l;
- if (((myrpt->p.duplex > 1 && myrpt->p.duplex != 3) || (myrpt->txkeyed && !myrpt->keyed)) && myrpt->monstream) {
- ast_writestream(myrpt->monstream, f);
+ if ((myrpt->p.duplex > 1 && myrpt->p.duplex != 3) || (myrpt->txkeyed && !myrpt->keyed)) {
+ if (myrpt->monstream) {
+ ast_writestream(myrpt->monstream, f);
+ }
+ if (myrpt->parrotstream) {
+ ast_writestream(myrpt->parrotstream, f);
+ }
}
if (((myrpt->p.duplex >= 2) || (!myrpt->keyed)) && myrpt->p.outstreamcmd && (myrpt->outstreampipe[1] != -1)) {
outstream_write(myrpt, f);
@@ -4675,56 +4760,33 @@ static inline int monchannel_read(struct rpt *myrpt)
}
return hangup_frame_helper(myrpt->monchannel, "monchannel", f);
}
-
-static inline int parrotchannel_read(struct rpt *myrpt)
+static inline int rxpchannel_read(struct rpt *myrpt)
{
- struct ast_frame *f = ast_read(myrpt->parrotchannel);
+ struct ast_frame *f = ast_read(myrpt->rxpchannel);
if (!f) {
ast_debug(1, "@@@@ rpt:Hung Up\n");
return -1;
}
- if (!((myrpt->p.parrotmode != PARROT_MODE_OFF) || myrpt->parrotonce)) {
- char myfname[300];
-
- if (myrpt->parrotstream) {
- ast_closestream(myrpt->parrotstream);
- myrpt->parrotstream = 0;
+ if (f->frametype == AST_FRAME_VOICE) {
+ if (!myrpt->localoverride && (myrpt->p.duplex != 2) && (myrpt->p.duplex != 4)) {
+ /* We are in 1/2 duplex mode or mode 3, send rxpchannel audio to txpchannel
+ * this audio excludes the rxaudio frames
+ * In DAHDI this was conference join in TALKER and LISTENER
+ */
+ ast_write(myrpt->txpchannel, f);
}
- snprintf(myfname, sizeof(myfname), PARROTFILE, myrpt->name, myrpt->parrotcnt);
- strcat(myfname, ".wav");
- unlink(myfname);
- } else if (f->frametype == AST_FRAME_VOICE) {
- if (myrpt->parrotstream)
- ast_writestream(myrpt->parrotstream, f);
}
- return hangup_frame_helper(myrpt->parrotchannel, "parrotchannel", f);
+ return hangup_frame_helper(myrpt->rxpchannel, "rxpchannel", f);
}
-static inline int voxchannel_read(struct rpt *myrpt)
+static inline int txpchannel_read(struct rpt *myrpt)
{
- struct ast_frame *f = ast_read(myrpt->voxchannel);
+ struct ast_frame *f = ast_read(myrpt->txpchannel);
if (!f) {
ast_debug(1, "@@@@ rpt:Hung Up\n");
return -1;
}
- if (f->frametype == AST_FRAME_VOICE) {
- int n = dovox(&myrpt->vox, f->data.ptr, f->datalen / 2);
- if (n != myrpt->wasvox) {
- ast_debug(1, "Node %s, vox %d\n", myrpt->name, n);
- myrpt->wasvox = n;
- myrpt->voxtostate = 0;
- if (n)
- myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
- else
- myrpt->voxtotimer = 0;
- }
- }
- return hangup_frame_helper(myrpt->voxchannel, "voxchannel", f);
-}
-
-static inline int txpchannel_read(struct rpt *myrpt)
-{
- return wait_for_hangup_helper(myrpt->txpchannel, "txpchannel");
+ return hangup_frame_helper(myrpt->txpchannel, "txpchannel", f);
}
static inline void voxtostate_to_voxtotimer(struct rpt *myrpt)
@@ -4774,7 +4836,7 @@ static void *rpt(void *this)
myrpt->macrobuf = ast_str_create(MAXMACRO);
if (!myrpt->macrobuf) {
myrpt->rpt_thread = AST_PTHREADT_STOP;
- pthread_exit(NULL);
+ return NULL;
}
}
rpt_mutex_lock(&myrpt->lock);
@@ -4807,7 +4869,7 @@ static void *rpt(void *this)
ast_log(LOG_ERROR, "ioperm(%x) not supported on this architecture\n", myrpt->p.iobase);
#endif
myrpt->rpt_thread = AST_PTHREADT_STOP;
- pthread_exit(NULL);
+ return NULL;
}
cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
@@ -4815,17 +4877,17 @@ static void *rpt(void *this)
ast_log(LOG_ERROR, "Failed to alloc cap\n");
rpt_mutex_unlock(&myrpt->lock);
myrpt->rpt_thread = AST_PTHREADT_STOP;
- pthread_exit(NULL);
+ return NULL;
}
ast_format_cap_append(cap, ast_format_slin, 0);
-
+ ast_debug(1, "Setting up channels");
if (rpt_setup_channels(myrpt, cap)) {
rpt_mutex_unlock(&myrpt->lock);
myrpt->rpt_thread = AST_PTHREADT_STOP;
disable_rpt(myrpt); /* Disable repeater */
ao2_ref(cap, -1);
- pthread_exit(NULL);
+ return NULL;
}
ao2_ref(cap, -1);
@@ -4837,7 +4899,7 @@ static void *rpt(void *this)
rpt_mutex_unlock(&myrpt->lock);
rpt_hangup(myrpt, RPT_PCHAN);
rpt_hangup_rx_tx(myrpt);
- pthread_exit(NULL);
+ return NULL;
}
myrpt->links = ao2_container_alloc_list(0, /* AO2 object flags. 0 means to use the default behavior */
AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, /* AO2 container flags. New items should be added to the front of the list */
@@ -4910,7 +4972,7 @@ static void *rpt(void *this)
if (!(myrpt->dsp = ast_dsp_new())) {
rpt_hangup(myrpt, RPT_RXCHAN);
myrpt->rpt_thread = AST_PTHREADT_STOP;
- pthread_exit(NULL);
+ return NULL;
}
/*! \todo At this point, we have a memory leak, because dsp needs to be freed. */
/*! \todo Find out what the right place is to free dsp, i.e. when myrpt itself goes away. */
@@ -4952,7 +5014,7 @@ static void *rpt(void *this)
rpt_update_boolean(myrpt, "RPT_ALINKS", -1);
myrpt->ready = 1;
looptimestart = rpt_tvnow();
-
+ ast_autoservice_stop(myrpt->rxchannel);
while (ms >= 0) {
struct ast_channel *who;
struct ast_channel *cs[300], *cs1[300];
@@ -5366,16 +5428,10 @@ static void *rpt(void *this)
myrpt->rem_dtmfbuf[0] = 0;
}
- if (myrpt->exttx && myrpt->parrotchannel && ((myrpt->p.parrotmode != PARROT_MODE_OFF) || myrpt->parrotonce) &&
- (myrpt->parrotstate == PARROT_STATE_IDLE)) {
+ if (myrpt->exttx && ((myrpt->p.parrotmode != PARROT_MODE_OFF) || myrpt->parrotonce) && (myrpt->parrotstate == PARROT_STATE_IDLE)) {
char myfname[300];
-
- /* first put the channel on the conference in announce mode */
- if (rpt_conf_add_announcer_monitor(myrpt->parrotchannel, myrpt)) {
- rpt_mutex_unlock(&myrpt->lock);
- break;
- }
-
+ /* setup audiohook to spy on the pchannel. */
+ ast_verb(4, "Parrot attached to %s\n", ast_channel_name(myrpt->pchannel));
snprintf(myfname, sizeof(myfname), PARROTFILE ".wav", myrpt->name, myrpt->parrotcnt);
unlink(myfname);
myrpt->parrotstate = PARROT_STATE_RECORDING;
@@ -5424,7 +5480,7 @@ static void *rpt(void *this)
myrpt->lastitx = x;
if (myrpt->p.itxctcss) {
if (IS_DAHDI_CHAN(myrpt->rxchannel)) {
- dahdi_radio_set_ctcss_encode(myrpt->dahdirxchannel, !x);
+ dahdi_radio_set_ctcss_encode(myrpt->localrxchannel, !x);
} else if (CHAN_TECH(myrpt->rxchannel, "radio") || CHAN_TECH(myrpt->rxchannel, "simpleusb")) {
snprintf(str, sizeof(str), "TXCTCSS %d", !(!x));
ast_sendtext(myrpt->rxchannel, str);
@@ -5455,19 +5511,19 @@ static void *rpt(void *this)
n = 0;
cs[n++] = myrpt->rxchannel;
cs[n++] = myrpt->pchannel;
- cs[n++] = myrpt->monchannel;
- if (myrpt->parrotchannel)
- cs[n++] = myrpt->parrotchannel;
- if (myrpt->voxchannel)
- cs[n++] = myrpt->voxchannel;
cs[n++] = myrpt->txpchannel;
+ cs[n++] = myrpt->rxpchannel;
+ if (myrpt->monchannel)
+ cs[n++] = myrpt->monchannel;
if (myrpt->txchannel != myrpt->rxchannel)
cs[n++] = myrpt->txchannel;
- if (myrpt->dahditxchannel != myrpt->txchannel)
- cs[n++] = myrpt->dahditxchannel;
+ if (myrpt->localtxchannel != myrpt->txchannel)
+ cs[n++] = myrpt->localtxchannel;
RPT_LIST_TRAVERSE(myrpt->links, l, l_it) {
- if ((!l->killme) && (!l->disctime) && l->chan) {
- cs[n++] = l->chan;
+ if (!l->killme) {
+ if (l->chan) {
+ cs[n++] = l->chan;
+ }
cs[n++] = l->pchan;
}
}
@@ -5520,13 +5576,25 @@ static void *rpt(void *this)
len = ast_str_strlen(myrpt->macrobuf);
c = str[0];
time(&t);
+ if (myrpt->patch_talking != myrpt->wasvox) {
+ /* Autopatch vox has changed states. */
+ ast_debug(1, "Node %s, vox %d\n", myrpt->name, myrpt->patch_talking);
+ myrpt->wasvox = myrpt->patch_talking;
+ myrpt->voxtostate = 0;
+ if (myrpt->patch_talking) {
+ myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
+ } else {
+ myrpt->voxtotimer = 0;
+ }
+ }
if (c && !myrpt->macrotimer && starttime && t > starttime) {
char cin = c & 0x7f;
myrpt->macrotimer = MACROTIME;
ast_copy_string(str, str + 1, len);
ast_str_truncate(myrpt->macrobuf, len - 1);
- if ((cin == 'p') || (cin == 'P'))
+ if ((cin == 'p') || (cin == 'P')) {
myrpt->macrotimer = MACROPTIME;
+ }
rpt_mutex_unlock(&myrpt->lock);
donodelog_fmt(myrpt, "DTMF(M),MAIN,%c", cin);
local_dtmf_helper(myrpt, c);
@@ -5545,38 +5613,30 @@ static void *rpt(void *this)
break;
}
continue;
- } else if (who == myrpt->txchannel) { /* if it was a read from tx */
- if (txchannel_read(myrpt)) {
+ } else if (who == myrpt->rxpchannel) {
+ if (rxpchannel_read(myrpt)) {
break;
}
- continue;
- } else if (who == myrpt->dahditxchannel) { /* if it was a read from pseudo-tx */
- if (dahditxchannel_read(myrpt, &myfirst)) {
+ } else if (who == myrpt->txchannel) { /* if it was a read from tx - Note if rxchannel = txchannel, we won't get here */
+ if (txchannel_read(myrpt)) {
break;
}
continue;
- }
-
- if (process_link_channels(myrpt, who, &myfirst)) {
- break;
- }
-
- if (who == myrpt->monchannel) {
- if (monchannel_read(myrpt)) {
- break;
- }
- } else if (myrpt->parrotchannel && who == myrpt->parrotchannel) {
- if (parrotchannel_read(myrpt)) {
- break;
- }
- } else if (myrpt->voxchannel && who == myrpt->voxchannel) {
- if (voxchannel_read(myrpt)) {
+ } else if (who == myrpt->localtxchannel) { /* if it was a read from local-tx */
+ if (localtxchannel_read(myrpt, &myfirst)) {
break;
}
+ continue;
} else if (who == myrpt->txpchannel) { /* if it was a read from remote tx */
if (txpchannel_read(myrpt)) {
break;
}
+ } else if (who == myrpt->monchannel) {
+ if (monchannel_read(myrpt)) {
+ break;
+ }
+ } else if (process_link_channels(myrpt, who, &myfirst)) {
+ break;
}
}
@@ -5590,17 +5650,14 @@ static void *rpt(void *this)
usleep(50000);
}
rpt_hangup(myrpt, RPT_PCHAN);
- rpt_hangup(myrpt, RPT_MONCHAN);
- if (myrpt->parrotchannel) {
- rpt_hangup(myrpt, RPT_PARROTCHAN);
+ if (myrpt->monchannel) {
+ rpt_hangup(myrpt, RPT_MONCHAN);
}
myrpt->parrotstate = PARROT_STATE_IDLE;
- if (myrpt->voxchannel) {
- rpt_hangup(myrpt, RPT_VOXCHAN);
- }
rpt_hangup(myrpt, RPT_TXPCHAN);
- if (myrpt->dahditxchannel != myrpt->txchannel) {
- rpt_hangup(myrpt, RPT_DAHDITXCHAN);
+ rpt_hangup(myrpt, RPT_RXPCHAN);
+ if (myrpt->localtxchannel != myrpt->txchannel) {
+ rpt_hangup(myrpt, RPT_LOCALTXCHAN);
}
rpt_hangup_rx_tx(myrpt);
rpt_frame_queue_free(&myrpt->frame_queue);
@@ -6029,7 +6086,7 @@ static void *rpt_master(void *ignore)
done:
ast_mutex_unlock(&rpt_master_lock);
ast_debug(1, "app_rpt master thread exiting\n");
- pthread_exit(NULL);
+ return NULL;
}
static inline int exec_chan_read(struct rpt *myrpt, struct ast_channel *chan, char *restrict keyed,
@@ -6298,15 +6355,15 @@ static int get_his_ip(struct ast_channel *chan, char *buf, size_t len)
static inline int kenwood_uio_helper(struct rpt *myrpt)
{
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIOMODE, 3)) {
- ast_log(LOG_ERROR, "Cannot set UIOMODE on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIOMODE, 3)) {
+ ast_log(LOG_ERROR, "Cannot set UIOMODE on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
return -1;
}
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIODATA, 3)) {
- ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIODATA, 3)) {
+ ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
return -1;
}
- if (dahdi_set_offhook(myrpt->dahditxchannel)) {
+ if (dahdi_set_offhook(myrpt->localtxchannel)) {
return -1;
}
return 0;
@@ -6822,7 +6879,6 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
}
l->mode = MODE_TRANSCEIVE;
ast_copy_string(l->name, b1, MAXNODESTR);
- l->isremote = 0;
l->chan = chan;
l->last_frame_sent = 0;
l->connected = 1;
@@ -6832,8 +6888,6 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
l->phonemode = phone_mode;
l->phonevox = phone_vox;
l->phonemonitor = phone_monitor;
- l->dtmfed = 0;
- l->gott = 0;
l->rxlingertimer = RX_LINGER_TIME;
l->newkeytimer = NEWKEYTIME;
l->link_newkey = RADIO_KEY_ALLOWED;
@@ -6872,7 +6926,7 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
ast_format_cap_append(cap, ast_format_slin, 0);
/* allocate a pseudo-channel thru asterisk */
- if (__rpt_request_pseudo(l, cap, RPT_PCHAN, RPT_LINK_CHAN)) {
+ if (__rpt_request_local(l, cap, RPT_PCHAN, RPT_LINK_CHAN, "IAXLink")) {
ao2_ref(cap, -1);
ao2_ref(l, -1);
return -1;
@@ -6881,7 +6935,7 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
ao2_ref(cap, -1);
/* make a conference for the tx */
- if (rpt_conf_add_speaker(l->pchan, myrpt)) {
+ if (rpt_conf_add(l->pchan, myrpt, RPT_CONF)) {
ao2_ref(l, -1);
return -1;
}
@@ -7053,7 +7107,7 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
return -1;
}
- myrpt->dahditxchannel = NULL;
+ myrpt->localtxchannel = NULL;
if (myrpt->txchanname) {
if (__rpt_request(myrpt, cap, RPT_TXCHAN, RPT_LINK_CHAN)) {
rpt_mutex_unlock(&myrpt->lock);
@@ -7063,15 +7117,15 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
}
} else {
myrpt->txchannel = myrpt->rxchannel;
- if (IS_DAHDI_CHAN_NAME(myrpt->rxchanname)) {
- myrpt->dahditxchannel = myrpt->rxchannel;
+ if (IS_LOCAL_NAME(myrpt->rxchanname)) {
+ myrpt->localtxchannel = myrpt->rxchannel;
}
}
i = 3;
ast_channel_setoption(myrpt->rxchannel, AST_OPTION_TONE_VERIFY, &i, sizeof(char), 0);
- if (rpt_request_pseudo(myrpt, cap, RPT_PCHAN)) {
+ if (rpt_request_local(myrpt, cap, RPT_PCHAN, "PChan")) {
rpt_mutex_unlock(&myrpt->lock);
rpt_hangup_rx_tx(myrpt);
ao2_ref(cap, -1);
@@ -7080,21 +7134,25 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
ao2_ref(cap, -1);
- if (!myrpt->dahdirxchannel)
- myrpt->dahdirxchannel = myrpt->pchannel;
- if (!myrpt->dahditxchannel)
- myrpt->dahditxchannel = myrpt->pchannel;
+ if (!myrpt->localrxchannel)
+ myrpt->localrxchannel = myrpt->rxpchannel;
+ if (!myrpt->localtxchannel)
+ myrpt->localtxchannel = myrpt->pchannel;
/* first put the channel on the conference in announce/monitor mode */
- if (rpt_conf_create(myrpt->pchannel, myrpt, RPT_TXCONF, RPT_CONF_CONFANNMON)) {
+ if (rpt_conf_create(myrpt, RPT_TXCONF)) {
rpt_mutex_unlock(&myrpt->lock);
rpt_hangup_rx_tx(myrpt);
rpt_hangup(myrpt, RPT_PCHAN);
return -1;
}
- rpt_equate_tx_conf(myrpt);
-
+ if (rpt_conf_add(myrpt->pchannel, myrpt, RPT_TXCONF)) {
+ rpt_mutex_unlock(&myrpt->lock);
+ rpt_hangup_rx_tx(myrpt);
+ rpt_hangup(myrpt, RPT_PCHAN);
+ return -1;
+ }
/* if serial io port, open it */
myrpt->iofd = -1;
if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt, myrpt->p.ioport)) == -1)) {
@@ -7106,8 +7164,8 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
}
iskenwood_pci4 = 0;
- if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel)) {
- res = rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_NONE);
+ if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->localtxchannel)) {
+ res = rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_NONE);
/* if PCIRADIO and kenwood selected */
if ((!res) && (!strcmp(myrpt->remoterig, REMOTE_RIG_KENWOOD))) {
if (kenwood_uio_helper(myrpt)) {
@@ -7117,20 +7175,20 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
iskenwood_pci4 = 1;
}
}
- if (myrpt->txchannel == myrpt->dahditxchannel) {
- dahdi_set_onhook(myrpt->dahditxchannel);
+ if (myrpt->txchannel == myrpt->localtxchannel) {
+ dahdi_set_onhook(myrpt->localtxchannel);
/* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
if ((myrpt->iofd < 1) && (!res) &&
((!strcmp(myrpt->remoterig, REMOTE_RIG_FT897)) || (!strcmp(myrpt->remoterig, REMOTE_RIG_FT950)) ||
(!strcmp(myrpt->remoterig, REMOTE_RIG_FT100)) || (!strcmp(myrpt->remoterig, REMOTE_RIG_XCAT)) ||
(!strcmp(myrpt->remoterig, REMOTE_RIG_IC706)) || (!strcmp(myrpt->remoterig, REMOTE_RIG_TM271)))) {
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIOMODE, 1)) {
- ast_log(LOG_ERROR, "Cannot set UIOMODE on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIOMODE, 1)) {
+ ast_log(LOG_ERROR, "Cannot set UIOMODE on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
rpt_mutex_unlock(&myrpt->lock);
return -1;
}
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIODATA, 3)) {
- ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIODATA, 3)) {
+ ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
rpt_mutex_unlock(&myrpt->lock);
return -1;
}
@@ -7190,15 +7248,11 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
ast_set_read_format(chan, ast_format_slin);
rem_rx = 0;
remkeyed = 0;
- /* if we are on 2w loop and are a remote, turn EC on */
- if (myrpt->remote && myrpt->rxchannel == myrpt->txchannel) {
- dahdi_set_echocancel(myrpt->dahdirxchannel, 128);
- }
answer_newkey_helper(myrpt, chan, phone_mode);
- if (myrpt->rxchannel == myrpt->dahdirxchannel) {
- if (dahdi_rx_offhook(myrpt->dahdirxchannel) == 1) {
+ if (myrpt->rxchannel == myrpt->localrxchannel) {
+ if (dahdi_rx_offhook(myrpt->localrxchannel) == 1) {
ast_indicate(chan, AST_CONTROL_RADIO_KEY);
myrpt->remoterx = 1;
remkeyed = 1;
@@ -7457,9 +7511,9 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
}
telem = telem->next;
}
- if (iskenwood_pci4 && myrpt->txchannel == myrpt->dahditxchannel) {
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIODATA, 1)) {
- ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (iskenwood_pci4 && myrpt->txchannel == myrpt->localtxchannel) {
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIODATA, 1)) {
+ ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
return -1;
}
} else {
@@ -7475,9 +7529,9 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
if (!myrpt->remtxfreqok) {
rpt_telemetry(myrpt, UNAUTHTX, NULL);
}
- if (iskenwood_pci4 && myrpt->txchannel == myrpt->dahditxchannel) {
- if (rpt_radio_set_param(myrpt->dahditxchannel, RPT_RADPAR_UIODATA, 3)) {
- ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->dahditxchannel), strerror(errno));
+ if (iskenwood_pci4 && myrpt->txchannel == myrpt->localtxchannel) {
+ if (rpt_radio_set_param(myrpt->localtxchannel, RPT_RADPAR_UIODATA, 3)) {
+ ast_log(LOG_ERROR, "Cannot set UIODATA on %s: %s\n", ast_channel_name(myrpt->localtxchannel), strerror(errno));
return -1;
}
} else {
@@ -7556,7 +7610,7 @@ static int rpt_exec(struct ast_channel *chan, const char *data)
myrpt->remoteon = 0;
rpt_mutex_unlock(&myrpt->lock);
rpt_frame_queue_free(&myrpt->frame_queue);
- if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel)) {
+ if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->localtxchannel)) {
if (kenwood_uio_helper(myrpt)) {
return -1;
}
@@ -7708,6 +7762,12 @@ static int reload(void)
ast_mutex_unlock(&rpt_master_lock);
return (0);
}
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application", .support_level = AST_MODULE_SUPPORT_EXTENDED,
- .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_curl", );
+/* clang-format off */
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
+ .support_level = AST_MODULE_SUPPORT_EXTENDED,
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .requires = "res_curl, bridge_softmix, chan_bridge_media",
+);
+/* clang-format on */
diff --git a/apps/app_rpt/app_rpt.h b/apps/app_rpt/app_rpt.h
index 0e101354b..53c664d3f 100644
--- a/apps/app_rpt/app_rpt.h
+++ b/apps/app_rpt/app_rpt.h
@@ -741,12 +741,13 @@ struct rpt_cmd_struct {
enum rpt_command_source command_source;
};
+struct ast_bridge; /* Forward declaration */
+
+/*! \brief Structure used to manage conference bridges */
struct rpt_conf {
- /* DAHDI conference numbers */
- struct {
- int conf;
- int txconf;
- } dahdiconf;
+ /* Conference bridge channels */
+ struct ast_bridge *conf;
+ struct ast_bridge *txconf;
};
/*! \brief Populate rpt structure with data */
@@ -941,16 +942,21 @@ struct rpt {
int parrottimer;
unsigned int parrotcnt;
int telemmode;
- struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
- struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
- struct ast_channel *voxchannel;
+ struct ast_channel *rxchannel; /*!< Channel connected to physical hardware, can be bi-directional */
+ struct ast_channel *txchannel; /*!< Channel connect to physical hardware if separate otherwise equal to rxchannel */
+ struct ast_channel *monchannel; /*!< Monitor channel used to record activity on the TXCONF */
+ struct ast_channel *pchannel; /*!< Channel used to copy CONF bridge audio into txpchannel */
+ struct ast_channel *rxpchannel; /*!< Channel used to copy RX audio into CONF bridge */
+ struct ast_channel *txpchannel; /*!< Channel used to receive RX audio into the TXCONF bridge */
+ struct ast_channel *localrxchannel; /*!< Channel used when in remote configuration for rx, may be set equal to pchannel */
+ struct ast_channel *localtxchannel; /*!< Channel used to receive audio from the TXCONF bridge into the txchannel */
struct rpt_frame_queue frame_queue;
struct rpt_tele tele;
struct timeval lasttv,curtv;
- pthread_t rpt_call_thread,rpt_thread;
- time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
- int calldigittimer;
struct rpt_conf rptconf;
+ pthread_t rpt_call_thread, rpt_thread;
+ time_t dtmf_time, rem_dtmf_time, dtmf_time_rem;
+ int calldigittimer;
int tailtimer, totimer, idtimer, cidx, scantimer, tmsgtimer, skedtimer, linkactivitytimer, elketimer;
int remote_time_out_reset_unkey_interval_timer, time_out_reset_unkey_interval_timer;
enum patch_call_mode callmode;
@@ -1024,6 +1030,7 @@ struct rpt {
int lastkeytimer;
enum newkey rpt_newkey;
int rxlingertimer;
+ rpt_bool patch_talking:1;
rpt_bool inpadtest:1;
rpt_bool localoverride:1;
rpt_bool wasvox:1;
@@ -1098,7 +1105,7 @@ struct nodelog {
struct statpost {
struct rpt *myrpt;
- char *stats_url;
+ struct ast_str *stats_url;
};
/*! \brief Whether a channel is using a specified technology */
@@ -1107,6 +1114,9 @@ struct statpost {
#define IS_PSEUDO(c) (!strncasecmp(ast_channel_name(c), "DAHDI/pseudo", 12))
#define IS_PSEUDO_NAME(c) (!strncasecmp(c, "DAHDI/pseudo", 12))
+#define IS_LOCAL(c) (!strncasecmp(ast_channel_name(c), "Local", 5))
+#define IS_LOCAL_NAME(c) (!strncasecmp(c, "Local", 5))
+
int rpt_debug_level(void);
int rpt_set_debug_level(int newlevel);
int rpt_num_rpts(void);
diff --git a/apps/app_rpt/rpt_bridging.c b/apps/app_rpt/rpt_bridging.c
index c4c73d68d..aa1073fd5 100644
--- a/apps/app_rpt/rpt_bridging.c
+++ b/apps/app_rpt/rpt_bridging.c
@@ -27,17 +27,22 @@
#include "asterisk.h"
#include
-#include /* use tone_zone_set_zone */
+#include "asterisk/bridge.h"
+#include "asterisk/core_unreal.h"
#include "asterisk/channel.h"
#include "asterisk/indications.h"
#include "asterisk/format_cache.h" /* use ast_format_slin */
+#include "asterisk/audiohook.h"
#include "app_rpt.h"
#include "rpt_bridging.h"
#include "rpt_call.h"
+/*!
+ * \brief used to display "words" in debug messages.
+ */
static const char *rpt_chan_type_str(enum rpt_chan_type chantype)
{
switch (chantype) {
@@ -47,16 +52,14 @@ static const char *rpt_chan_type_str(enum rpt_chan_type chantype)
return "txchan";
case RPT_PCHAN:
return "pchan";
- case RPT_DAHDITXCHAN:
- return "dahditxchan";
+ case RPT_LOCALTXCHAN:
+ return "localtxchan";
case RPT_MONCHAN:
return "monchan";
- case RPT_PARROTCHAN:
- return "parrotchan";
- case RPT_VOXCHAN:
- return "voxchan";
case RPT_TXPCHAN:
return "txpchan";
+ case RPT_RXPCHAN:
+ return "rxpchan";
}
ast_assert(0);
return NULL;
@@ -70,11 +73,10 @@ static const char *rpt_chan_name(struct rpt *myrpt, enum rpt_chan_type chantype)
case RPT_TXCHAN:
return myrpt->txchanname;
case RPT_PCHAN:
- case RPT_DAHDITXCHAN:
+ case RPT_LOCALTXCHAN:
case RPT_MONCHAN:
- case RPT_PARROTCHAN:
- case RPT_VOXCHAN:
case RPT_TXPCHAN:
+ case RPT_RXPCHAN:
return NULL;
}
ast_assert(0);
@@ -91,16 +93,14 @@ static struct ast_channel **rpt_chan_channel(struct rpt *myrpt, struct rpt_link
return &myrpt->txchannel;
case RPT_PCHAN:
return &myrpt->pchannel;
- case RPT_DAHDITXCHAN:
- return &myrpt->dahditxchannel;
+ case RPT_LOCALTXCHAN:
+ return &myrpt->localtxchannel;
case RPT_MONCHAN:
return &myrpt->monchannel;
- case RPT_PARROTCHAN:
- return &myrpt->parrotchannel;
- case RPT_VOXCHAN:
- return &myrpt->voxchannel;
case RPT_TXPCHAN:
return &myrpt->txpchannel;
+ case RPT_RXPCHAN:
+ return &myrpt->rxpchannel;
}
} else if (link) {
switch (chantype) {
@@ -114,7 +114,7 @@ static struct ast_channel **rpt_chan_channel(struct rpt *myrpt, struct rpt_link
return NULL;
}
-#define RPT_DIAL_TIME 999
+#define RPT_DIAL_DURATION 999 /*! \brief Wait timeout for ast_call() executions (asterisk may not be using) */
void rpt_hangup(struct rpt *myrpt, enum rpt_chan_type chantype)
{
@@ -139,6 +139,10 @@ void rpt_hangup(struct rpt *myrpt, enum rpt_chan_type chantype)
ast_debug(2, "Also resetting rxchannel\n");
myrpt->rxchannel = NULL;
}
+ if (myrpt->localtxchannel && myrpt->localtxchannel == *chanptr) {
+ ast_debug(2, "Also resetting localtxchannel\n");
+ myrpt->localtxchannel = NULL;
+ }
break;
default:
break;
@@ -153,15 +157,14 @@ static const char *rpt_chan_app(enum rpt_chan_type chantype, enum rpt_chan_flags
{
switch (chantype) {
case RPT_RXCHAN:
- return flags & RPT_LINK_CHAN ? "(Link Rx)" : "(Repeater Rx)";
+ return flags & RPT_LINK_CHAN ? "Link Rx" : "Repeater Rx";
case RPT_TXCHAN:
- return flags & RPT_LINK_CHAN ? "(Link Tx)" : "(Repeater Tx)";
+ return flags & RPT_LINK_CHAN ? "Link Tx" : "Repeater Tx";
case RPT_PCHAN:
- case RPT_DAHDITXCHAN:
+ case RPT_LOCALTXCHAN:
case RPT_MONCHAN:
- case RPT_PARROTCHAN:
- case RPT_VOXCHAN:
case RPT_TXPCHAN:
+ case RPT_RXPCHAN:
return NULL;
}
ast_assert(0);
@@ -176,11 +179,10 @@ static const char *rpt_chan_app_data(enum rpt_chan_type chantype)
case RPT_TXCHAN:
return "Tx";
case RPT_PCHAN:
- case RPT_DAHDITXCHAN:
+ case RPT_LOCALTXCHAN:
case RPT_MONCHAN:
- case RPT_PARROTCHAN:
- case RPT_VOXCHAN:
case RPT_TXPCHAN:
+ case RPT_RXPCHAN:
return NULL;
}
ast_assert(0);
@@ -224,21 +226,13 @@ int __rpt_request(void *data, struct ast_format_cap *cap, enum rpt_chan_type cha
return -1;
}
- /* XXX
- * Note: Removed in refactoring:
- * inside rpt_make_call, we should rpt_mutex_unlock(&myrpt->lock);
- * before ast_call
- * and
- * rpt_mutex_lock(&myrpt->lock);
- * afterwards,
- * if flags & RPT_LINK_CHAN.
- * This might not be necessary, but if it is, this should be re-added. */
-
- rpt_make_call(chan, device, RPT_DIAL_TIME, tech, rpt_chan_app(chantype, flags), rpt_chan_app_data(chantype), myrpt->name);
- if (ast_channel_state(chan) != AST_STATE_UP) {
- ast_log(LOG_ERROR, "Requested channel %s not up?\n", ast_channel_name(chan));
- ast_hangup(chan);
- return -1;
+ if (!IS_LOCAL_NAME(tech)) {
+ rpt_make_call(chan, device, RPT_DIAL_DURATION, tech, rpt_chan_app(chantype, flags), rpt_chan_app_data(chantype), myrpt->name);
+ if (ast_channel_state(chan) != AST_STATE_UP) {
+ ast_log(LOG_ERROR, "Requested channel %s not up?\n", ast_channel_name(chan));
+ ast_hangup(chan);
+ return -1;
+ }
}
chanptr = rpt_chan_channel(myrpt, NULL, chantype);
@@ -246,15 +240,10 @@ int __rpt_request(void *data, struct ast_format_cap *cap, enum rpt_chan_type cha
switch (chantype) {
case RPT_RXCHAN:
- myrpt->dahdirxchannel = !strcasecmp(tech, "DAHDI") ? chan : NULL;
+ myrpt->localrxchannel = IS_LOCAL_NAME(tech) ? chan : NULL;
break;
case RPT_TXCHAN:
- if (flags & RPT_LINK_CHAN) {
- /* XXX Dunno if this difference is really necessary, but this is a literal refactor of existing logic... */
- myrpt->dahditxchannel = !strcasecmp(tech, "DAHDI") ? chan : NULL;
- } else {
- myrpt->dahditxchannel = !strcasecmp(tech, "DAHDI") && strcasecmp(device, "pseudo") ? chan : NULL;
- }
+ myrpt->localtxchannel = IS_LOCAL_NAME(tech) ? chan : NULL;
break;
default:
break;
@@ -263,19 +252,62 @@ int __rpt_request(void *data, struct ast_format_cap *cap, enum rpt_chan_type cha
return 0;
}
-struct ast_channel *rpt_request_pseudo_chan(struct ast_format_cap *cap)
+static const char *rpt_bridge_chan_type_name(enum rpt_bridge_chan_type type)
+{
+ switch (type) {
+ case RPT_LOCAL:
+ return "Local";
+ case RPT_TELEMETRY:
+ return "Announcer";
+ case RPT_MONITOR:
+ return "Recorder";
+ }
+ ast_assert(0);
+ return NULL;
+}
+
+static const char *rpt_chan_type_name(enum rpt_chan_type type, enum rpt_chan_flags flags)
{
- struct ast_channel *chan = ast_request("DAHDI", cap, NULL, NULL, "pseudo", NULL);
+ if (flags & RPT_LINK_CHAN) {
+ return "Announcer";
+ }
+
+ switch (type) {
+ case RPT_MONCHAN:
+ case RPT_PCHAN:
+ return "Recorder";
+ case RPT_RXPCHAN:
+ case RPT_TXPCHAN:
+ return "Announcer";
+ default:
+ return "Local";
+ }
+}
+
+struct ast_channel *__rpt_request_local_chan(struct ast_format_cap *cap, const char *exten, enum rpt_bridge_chan_type type)
+{
+ struct ast_channel *chan;
+
+ chan = ast_request(rpt_bridge_chan_type_name(type), cap, NULL, NULL, exten, NULL);
if (!chan) {
- ast_log(LOG_ERROR, "Failed to request pseudo channel\n");
+ ast_log(LOG_ERROR, "Failed to request local channel\n");
return NULL;
}
- rpt_disable_cdr(chan);
- ast_answer(chan);
+
+ ast_debug(1, "Requesting channel %s setup\n", ast_channel_name(chan));
+ ast_set_read_format(chan, ast_format_slin);
+ ast_set_write_format(chan, ast_format_slin);
+ if (type == RPT_LOCAL) {
+ /* Local channel needs to be answered.
+ * Announcer channels auto answer on creation.
+ */
+ rpt_disable_cdr(chan);
+ ast_debug(1, "Requested channel %s cdr disabled\n", ast_channel_name(chan));
+ }
return chan;
}
-int __rpt_request_pseudo(void *data, struct ast_format_cap *cap, enum rpt_chan_type chantype, enum rpt_chan_flags flags)
+int __rpt_request_local(void *data, struct ast_format_cap *cap, enum rpt_chan_type chantype, enum rpt_chan_flags flags, const char *exten)
{
struct rpt *myrpt = NULL;
struct rpt_link *link = NULL;
@@ -286,30 +318,25 @@ int __rpt_request_pseudo(void *data, struct ast_format_cap *cap, enum rpt_chan_t
} else {
myrpt = data;
}
-
- chan = ast_request("DAHDI", cap, NULL, NULL, "pseudo", NULL);
+ chan = ast_request(rpt_chan_type_name(chantype, flags), cap, NULL, NULL, exten, NULL);
if (!chan) {
- ast_log(LOG_ERROR, "Failed to request pseudo channel\n");
+ ast_log(LOG_ERROR, "Failed to request local channel\n");
return -1;
}
-
- ast_debug(1, "Requested channel %s\n", ast_channel_name(chan));
-
- /* A subset of what rpt_make_call does... */
ast_set_read_format(chan, ast_format_slin);
ast_set_write_format(chan, ast_format_slin);
rpt_disable_cdr(chan);
- ast_answer(chan);
-
chanptr = rpt_chan_channel(myrpt, link, chantype);
*chanptr = chan;
switch (chantype) {
+ case RPT_MONCHAN:
+ break; /* WE don't need to answer MONCHAN */
case RPT_PCHAN:
if (!(flags & RPT_LINK_CHAN)) {
ast_assert(myrpt != NULL);
- if (!myrpt->dahdirxchannel) {
- myrpt->dahdirxchannel = chan;
+ if (!myrpt->localrxchannel) {
+ myrpt->localrxchannel = chan;
}
}
break;
@@ -320,322 +347,119 @@ int __rpt_request_pseudo(void *data, struct ast_format_cap *cap, enum rpt_chan_t
return 0;
}
-#define join_dahdiconf(chan, ci) __join_dahdiconf(chan, ci, __FILE__, __LINE__, __PRETTY_FUNCTION__)
-
-static int __join_dahdiconf(struct ast_channel *chan, struct dahdi_confinfo *ci, const char *file, int line, const char *function)
-{
- ci->chan = 0;
-
- /* First put the channel on the conference in proper mode */
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_SETCONF, ci) == -1) {
- ast_log(LOG_WARNING, "%s:%d (%s) Unable to set conference mode on %s\n", file, line, function, ast_channel_name(chan));
- return -1;
- }
- return 0;
-}
-
-static int dahdi_conf_create(struct ast_channel *chan, int *confno, int mode)
-{
- int res;
- struct dahdi_confinfo ci; /* conference info */
-
- ci.confno = -1;
- ci.confmode = mode;
-
- res = join_dahdiconf(chan, &ci);
- if (res) {
- ast_log(LOG_WARNING, "Failed to join DAHDI conf (mode: %d)\n", mode);
- } else {
- *confno = ci.confno;
- }
- return res;
-}
-
-static int dahdi_conf_add(struct ast_channel *chan, int confno, int mode)
-{
- int res;
- struct dahdi_confinfo ci; /* conference info */
-
- ci.confno = confno;
- ci.confmode = mode;
-
- ast_debug(2, "Channel %s joining conference %i", ast_channel_name(chan), confno);
-
- res = join_dahdiconf(chan, &ci);
- if (res) {
- ast_log(LOG_WARNING, "Failed to join DAHDI conf (mode: %d)\n", mode);
- }
- return res;
-}
-
-#define RPT_DAHDI_FLAG(r, d) \
- if (rflags & r) { \
- dflags |= d; \
- }
-
-static int dahdi_conf_flags(enum rpt_conf_flags rflags)
-{
- int dflags = 0;
-
- RPT_DAHDI_FLAG(RPT_CONF_NORMAL, DAHDI_CONF_NORMAL);
- RPT_DAHDI_FLAG(RPT_CONF_MONITOR, DAHDI_CONF_MONITOR);
- RPT_DAHDI_FLAG(RPT_CONF_MONITORTX, DAHDI_CONF_MONITORTX);
- RPT_DAHDI_FLAG(RPT_CONF_CONF, DAHDI_CONF_CONF);
- RPT_DAHDI_FLAG(RPT_CONF_CONFANN, DAHDI_CONF_CONFANN);
- RPT_DAHDI_FLAG(RPT_CONF_CONFMON, DAHDI_CONF_CONFMON);
- RPT_DAHDI_FLAG(RPT_CONF_CONFANNMON, DAHDI_CONF_CONFANNMON);
- RPT_DAHDI_FLAG(RPT_CONF_LISTENER, DAHDI_CONF_LISTENER);
- RPT_DAHDI_FLAG(RPT_CONF_TALKER, DAHDI_CONF_TALKER);
-
- return dflags;
-}
-
-static int *dahdi_confno(struct rpt *myrpt, enum rpt_conf_type type)
+int __rpt_conf_create(struct rpt *myrpt, enum rpt_conf_type type, const char *file, int line)
{
+ struct ast_bridge *conf = NULL, **confptr;
+ const char *conference_name = "";
switch (type) {
case RPT_CONF:
- return &myrpt->rptconf.dahdiconf.conf;
+ conference_name = RPT_CONF_NAME;
+ confptr = &myrpt->rptconf.conf;
+ break;
case RPT_TXCONF:
- return &myrpt->rptconf.dahdiconf.txconf;
- }
- ast_assert(0);
- return NULL;
-}
-
-/*!
- * \brief Get the channel number of a DAHDI channel
- * \param chan DAHDI channel
- * \retval -1 on failure, conference number on success
- */
-static int dahdi_conf_get_channo(struct ast_channel *chan)
-{
- struct dahdi_confinfo ci = {0};
-
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_CHANNO, &ci.chan)) {
- ast_log(LOG_WARNING, "DAHDI_CHANNO failed: %s\n", strerror(errno));
+ conference_name = RPT_TXCONF_NAME;
+ confptr = &myrpt->rptconf.txconf;
+ break;
+ default:
+ __builtin_unreachable();
return -1;
}
-
- return ci.chan;
-}
-
-int __rpt_conf_create(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, enum rpt_conf_flags flags, const char *file, int line)
-{
- int *confno, dflags;
- /* Convert RPT conf flags to DAHDI conf flags... for now. */
- dflags = dahdi_conf_flags(flags);
- confno = dahdi_confno(myrpt, type);
- if (dahdi_conf_create(chan, confno, dflags)) {
- ast_log(LOG_ERROR, "%s:%d: Failed to create conference using chan type %d\n", file, line, type);
+ ast_debug(3, "Setting up conference '%s' mixing bridge \n", conference_name);
+ conf = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_MULTIMIX,
+ AST_BRIDGE_FLAG_MASQUERADE_ONLY | AST_BRIDGE_FLAG_TRANSFER_BRIDGE_ONLY, "app_rpt", conference_name, NULL);
+ if (!conf) {
+ ast_log(LOG_ERROR, "Conference '%s' mixing bridge could not be created.\n", conference_name);
return -1;
}
- return 0;
-}
-int rpt_equate_tx_conf(struct rpt *myrpt)
-{
- /* save pseudo channel conference number */
- myrpt->rptconf.dahdiconf.conf = myrpt->rptconf.dahdiconf.txconf;
- return 0;
-}
-
-int __rpt_conf_add(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, enum rpt_conf_flags flags, const char *file, int line)
-{
- /* Convert RPT conf flags to DAHDI conf flags... for now. */
- int *confno, dflags;
-
- dflags = dahdi_conf_flags(flags);
- confno = dahdi_confno(myrpt, type);
-
- if (dahdi_conf_add(chan, *confno, dflags)) {
- ast_log(LOG_ERROR, "%s:%d: Failed to add to conference using chan type %d\n", file, line, type);
- return -1;
- }
+ *confptr = conf;
return 0;
}
-int rpt_call_bridge_setup(struct rpt *myrpt, struct ast_channel *mychannel)
+int __rpt_conf_add(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, const char *file, int line)
{
+ struct ast_bridge *conf = NULL;
+ const char *conference_name = "";
+ struct ast_unreal_pvt *p;
int res;
- /* Put pchannel back on the conference in speaker mode */
- if (myrpt->p.duplex == 4 || myrpt->p.duplex == 3) {
- if (rpt_conf_add_speaker(myrpt->pchannel, myrpt)) {
- return -1;
- }
- }
-
- /* get its conference number */
- res = dahdi_conf_get_channo(mychannel);
- if (res < 0) {
- ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
- /* Put pchannel back on the conference in announce mode */
- if (myrpt->p.duplex == 4 || myrpt->p.duplex == 3) {
- rpt_conf_add_announcer_monitor(myrpt->pchannel, myrpt);
- }
+ switch (type) {
+ case RPT_CONF:
+ conference_name = RPT_CONF_NAME;
+ conf = myrpt->rptconf.conf;
+ break;
+ case RPT_TXCONF:
+ conference_name = RPT_TXCONF_NAME;
+ conf = myrpt->rptconf.txconf;
+ break;
+ default:
+ __builtin_unreachable();
return -1;
}
-
- /* put vox channel monitoring on the channel
- *
- * This uses the internal DAHDI channel number to create the
- * monitor conference. This code will hang here when trying to
- * join the conference when the underlying version of DAHDI in use
- * is missing a patch that allows the DAHDI_CONF_MONITOR option
- * to monitor a pseudo channel. This patch prevents the hardware
- * pre-echo routines from acting on a pseudo channel. It also
- * prevents the DAHDI check conference routine from acting
- * on a channel number being used as a conference.
- */
- if (dahdi_conf_add(myrpt->voxchannel, res, DAHDI_CONF_MONITOR)) {
- /* Put pchannel back on the conference in announce mode */
- if (myrpt->p.duplex == 4 || myrpt->p.duplex == 3) {
- rpt_conf_add_announcer_monitor(myrpt->pchannel, myrpt);
- }
+ if (!conf) {
+ ast_log(LOG_ERROR, "Conference '%s' mixing bridge doesn't exist, can't add channel %s\n", conference_name, ast_channel_name(chan));
return -1;
}
- return 0;
-}
-
-int rpt_mon_setup(struct rpt *myrpt)
-{
- int res;
-
- if (!IS_PSEUDO(myrpt->txchannel) && myrpt->dahditxchannel == myrpt->txchannel) {
- int confno = dahdi_conf_get_channo(myrpt->txchannel); /* get tx channel's port number */
- if (confno < 0) {
- return -1;
- }
- res = dahdi_conf_add(myrpt->monchannel, confno, DAHDI_CONF_MONITORTX);
- } else {
- /* first put the channel on the conference in announce mode */
- res = rpt_conf_add(myrpt->monchannel, myrpt, RPT_TXCONF, RPT_CONF_CONFANNMON);
+ ast_debug(3, "Adding channel %s to conference '%s' mixing bridge \n", ast_channel_name(chan), conference_name);
+ res = ast_unreal_channel_push_to_bridge(chan, conf, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
+ if (res) {
+ ast_log(LOG_ERROR, "Failed to add channel %s to conference '%s'\n", ast_channel_name(chan), conference_name);
+ return res;
+ }
+ p = ast_channel_tech_pvt(chan);
+ if (p && p->chan) {
+ ast_raw_answer(p->chan); /* We can not wait 500ms for media to start flowing */
}
return res;
}
-int rpt_parrot_add(struct rpt *myrpt)
+int rpt_conf_get_muted(struct ast_channel *chan, struct rpt *myrpt)
{
- /* first put the channel on the conference in announce mode */
- if (dahdi_conf_add(myrpt->parrotchannel, 0, DAHDI_CONF_NORMAL)) {
- return -1;
- }
+ /*! \todo: Do we need to check mute? What should it do?*/
return 0;
}
-static int dahdi_conf_get_muted(struct ast_channel *chan)
+int rpt_play_tone(struct ast_channel *chan, const char *tone)
{
- int muted;
-
- if (!CHAN_TECH(chan, "DAHDI")) {
- return 0;
- }
-
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_GETCONFMUTE, &muted) == -1) {
- ast_log(LOG_WARNING, "Couldn't get mute status on %s: %s\n", ast_channel_name(chan), strerror(errno));
- muted = 0;
+ int res = 0;
+ struct ast_tone_zone *zone = ast_channel_zone(chan);
+ struct ast_tone_zone_sound *ts = ast_get_indication_tone(zone, tone);
+ if (ts) {
+ res = ast_playtones_start(chan, 0, ts->data, 0);
+ ts = ast_tone_zone_sound_unref(ts);
+ } else {
+ ast_log(LOG_WARNING, "No tone '%s' found in zone '%s'\n", tone, (zone && zone->country[0]) ? zone->country : "default");
+ return -1;
}
- return muted;
-}
-
-int rpt_conf_get_muted(struct ast_channel *chan, struct rpt *myrpt)
-{
- return dahdi_conf_get_muted(chan);
-}
-/*!
- * \param chan
- * \param tone DAHDI_TONE_DIALTONE, DAHDI_TONE_CONGESTION, or -1 to stop tone
- * \retval 0 on success, -1 on failure
- */
-static int rpt_play_tone(struct ast_channel *chan, int tone)
-{
- if (tone_zone_play_tone(ast_channel_fd(chan, 0), tone)) {
+ if (res) {
ast_log(LOG_WARNING, "Cannot start tone on %s\n", ast_channel_name(chan));
return -1;
}
return 0;
}
-int rpt_play_dialtone(struct ast_channel *chan)
-{
- return rpt_play_tone(chan, DAHDI_TONE_DIALTONE);
-}
-
-int rpt_play_congestion(struct ast_channel *chan)
-{
- return rpt_play_tone(chan, DAHDI_TONE_CONGESTION);
-}
-
int rpt_stop_tone(struct ast_channel *chan)
{
- return rpt_play_tone(chan, -1);
-}
-
-int rpt_set_tone_zone(struct ast_channel *chan, const char *tz)
-{
- if (tone_zone_set_zone(ast_channel_fd(chan, 0), (char*) tz) == -1) {
- ast_log(LOG_WARNING, "Unable to set tone zone %s on %s\n", tz, ast_channel_name(chan));
- return -1;
- }
+ ast_playtones_stop(chan);
return 0;
}
-int dahdi_write_wait(struct ast_channel *chan)
-{
- int res, i, flags;
-
- for (i = 0; i < 20; i++) {
- flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
- res = ioctl(ast_channel_fd(chan, 0), DAHDI_IOMUX, &flags);
- if (res) {
- ast_log(LOG_WARNING, "DAHDI_IOMUX failed: %s\n", strerror(errno));
- break;
- }
- if (flags & DAHDI_IOMUX_WRITEEMPTY) {
- break;
- }
- if (ast_safe_sleep(chan, 50)) {
- res = -1;
- break;
- }
- }
- return res;
-}
-
-int dahdi_flush(struct ast_channel *chan)
+int rpt_set_tone_zone(struct ast_channel *chan, const char *tz)
{
- int i = DAHDI_FLUSH_EVENT;
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_FLUSH, &i) == -1) {
- ast_log(LOG_ERROR, "Can't flush events on %s: %s", ast_channel_name(chan), strerror(errno));
+ struct ast_tone_zone *new_zone;
+ if (!(new_zone = ast_get_indication_zone(tz))) {
+ ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", tz);
return -1;
}
- return 0;
-}
-int dahdi_bump_buffers(struct ast_channel *chan, int samples)
-{
- struct dahdi_bufferinfo bi;
-
- /* This is a miserable kludge. For some unknown reason, which I dont have
- time to properly research, buffer settings do not get applied to dahdi
- pseudo-channels. So, if we have a need to fit more then 1 160 sample
- buffer into the psuedo-channel at a time, and there currently is not
- room, it increases the number of buffers to accommodate the larger number
- of samples (version 0.257 9/3/10) */
- memset(&bi, 0, sizeof(bi));
-
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_BUFINFO, &bi) == -1) {
- ast_log(LOG_ERROR, "Failed to get buffer info on %s: %s\n", ast_channel_name(chan), strerror(errno));
- return -1;
- }
- if (samples > bi.bufsize && (bi.numbufs < ((samples / bi.bufsize) + 1))) {
- bi.numbufs = (samples / bi.bufsize) + 1;
- if (ioctl(ast_channel_fd(chan, 0), DAHDI_SET_BUFINFO, &bi)) {
- ast_log(LOG_ERROR, "Failed to set buffer info on %s: %s\n", ast_channel_name(chan), strerror(errno));
- return -1;
- }
+ ast_channel_lock(chan);
+ if (ast_channel_zone(chan)) {
+ ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
}
+ ast_channel_zone_set(chan, ast_tone_zone_ref(new_zone));
+ ast_channel_unlock(chan);
+ new_zone = ast_tone_zone_unref(new_zone);
return 0;
}
@@ -665,4 +489,4 @@ int dahdi_set_echocancel(struct ast_channel *chan, int ec)
return -1;
}
return 0;
-}
+}
\ No newline at end of file
diff --git a/apps/app_rpt/rpt_bridging.h b/apps/app_rpt/rpt_bridging.h
index 06ae13a44..a57a95398 100644
--- a/apps/app_rpt/rpt_bridging.h
+++ b/apps/app_rpt/rpt_bridging.h
@@ -2,12 +2,17 @@
enum rpt_chan_type {
RPT_RXCHAN, /* Receive channel */
RPT_TXCHAN, /* Transmit channel */
- RPT_PCHAN,
- RPT_DAHDITXCHAN,
+ RPT_PCHAN, /* CONF to TXCONF */
+ RPT_LOCALTXCHAN,
RPT_MONCHAN, /* Monitor channel */
- RPT_PARROTCHAN,
- RPT_VOXCHAN,
RPT_TXPCHAN,
+ RPT_RXPCHAN, /* RXChannel to CONF */
+};
+
+enum rpt_bridge_chan_type {
+ RPT_LOCAL,
+ RPT_TELEMETRY,
+ RPT_MONITOR,
};
/* Each of these corresponds to a member of the rpt_conf structure in app_rpt.h */
@@ -16,19 +21,8 @@ enum rpt_conf_type {
RPT_TXCONF, /* Local Audio */
};
-/* Uses same flag name style as DAHDI_CONF flags, since that's what these are based on */
-enum rpt_conf_flags {
- RPT_CONF_NORMAL = (1 << 0),
- RPT_CONF_MONITOR = (1 << 1),
- RPT_CONF_MONITORTX = (1 << 2),
- RPT_CONF_CONF = (1 << 3),
- RPT_CONF_CONFANN = (1 << 4),
- RPT_CONF_CONFMON = (1 << 5),
- RPT_CONF_CONFANNMON = (1 << 6),
- RPT_CONF_LISTENER = (1 << 7),
- RPT_CONF_TALKER = (1 << 8),
-};
-
+#define RPT_TXCONF_NAME "TXCONF" /* TX Conference Name */
+#define RPT_CONF_NAME "CONF" /* Repeater Conference Name */
enum rpt_chan_flags {
RPT_LINK_CHAN = (1 << 0),
};
@@ -54,12 +48,16 @@ int __rpt_request(void *data, struct ast_format_cap *cap, enum rpt_chan_type cha
#define rpt_request(data, cap, chantype) __rpt_request(data, cap, chantype, 0)
/*!
- * \brief Request a pseudo channel
+ * \brief Request a Local channel
* \param cap
* \return channel on success
* \return NULL on failure
*/
-struct ast_channel *rpt_request_pseudo_chan(struct ast_format_cap *cap);
+struct ast_channel *__rpt_request_local_chan(struct ast_format_cap *cap, const char *exten, enum rpt_bridge_chan_type type);
+
+#define rpt_request_local_chan(cap, exten) __rpt_request_local_chan(cap, exten, RPT_LOCAL)
+#define rpt_request_telem_chan(cap, exten) __rpt_request_local_chan(cap, exten, RPT_TELEMETRY)
+#define rpt_request_mon_chan(cap, exten) __rpt_request_local_chan(cap, exten, RPT_MONITOR)
/*!
* \brief Request a repeater channel not associated with a real device
@@ -69,59 +67,45 @@ struct ast_channel *rpt_request_pseudo_chan(struct ast_format_cap *cap);
* \note myrpt->lock must be held when calling
* \retval 0 on success, -1 on failure
*/
-int __rpt_request_pseudo(void *data, struct ast_format_cap *cap, enum rpt_chan_type chantype, enum rpt_chan_flags flags);
-
-#define rpt_request_pseudo(data, cap, chantype) __rpt_request_pseudo(data, cap, chantype, 0)
-
-int __rpt_conf_create(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, enum rpt_conf_flags flags, const char *file, int line);
-
-int __rpt_conf_add(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, enum rpt_conf_flags flags, const char *file, int line);
-
-int rpt_equate_tx_conf(struct rpt *myrpt);
-
-#define rpt_conf_create(chan, myrpt, type, flags) __rpt_conf_create(chan, myrpt, type, flags, __FILE__, __LINE__)
-#define rpt_conf_add(chan, myrpt, type, flags) __rpt_conf_add(chan, myrpt, type, flags, __FILE__, __LINE__)
-
-#define rpt_conf_add_speaker(chan, myrpt) rpt_conf_add(chan, myrpt, RPT_CONF, RPT_CONF_CONF | RPT_CONF_LISTENER | RPT_CONF_TALKER)
+int __rpt_request_local(void *data, struct ast_format_cap *cap, enum rpt_chan_type chantype, enum rpt_chan_flags flags, const char *exten);
-#define rpt_tx_conf_add_speaker(chan, myrpt) rpt_conf_add(chan, myrpt, RPT_TXCONF, RPT_CONF_CONF | RPT_CONF_LISTENER | RPT_CONF_TALKER)
+#define rpt_request_local(data, cap, chantype, exten) __rpt_request_local(data, cap, chantype, 0, exten)
-#define rpt_conf_add_announcer(chan, myrpt) rpt_conf_add(chan, myrpt, RPT_CONF, RPT_CONF_CONFANN)
+int __rpt_conf_create(struct rpt *myrpt, enum rpt_conf_type type, const char *file, int line);
-#define rpt_conf_add_announcer_monitor(chan, myrpt) rpt_conf_add(chan, myrpt, RPT_CONF, RPT_CONF_CONFANNMON)
+int __rpt_conf_add(struct ast_channel *chan, struct rpt *myrpt, enum rpt_conf_type type, const char *file, int line);
-#define rpt_tx_conf_add_announcer(chan, myrpt) rpt_conf_add(chan, myrpt, RPT_TXCONF, RPT_CONF_CONFANN)
+#define rpt_conf_create(myrpt, type) __rpt_conf_create(myrpt, type, __FILE__, __LINE__)
+#define rpt_conf_add(chan, myrpt, type) __rpt_conf_add(chan, myrpt, type, __FILE__, __LINE__)
-/*! \note Used in app_rpt.c */
-int rpt_call_bridge_setup(struct rpt *myrpt, struct ast_channel *mychannel);
-
-/*! \note Used in app_rpt.c */
-int rpt_mon_setup(struct rpt *myrpt);
-
-/*! \note Used in app_rpt.c */
-int rpt_parrot_add(struct rpt *myrpt);
+/*!
+ * \param chan Channel to play tone on
+ * \param tone tone type (e.g., "dial", "congestion")
+ * \retval 0 on success, -1 on failure
+ */
+int rpt_play_tone(struct ast_channel *chan, const char *tone);
/*!
- * \brief Get if channel is muted in conference
+ * \brief Play congestion on a channel
* \param chan
- * \param myrpt
- * \retval 0 if not muted, 1 if muted
+ * \retval 0 on success, -1 on failure
*/
-int rpt_conf_get_muted(struct ast_channel *chan, struct rpt *myrpt);
+#define rpt_play_congestion(chan) rpt_play_tone(chan, "congestion")
/*!
* \brief Play dialtone on a channel
* \param chan
* \retval 0 on success, -1 on failure
*/
-int rpt_play_dialtone(struct ast_channel *chan);
+#define rpt_play_dialtone(chan) rpt_play_tone(chan, "dial")
/*!
- * \brief Play congestion tone on a channel
+ * \brief Get if channel is muted in conference
* \param chan
- * \retval 0 on success, -1 on failure
+ * \param myrpt
+ * \retval 0 if not muted, 1 if muted
*/
-int rpt_play_congestion(struct ast_channel *chan);
+int rpt_conf_get_muted(struct ast_channel *chan, struct rpt *myrpt);
/*!
* \brief Stop playing tones on a channel
@@ -137,31 +121,7 @@ int rpt_stop_tone(struct ast_channel *chan);
*/
int rpt_set_tone_zone(struct ast_channel *chan, const char *tz);
-/*!
- * \brief Wait for the DAHDI driver to physically write all audio to the hardware
- * \note Up to a max of 1 second
- * \note Only use with DAHDI channels!
- * \param chan
- * \retval 0 on success, -1 on failure
- */
-int dahdi_write_wait(struct ast_channel *chan);
-
-/*!
- * \brief Flush events on a DAHDI channel
- * \note Only use with DAHDI channels!
- * \param chan
- * \retval 0 on success, -1 on failure
- */
-int dahdi_flush(struct ast_channel *chan);
-
-/*!
- * \brief Increase buffer space on DAHDI channel, if needed to accommodate samples
- * \note Only use with DAHDI channels!
- * \param chan
- * \param samples
- * \retval 0 on success, -1 on failure
- */
-int dahdi_bump_buffers(struct ast_channel *chan, int samples);
+#define DEFAULT_TALKING_THRESHOLD 160 /* Bridge talking threshold - setting VOX level for when a user is indicated at "talking" */
/*!
* \brief Get value of rxisoffhook
@@ -191,4 +151,4 @@ int dahdi_set_hook(struct ast_channel *chan, int offhook);
* \param ec 0 to disable, non-zero to enable
* \retval 0 on success, -1 on failure
*/
-int dahdi_set_echocancel(struct ast_channel *chan, int ec);
+int dahdi_set_echocancel(struct ast_channel *chan, int ec);
\ No newline at end of file
diff --git a/apps/app_rpt/rpt_call.c b/apps/app_rpt/rpt_call.c
index 72e33c3c2..fc7c079fe 100644
--- a/apps/app_rpt/rpt_call.c
+++ b/apps/app_rpt/rpt_call.c
@@ -22,21 +22,58 @@
#include "asterisk/channel.h"
#include "asterisk/format_cache.h"
+#include "asterisk/core_unreal.h"
#include "app_rpt.h"
#include "rpt_call.h"
int rpt_disable_cdr(struct ast_channel *chan)
{
- if (!ast_channel_cdr(chan)) {
- ast_debug(4, "No CDR present on %s\n", ast_channel_name(chan));
+ struct ast_unreal_pvt *p;
+ int res = 0;
+
+ if (!IS_LOCAL(chan)) {
+ if (ast_channel_cdr(chan)) {
+ if (ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL)) {
+ ast_log(AST_LOG_WARNING, "Failed to disable CDR for channel %s\n", ast_channel_name(chan));
+ return -1;
+ }
+ } else {
+ ast_debug(4, "No CDR present on %s\n", ast_channel_name(chan));
+ }
return 0;
}
- if (ast_cdr_set_property(ast_channel_name(chan), AST_CDR_FLAG_DISABLE_ALL)) {
- ast_log(AST_LOG_WARNING, "Failed to disable CDR for channel %s\n", ast_channel_name(chan));
+
+ /* It's a local channel */
+ p = ast_channel_tech_pvt(chan);
+ if (!p) {
+ ast_log(AST_LOG_WARNING, "Local channel %s missing private\n", ast_channel_name(chan));
return -1;
}
- return 0;
+ ao2_lock(p);
+ if (p->owner) {
+ if (ast_channel_cdr(p->owner)) {
+ if (ast_cdr_set_property(ast_channel_name(p->owner), AST_CDR_FLAG_DISABLE_ALL)) {
+ ast_log(AST_LOG_WARNING, "Failed to disable CDR for channel %s\n", ast_channel_name(p->owner));
+ res = -1;
+ }
+ } else {
+ ast_debug(4, "No CDR present on %s\n", ast_channel_name(p->owner));
+ }
+ }
+
+ if (p->chan) {
+ if (ast_channel_cdr(p->chan)) {
+ if (ast_cdr_set_property(ast_channel_name(p->chan), AST_CDR_FLAG_DISABLE_ALL)) {
+ ast_log(AST_LOG_WARNING, "Failed to disable CDR for channel %s\n", ast_channel_name(p->chan));
+ res = -1;
+ }
+ } else {
+ ast_debug(4, "No CDR present on %s\n", ast_channel_name(p->chan));
+ }
+ }
+ ao2_unlock(p);
+ return res;
}
int rpt_setup_call(struct ast_channel *chan, const char *addr, int timeout, const char *driver, const char *data, const char *desc, const char *callerid)
diff --git a/apps/app_rpt/rpt_channel.c b/apps/app_rpt/rpt_channel.c
index 01ba3c069..1bf39bbda 100644
--- a/apps/app_rpt/rpt_channel.c
+++ b/apps/app_rpt/rpt_channel.c
@@ -54,7 +54,7 @@ int wait_interval(struct rpt *myrpt, enum rpt_delay type, struct ast_channel *ch
}
interval = get_wait_interval(myrpt, type);
- ast_debug(1, "Delay interval = %d\n", interval);
+ ast_debug(1, "Delay interval = %d on %s\n", interval, ast_channel_name(chan));
if (interval && ast_safe_sleep(chan, interval) < 0) {
return -1;
}
diff --git a/apps/app_rpt/rpt_cli.c b/apps/app_rpt/rpt_cli.c
index 7bb8e8965..1ce728434 100644
--- a/apps/app_rpt/rpt_cli.c
+++ b/apps/app_rpt/rpt_cli.c
@@ -1079,12 +1079,11 @@ static int rpt_show_channels(int fd, int argc, const char *const *argv)
DUMP_CHANNEL(rxchannel);
DUMP_CHANNEL(txchannel);
DUMP_CHANNEL(monchannel);
- DUMP_CHANNEL(parrotchannel);
DUMP_CHANNEL(pchannel);
+ DUMP_CHANNEL(rxpchannel);
DUMP_CHANNEL(txpchannel);
- DUMP_CHANNEL(dahdirxchannel);
- DUMP_CHANNEL(dahditxchannel);
- DUMP_CHANNEL(voxchannel);
+ DUMP_CHANNEL(localrxchannel);
+ DUMP_CHANNEL(localtxchannel);
rpt_mutex_unlock(&rpt_vars[this_rpt].lock);
#undef DUMP_CHANNEL
diff --git a/apps/app_rpt/rpt_functions.c b/apps/app_rpt/rpt_functions.c
index 28b30a353..b21b56b1f 100644
--- a/apps/app_rpt/rpt_functions.c
+++ b/apps/app_rpt/rpt_functions.c
@@ -835,7 +835,7 @@ enum rpt_function_response function_remote(struct rpt *myrpt, char *param, char
(!strcmp(myrpt->remoterig, REMOTE_RIG_FT100)) ||
(!strcmp(myrpt->remoterig, REMOTE_RIG_FT950)) || (!strcmp(myrpt->remoterig, REMOTE_RIG_IC706)))) {
myrpt->remotetx = 0;
- if (!IS_PSEUDO(myrpt->txchannel)) {
+ if (!IS_LOCAL(myrpt->txchannel)) {
ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
}
myrpt->tunetx = 0;
diff --git a/apps/app_rpt/rpt_link.c b/apps/app_rpt/rpt_link.c
index a8ed768a6..2a1356fc6 100644
--- a/apps/app_rpt/rpt_link.c
+++ b/apps/app_rpt/rpt_link.c
@@ -764,9 +764,9 @@ void *rpt_link_connect(void *data)
goto cleanup;
}
- rpt_make_call(l->chan, tele, 2000, deststr, "(Remote Rx)", "remote", myrpt->name);
+ rpt_make_call(l->chan, tele, 2000, deststr, "Remote Rx", "remote", myrpt->name);
- if (__rpt_request_pseudo(l, cap, RPT_PCHAN, RPT_LINK_CHAN)) {
+ if (__rpt_request_local(l, cap, RPT_PCHAN, RPT_LINK_CHAN, "IAXLink")) {
ao2_ref(cap, -1);
ast_hangup(l->chan);
l->connect_in_progress = 0;
@@ -776,8 +776,7 @@ void *rpt_link_connect(void *data)
ao2_ref(cap, -1);
- /* make a conference for the tx */
- if (rpt_conf_add_speaker(l->pchan, myrpt)) {
+ if (rpt_conf_add(l->pchan, myrpt, RPT_CONF)) {
ast_hangup(l->chan);
ast_hangup(l->pchan);
l->connect_in_progress = 0;
diff --git a/apps/app_rpt/rpt_manager.c b/apps/app_rpt/rpt_manager.c
index 43d964740..66f6f2312 100644
--- a/apps/app_rpt/rpt_manager.c
+++ b/apps/app_rpt/rpt_manager.c
@@ -279,15 +279,15 @@ static int rpt_manager_do_xstat(struct mansession *ses, const struct message *m)
/* Get variables info */
j = 0;
- if (!strcasecmp(rxchanname, "DAHDI/pseudo")) {
- /* DAHDI/pseudo isn't a real channel name, calling ast_channel_get_by_name
+ if (!strcasecmp(rxchanname, "Local/pseudo")) {
+ /* Local/pseudo isn't a real channel name, calling ast_channel_get_by_name
* will always fail, so avoid an unnecessary traversal of the channels container for nothing. */
pseudo = 1;
} else {
rxchan = ast_channel_get_by_name(rxchanname);
}
/* rxchan might've disappeared in the meantime. Verify it still exists before we try to lock it,
- * at least unless it's a DAHDI pseudo channel.
+ * at least unless it's a Local channel.
* XXX This was added to address assertions due to bad locking, but app_rpt should probably
* be globally ref'ing the channel and holding it until it unloads. Should be investigated. */
if (rxchan || pseudo) {
diff --git a/apps/app_rpt/rpt_radio.c b/apps/app_rpt/rpt_radio.c
index ef7906708..1489d3707 100644
--- a/apps/app_rpt/rpt_radio.c
+++ b/apps/app_rpt/rpt_radio.c
@@ -38,7 +38,7 @@ static int dahdi_radio_set_ctcss_decode(struct ast_channel *chan, int enable)
int rpt_radio_rx_set_ctcss_decode(struct rpt *myrpt, int enable)
{
if (CHAN_TECH(myrpt->rxchannel, "DAHDI")) {
- return dahdi_radio_set_ctcss_decode(myrpt->dahdirxchannel, enable);
+ return dahdi_radio_set_ctcss_decode(myrpt->localrxchannel, enable);
}
return 1;
}
@@ -73,33 +73,30 @@ int rpt_pciradio_serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int t
int i, index, oldmode, olddata;
struct dahdi_radio_param prm;
+ if (!myrpt->localrxchannel) {
+ return -1;
+ }
prm.radpar = DAHDI_RADPAR_UIOMODE;
- if (ioctl(ast_channel_fd(myrpt->dahdirxchannel, 0), DAHDI_RADIO_GETPARAM, &prm) == -1) {
+ if (ioctl(ast_channel_fd(myrpt->localrxchannel, 0), DAHDI_RADIO_GETPARAM, &prm) == -1) {
return -1;
}
oldmode = prm.data;
prm.radpar = DAHDI_RADPAR_UIODATA;
- if (ioctl(ast_channel_fd(myrpt->dahdirxchannel, 0), DAHDI_RADIO_GETPARAM, &prm) == -1) {
+ if (ioctl(ast_channel_fd(myrpt->localrxchannel, 0), DAHDI_RADIO_GETPARAM, &prm) == -1) {
return -1;
}
olddata = prm.data;
prm.radpar = DAHDI_RADPAR_REMMODE;
if ((asciiflag & 1) && strcmp(myrpt->remoterig, REMOTE_RIG_TM271) && strcmp(myrpt->remoterig, REMOTE_RIG_KENWOOD)) {
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_SERIAL_ASCII)) {
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_SERIAL_ASCII)) {
return -1;
}
} else {
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_SERIAL)) {
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_SERIAL)) {
return -1;
}
}
- if (asciiflag & 2) {
- if (dahdi_set_onhook(myrpt->dahdirxchannel)) {
- return -1;
- }
- usleep(100000);
- }
if ((!strcmp(myrpt->remoterig, REMOTE_RIG_TM271)) || (!strcmp(myrpt->remoterig, REMOTE_RIG_KENWOOD))) {
for (i = 0; i < txbytes - 1; i++) {
@@ -107,7 +104,7 @@ int rpt_pciradio_serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int t
prm.data = 0;
prm.buf[0] = txbuf[i];
prm.index = 1;
- if (ioctl(ast_channel_fd(myrpt->dahdirxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
+ if (ioctl(ast_channel_fd(myrpt->localrxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
return -1;
usleep(6666);
}
@@ -116,7 +113,7 @@ int rpt_pciradio_serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int t
prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
else
prm.data = DAHDI_RADPAR_REM_SERIAL;
- if (ioctl(ast_channel_fd(myrpt->dahdirxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
+ if (ioctl(ast_channel_fd(myrpt->localrxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
return -1;
prm.radpar = DAHDI_RADPAR_REMCOMMAND;
prm.data = rxmaxbytes;
@@ -128,25 +125,25 @@ int rpt_pciradio_serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int t
memcpy(prm.buf, txbuf, txbytes);
prm.index = txbytes;
}
- if (ioctl(ast_channel_fd(myrpt->dahdirxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
+ if (ioctl(ast_channel_fd(myrpt->localrxchannel, 0), DAHDI_RADIO_SETPARAM, &prm) == -1)
return -1;
if (rxbuf) {
*rxbuf = 0;
memcpy(rxbuf, prm.buf, prm.index);
}
index = prm.index;
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_NONE)) {
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_NONE)) {
return -1;
}
if (asciiflag & 2) {
- if (dahdi_set_offhook(myrpt->dahdirxchannel)) {
+ if (dahdi_set_offhook(myrpt->localrxchannel)) {
return -1;
}
}
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_UIOMODE, oldmode)) {
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_UIOMODE, oldmode)) {
return -1;
}
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_UIODATA, olddata)) {
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_UIODATA, olddata)) {
return -1;
}
return index;
diff --git a/apps/app_rpt/rpt_serial.c b/apps/app_rpt/rpt_serial.c
index 3f560f3f9..19d8d85a4 100644
--- a/apps/app_rpt/rpt_serial.c
+++ b/apps/app_rpt/rpt_serial.c
@@ -416,12 +416,15 @@ static void rbi_out_parallel(struct rpt *myrpt, unsigned char *data)
static void rbi_out(struct rpt *myrpt, unsigned char *data)
{
- if (rpt_radio_set_param(myrpt->dahdirxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_RBI1)) {
+ if (!myrpt->localrxchannel) {
+ return;
+ }
+ if (rpt_radio_set_param(myrpt->localrxchannel, RPT_RADPAR_REMMODE, RPT_RADPAR_REM_RBI1)) {
/* if setparam ioctl fails, its probably not a pciradio card */
rbi_out_parallel(myrpt, data);
return;
}
- rpt_radio_set_remcommand_data(myrpt->dahdirxchannel, data, 5);
+ rpt_radio_set_remcommand_data(myrpt->localrxchannel, data, 5);
}
int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
@@ -489,7 +492,7 @@ int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, unsig
}
/* if not a DAHDI channel, can't use pciradio stuff */
- if (myrpt->rxchannel != myrpt->dahdirxchannel) {
+ if (myrpt->rxchannel != myrpt->localrxchannel) {
return -1;
}
diff --git a/apps/app_rpt/rpt_telemetry.c b/apps/app_rpt/rpt_telemetry.c
index 92543292a..d8a02158c 100644
--- a/apps/app_rpt/rpt_telemetry.c
+++ b/apps/app_rpt/rpt_telemetry.c
@@ -686,8 +686,6 @@ static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
ast_stopstream(chan);
- /* Wait for the DAHDI driver to physically write the tone blocks to the hardware */
- res = dahdi_write_wait(chan);
return res;
}
@@ -871,9 +869,6 @@ static void handle_varcmd_tele(struct rpt *myrpt, struct ast_channel *mychannel,
return;
}
if (!strcasecmp(strs[0], "PROC")) {
- if (wait_interval(myrpt, DLY_TELEM, mychannel) == -1) {
- return;
- }
res = telem_lookup(myrpt, mychannel, "patchup", "PROC");
if (res < 0) { /* Then default message */
sayfile(mychannel, "rpt/callproceeding");
@@ -1292,32 +1287,6 @@ void *rpt_tele_thread(void *this)
ident = "";
id_malloc = 0;
}
- rpt_mutex_unlock(&myrpt->lock);
-
- cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
- if (!cap) {
- ast_log(LOG_ERROR, "Failed to alloc cap\n");
- rpt_mutex_lock(&myrpt->lock);
- goto abort2; /* Didn't set active_telem, so goto abort2, not abort. */
- }
-
- ast_format_cap_append(cap, ast_format_slin, 0);
-
- /* allocate a pseudo-channel thru asterisk */
- mychannel = rpt_request_pseudo_chan(cap);
- ao2_ref(cap, -1);
-
- if (!mychannel) {
- ast_log(LOG_WARNING, "Unable to obtain pseudo channel (mode: %d)\n", mytele->mode);
- rpt_mutex_lock(&myrpt->lock);
- goto abort2; /* Didn't set active_telem, so goto abort2, not abort. */
- }
- ast_debug(1, "Requested channel %s\n", ast_channel_name(mychannel));
-
- rpt_mutex_lock(&myrpt->lock);
- ast_channel_ref(mychannel); /* Create a reference to prevent channel from being freed too soon */
- mytele->chan = mychannel;
-
/* Wait for previous telemetry to finish before we start so we're not speaking on top of each other. */
ast_debug(5, "Queued telemetry, active_telem = %p, mytele = %p\n", myrpt->active_telem, mytele);
while (myrpt->active_telem && ((myrpt->active_telem->mode == PAGE) || (myrpt->active_telem->mode == MDC1200))) {
@@ -1341,29 +1310,49 @@ void *rpt_tele_thread(void *this)
ast_debug(5, "Beginning telemetry, active_telem = %p, mytele = %p\n", myrpt->active_telem, mytele);
- /* make a conference for the tx */
- /* If the telemetry is only intended for a local audience, only connect the ID audio to the local tx conference so linked systems can't hear it */
- /* first put the channel on the conference in announce mode */
+ cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+ if (!cap) {
+ ast_log(LOG_ERROR, "Failed to alloc cap\n");
+ rpt_mutex_lock(&myrpt->lock);
+ goto abort;
+ }
+
+ ast_format_cap_append(cap, ast_format_slin, 0);
+ /* allocate a local channel thru asterisk and call the correct conference */
+ mychannel = rpt_request_telem_chan(cap, "Telemetry");
+ ao2_ref(cap, -1);
+
+ if (!mychannel) {
+ ast_log(LOG_WARNING, "Unable to obtain local channel (mode: %d)\n", mytele->mode);
+ rpt_mutex_lock(&myrpt->lock);
+ goto abort;
+ }
+ ast_debug(1, "Requested channel %s\n", ast_channel_name(mychannel));
+ ast_channel_ref(mychannel); /* Create a reference to prevent channel from being freed too soon */
+ mytele->chan = mychannel;
+
switch (mytele->mode) {
- case ID1:
- case PLAYBACK:
- case TEST_TONE:
- case STATS_GPS_LEGACY:
- type = RPT_CONF;
- break;
- default:
- type = RPT_TXCONF;
- break;
+ case ID1:
+ case PLAYBACK:
+ case TEST_TONE:
+ case STATS_GPS_LEGACY:
+ type = RPT_CONF;
+ break;
+ default:
+ type = RPT_TXCONF;
+ break;
}
+
if (ast_audiohook_volume_set_float(mychannel, AST_AUDIOHOOK_DIRECTION_WRITE, myrpt->p.telemnomgain)) {
ast_log(LOG_WARNING, "Setting the volume on channel %s to %2.2f failed", ast_channel_name(mychannel), myrpt->p.telemnomgain);
}
- if (rpt_conf_add(mychannel, myrpt, type, RPT_CONF_CONFANN)) {
+ if (rpt_conf_add(mychannel, myrpt, type)) {
+ ast_log(LOG_WARNING, "Unable to join local channel to conference %s\n", type == RPT_CONF ? RPT_CONF_NAME : RPT_TXCONF_NAME);
rpt_mutex_lock(&myrpt->lock);
goto abort;
}
- ast_stopstream(mychannel);
+
res = 0;
switch (mytele->mode) {
case USEROUT:
@@ -1671,11 +1660,6 @@ void *rpt_tele_thread(void *this)
res = telem_send_ct(myrpt, mychannel, "unlinkedct", mytele->mode == UNKEY ? "UNKEY" : "LOCUNKEY", 0);
}
if (hasremote && ((!myrpt->cmdnode[0]) || (!strcmp(myrpt->cmdnode, "aprstt")))) {
- /* set for all to hear */
- if (rpt_conf_add_announcer(mychannel, myrpt)) {
- rpt_mutex_lock(&myrpt->lock);
- goto abort;
- }
/* Remote Unkey Courtesy Tone */
res = telem_send_ct(myrpt, mychannel, "remotect", mytele->mode == UNKEY ? "UNKEY" : "LOCUNKEY", 200);
}
@@ -1684,11 +1668,6 @@ void *rpt_tele_thread(void *this)
char mystr[10];
ast_safe_sleep(mychannel, 200);
- /* set for all to hear */
- if (rpt_tx_conf_add_announcer(mychannel, myrpt)) {
- rpt_mutex_lock(&myrpt->lock);
- goto abort;
- }
snprintf(mystr, sizeof(mystr), "%04x", myrpt->lastunit);
myrpt->lastunit = 0;
ast_say_character_str(mychannel, mystr, NULL, ast_channel_language(mychannel));
@@ -2008,21 +1987,10 @@ void *rpt_tele_thread(void *this)
res = -1;
break;
}
- if (myrpt->iofd < 0) {
- int rxisoffhook;
- if (dahdi_flush(myrpt->dahditxchannel) || ((rxisoffhook = dahdi_rx_offhook(myrpt->dahdirxchannel)) < 0)) {
- myrpt->remsetting = 0;
- ast_mutex_unlock(&myrpt->remlock);
- res = -1;
- break;
- }
- myrpt->remoterx = rxisoffhook || myrpt->tele.next != &myrpt->tele;
- }
} else if (!strcmp(myrpt->remoterig, REMOTE_RIG_TMD700)) {
res = set_tmd700(myrpt);
setxpmr(myrpt, 0);
}
-
myrpt->remsetting = 0;
ast_mutex_unlock(&myrpt->remlock);
if (!res) {
diff --git a/channels/chan_simpleusb.c b/channels/chan_simpleusb.c
index 9b9dd5c3f..85898ad57 100644
--- a/channels/chan_simpleusb.c
+++ b/channels/chan_simpleusb.c
@@ -187,6 +187,7 @@ struct chan_simpleusb_pvt {
char devicenum;
char devstr[128];
+ char serial[128];
int spkrmax;
int micmax;
int micplaymax;
@@ -791,14 +792,17 @@ static int load_tune_config(struct chan_simpleusb_pvt *o, const struct ast_confi
int opened = 0;
int configured = 0;
char devstr[sizeof(o->devstr)];
+ char serial[sizeof(o->serial)];
o->rxmixerset = 500;
o->txmixaset = 500;
o->txmixbset = 500;
devstr[0] = '\0';
+ serial[0] = '\0';
if (!reload) {
- o->devstr[0] = 0;
+ o->devstr[0] = '\0';
+ o->serial[0] = '\0';
}
if (!cfg) {
@@ -819,11 +823,13 @@ static int load_tune_config(struct chan_simpleusb_pvt *o, const struct ast_confi
CV_UINT("txmixaset", o->txmixaset);
CV_UINT("txmixbset", o->txmixbset);
CV_STR("devstr", devstr);
+ CV_STR("serial", serial);
CV_END;
}
if (!reload) {
/* Using the ternary operator in CV_STR won't work, due to butchering the sizeof, so copy after if needed */
strcpy(o->devstr, devstr); /* Safe */
+ strcpy(o->serial, serial); /* Safe */
}
if (opened) {
ast_config_destroy(cfg2);
@@ -893,6 +899,8 @@ static void *hidthread(void *arg)
* with the usb hid device
*/
while (!o->stophid) {
+ char serial[sizeof(o->serial)] = { '\0' };
+
ast_radio_time(&o->lasthidtime);
ast_mutex_lock(&usb_dev_lock);
o->hasusb = 0;
@@ -913,7 +921,37 @@ static void *hidthread(void *arg)
* found device.
*/
ast_radio_time(&o->lasthidtime);
-
+
+ /* If configuration has a serial number defined, find the device */
+ if (!ast_strlen_zero(o->serial)) {
+ int index;
+ char *index_devstr = NULL;
+
+ for (index = 0;; index++) {
+ index_devstr = ast_radio_usb_get_devstr(index);
+ if (ast_strlen_zero(index_devstr)) {
+ /* if no more devices */
+ break;
+ }
+
+ /* get the device serial number */
+ if (ast_radio_usb_get_serial(index_devstr, serial, sizeof(serial)) == 0) {
+ /* if no serial number */
+ continue;
+ }
+
+ if (strcmp(o->serial, serial) == 0) {
+ /*
+ * We found a device with the matching serial number, set
+ * the devstr to the matching device.
+ */
+ ast_log(LOG_NOTICE, "Matched device serial %s to %s\n", o->serial, o->name);
+ ast_copy_string(o->devstr, index_devstr, sizeof(o->devstr));
+ break;
+ }
+ }
+ }
+
/* Automatically assign a devstr if one was not specified in the configuration. */
if (ast_strlen_zero(o->devstr)) {
int index = 0;
@@ -943,6 +981,9 @@ static void *hidthread(void *arg)
/* We found an unused device assign it to our node */
ast_copy_string(o->devstr, index_devstr, sizeof(o->devstr));
ast_log(LOG_NOTICE, "Channel %s: Automatically assigned USB device %s to SimpleUSB channel\n", o->name, o->devstr);
+ if (ast_radio_usb_get_serial(index_devstr, serial, sizeof(serial)) > 0) {
+ ast_copy_string(o->serial, serial, sizeof(o->serial));
+ }
break;
}
if (ast_strlen_zero(o->devstr)) {
@@ -3118,6 +3159,9 @@ static void _menu_print(int fd, struct chan_simpleusb_pvt *o)
ast_cli(fd, "Active radio interface is [%s]\n", simpleusb_active);
ast_mutex_lock(&usb_dev_lock);
ast_cli(fd, "Device String is %s\n", o->devstr);
+ if (!ast_strlen_zero(o->serial)) {
+ ast_cli(fd, "Device Serial is %s\n", o->serial);
+ }
ast_mutex_unlock(&usb_dev_lock);
ast_cli(fd, "Card is %i\n", ast_radio_usb_get_usbdev(o->devstr));
ast_cli(fd, "Rx Level currently set to %d\n", o->rxmixerset);
@@ -3320,7 +3364,36 @@ static void tune_write(struct chan_simpleusb_pvt *o)
if (!category) {
ast_log(LOG_ERROR, "No category '%s' exists?\n", o->name);
} else {
- CONFIG_UPDATE_STR(devstr);
+ /*
+ * To simplify channel driver setup we allow the "devstr=" value
+ * to be empty/blank indicating that we should match the first
+ * available interface.
+ *
+ * This works (and will continue to work) well as long as the
+ * "devstr=" value in the configuration file remains empty/blank.
+ * But, if the value is ever provided then we only match interfaces
+ * with the specified string. Moving the interface (accidentally
+ * or intentionally) to a different "port" will result in not
+ * finding/matching the interface.
+ *
+ * To minimize conflicts, we want to avoid writing out the specific
+ * "devstr=" value to the configuration file unless needed. Here,
+ * we check if the current "devstr=" value is empty/blank and
+ * that there is only a single audio interface connected to the
+ * system. If so, we leave the value empty/blank.
+ */
+ const char *val;
+ char *dev;
+
+ val = ast_variable_retrieve(cfg, o->name, "devstr");
+ dev = ast_radio_usb_get_devstr(1);
+ if (!ast_strlen_zero(val) || !ast_strlen_zero(dev)) {
+ /* if the "devstr=" value exists or there is more than 1 sound device */
+ CONFIG_UPDATE_STR(devstr);
+ if (!ast_strlen_zero(o->serial)) {
+ CONFIG_UPDATE_STR(serial);
+ }
+ }
CONFIG_UPDATE_INT(rxmixerset);
CONFIG_UPDATE_INT(txmixaset);
CONFIG_UPDATE_INT(txmixbset);
diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c
index 9fc364684..0a8bfa4c0 100644
--- a/channels/chan_usbradio.c
+++ b/channels/chan_usbradio.c
@@ -203,6 +203,7 @@ struct chan_usbradio_pvt {
char devicenum;
char devstr[128];
+ char serial[128];
int spkrmax;
int micmax;
int micplaymax;
@@ -753,6 +754,7 @@ static int load_tune_config(struct chan_usbradio_pvt *o, const struct ast_config
int opened = 0;
int configured = 0;
char devstr[sizeof(o->devstr)];
+ char serial[sizeof(o->serial)];
/* No load defaults */
o->rxmixerset = 500;
@@ -764,8 +766,10 @@ static int load_tune_config(struct chan_usbradio_pvt *o, const struct ast_config
o->txslimsp = DEFAULT_TX_SOFT_LIMITER_SETPOINT;
devstr[0] = '\0';
+ serial[0] = '\0';
if (!reload) {
o->devstr[0] = 0;
+ o->serial[0] = 0;
}
if (!cfg) {
@@ -791,11 +795,13 @@ static int load_tune_config(struct chan_usbradio_pvt *o, const struct ast_config
CV_UINT("txslimsp", o->txslimsp);
CV_UINT("fever", o->fever);
CV_STR("devstr", devstr);
+ CV_STR("serial", serial);
CV_END;
}
if (!reload) {
/* Using the ternary operator in CV_STR won't work, due to butchering the sizeof, so copy after if needed */
strcpy(o->devstr, devstr); /* Safe */
+ strcpy(o->serial, serial); /* Safe */
}
if (opened) {
ast_config_destroy(cfg2);
@@ -865,6 +871,8 @@ static void *hidthread(void *arg)
* with the usb hid device
*/
while (!o->stophid) {
+ char serial[sizeof(o->serial)] = { '\0' };
+
ast_radio_time(&o->lasthidtime);
ast_mutex_lock(&usb_dev_lock);
o->hasusb = 0;
@@ -886,6 +894,36 @@ static void *hidthread(void *arg)
*/
ast_radio_time(&o->lasthidtime);
+ /* If configuration has a serial number defined, find the device */
+ if (!ast_strlen_zero(o->serial)) {
+ int index;
+ char *index_devstr = NULL;
+
+ for (index = 0;; index++) {
+ index_devstr = ast_radio_usb_get_devstr(index);
+ if (ast_strlen_zero(index_devstr)) {
+ /* if no more devices */
+ break;
+ }
+
+ /* get the device serial number */
+ if (ast_radio_usb_get_serial(index_devstr, serial, sizeof(serial)) == 0) {
+ /* if no serial number */
+ continue;
+ }
+
+ if (strcmp(o->serial, serial) == 0) {
+ /*
+ * We found a device with the matching serial number, set
+ * the devstr to the matching device.
+ */
+ ast_log(LOG_NOTICE, "Matched device serial %s to %s\n", o->serial, o->name);
+ ast_copy_string(o->devstr, index_devstr, sizeof(o->devstr));
+ break;
+ }
+ }
+ }
+
/* Automatically assign a devstr if one was not specified in the configuration. */
if (ast_strlen_zero(o->devstr)) {
int index = 0;
@@ -915,6 +953,9 @@ static void *hidthread(void *arg)
/* We found an unused device assign it to our node */
ast_copy_string(o->devstr, index_devstr, sizeof(o->devstr));
ast_log(LOG_NOTICE, "Channel %s: Automatically assigned USB device %s to USBRadio channel\n", o->name, o->devstr);
+ if (ast_radio_usb_get_serial(index_devstr, serial, sizeof(serial)) > 0) {
+ ast_copy_string(o->serial, serial, sizeof(o->serial));
+ }
break;
}
if (ast_strlen_zero(o->devstr)) {
@@ -3648,6 +3689,9 @@ static void _menu_print(int fd, struct chan_usbradio_pvt *o)
ast_cli(fd, "Active radio interface is [%s]\n", usbradio_active);
ast_mutex_lock(&usb_dev_lock);
ast_cli(fd, "Device String is %s\n", o->devstr);
+ if (!ast_strlen_zero(o->serial)) {
+ ast_cli(fd, "Device Serial is %s\n", o->serial);
+ }
ast_mutex_unlock(&usb_dev_lock);
ast_cli(fd, "Card is %i\n", ast_radio_usb_get_usbdev(o->devstr));
ast_cli(fd, "Output A is currently set to ");
@@ -4512,7 +4556,36 @@ static void tune_write(struct chan_usbradio_pvt *o)
if (!category) {
ast_log(LOG_ERROR, "No category '%s' exists?\n", o->name);
} else {
- CONFIG_UPDATE_STR(devstr);
+ /*
+ * To simplify channel driver setup we allow the "devstr=" value
+ * to be empty/blank indicating that we should match the first
+ * available interface.
+ *
+ * This works (and will continue to work) well as long as the
+ * "devstr=" value in the configuration file remains empty/blank.
+ * But, if the value is ever provided then we only match interfaces
+ * with the specified string. Moving the interface (accidentally
+ * or intentionally) to a different "port" will result in not
+ * finding/matching the interface.
+ *
+ * To minimize conflicts, we want to avoid writing out the specific
+ * "devstr=" value to the configuration file unless needed. Here,
+ * we check if the current "devstr=" value is empty/blank and
+ * that there is only a single audio interface connected to the
+ * system. If so, we leave the value empty/blank.
+ */
+ const char *val;
+ char *dev;
+
+ val = ast_variable_retrieve(cfg, o->name, "devstr");
+ dev = ast_radio_usb_get_devstr(1);
+ if (!ast_strlen_zero(val) || !ast_strlen_zero(dev)) {
+ /* if the "devstr=" value exists or there is more than 1 sound device */
+ CONFIG_UPDATE_STR(devstr);
+ if (!ast_strlen_zero(o->serial)) {
+ CONFIG_UPDATE_STR(serial);
+ }
+ }
CONFIG_UPDATE_INT(rxmixerset);
CONFIG_UPDATE_INT(txmixaset);
CONFIG_UPDATE_INT(txmixbset);
diff --git a/configs/rpt/extensions.conf b/configs/rpt/extensions.conf
index 7f8a724ba..fef6ba820 100644
--- a/configs/rpt/extensions.conf
+++ b/configs/rpt/extensions.conf
@@ -67,12 +67,14 @@ exten => ${NODE},1,Ringing()
; Comment-out the following clause if you want Allstar Autopatch service
[pstn-out]
-exten => _NXXNXXXXXX,1,playback(ss-noservice)
- same => n,Congestion
+exten => _NXXNXXXXXX,1,Wait(1)
+ same => n,Playback(ss-noservice)
+ same => n,Hangup
; Un-comment out the following clause if you want Allstar Autopatch service
;[pstn-out]
-;exten => _NXXNXXXXXX,1,Dial(IAX2/allstar-autopatch/\${EXTEN})
+;exten => _NXXNXXXXXX,1,Wait(1)
+; same => n, Dial(IAX2/allstar-autopatch/\${EXTEN})
; same => n,Busy
[invalidnum]
diff --git a/configs/rpt/modules.conf b/configs/rpt/modules.conf
index 87a224e68..d4e68dfa5 100644
--- a/configs/rpt/modules.conf
+++ b/configs/rpt/modules.conf
@@ -41,9 +41,14 @@ load = app_sendtext.so ; Send and Receive Text Applications
load = app_system.so ; Generic System() application
load = app_transfer.so ; Transfers a caller to another extension
+; Bridging
+
+require = bridge_softmix.so ; Multi-party software based channel mixing
+
; Channel Drivers
-load = chan_dahdi.so ; DAHDI Telephony w/PRI & SS7 & MFC/R2
+require = chan_bridge_media.so ; Bridge Media Channel Driver
+noload = chan_dahdi.so ; DAHDI Telephony w/PRI & SS7 & MFC/R2
noload = chan_echolink.so ; Echolink Channel Driver
require = chan_iax2.so ; Inter Asterisk eXchange (Ver 2)
noload = chan_mobile.so ; Bluetooth Mobile Device Channel Driver
@@ -121,7 +126,7 @@ load = pbx_config.so ; Text Extension Configuration
load = res_crypto.so ; Cryptographic Digital Signatures
require = res_curl.so ; cURL Resource Module
require = res_rpt_http_registrations.so ; RPT HTTP Periodic Registrations
-load = res_timing_dahdi.so ; DAHDI Timing Interface
+noload = res_timing_dahdi.so ; DAHDI Timing Interface
load = res_timing_timerfd.so ; Timerfd Timing Interface is preferred for ASL3
require = res_usbradio.so ; USB Radio Resource
@@ -135,8 +140,6 @@ require = res_usbradio.so ; USB Radio Resource
;load = bridge_holding.so ; Holding bridge module
;load = bridge_native_rtp.so ; Native RTP bridging module
;load = bridge_simple.so ; Simple two channel bridging module
-;load = bridge_softmix.so ; Multi-party software based channel mixing
-;load = chan_bridge_media.so ; Bridge Media Channel Driver
;load = chan_pjsip.so ; PJSIP Channel Driver
;load = func_pjsip_endpoint.so ; Get information about a PJSIP endpoint
;load = func_sorcery.so ; Get a field from a sorcery object
diff --git a/configs/rpt/rpt.conf b/configs/rpt/rpt.conf
index 64ec6c209..29a2b5866 100644
--- a/configs/rpt/rpt.conf
+++ b/configs/rpt/rpt.conf
@@ -65,13 +65,13 @@ node_lookup_method = dns ;method used to lookup nodes
; Must also be enabled in modules.conf
; Enable the selected channel driver in modules.conf !!!
; Rx/Tx audio/signaling channel. Choose ONLY 1 per node stanza.
-; rxchannel = dahdi/pseudo ; No radio (hub)
+; rxchannel = Local/pseudo ; No radio (hub)
; rxchannel = SimpleUSB/1999 ; SimpleUSB
; rxchannel = Radio/1999 ; USBRadio (DSP)
; rxchannel = Voter/1999 ; RTCM device
; rxchannel = USRP/127.0.0.1:34001:32001 ;GNU Radio interface USRP
-rxchannel = dahdi/pseudo ; No radio (hub)
+rxchannel = Local/pseudo ; No radio (hub)
duplex = 2 ; 0 = Half duplex with no telemetry tones or hang time.
; Special Case: Full duplex if linktolink is set to yes.
diff --git a/configs/rpt/simpleusb.conf b/configs/rpt/simpleusb.conf
index 8847962f6..32dce21f4 100644
--- a/configs/rpt/simpleusb.conf
+++ b/configs/rpt/simpleusb.conf
@@ -133,7 +133,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample sc
; place settings that are different than the template.
;
; Note: the device string is automatically found when the
-; USB setting "devstr=" is empty.
+; USB setting "devstr=" and "serial=" are both empty.
;
; Note: the interface "tune" settings will be added to the
; per-node settings (below).
@@ -142,6 +142,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample sc
;;;;; ASL3 Tune settings ;;;;;
devstr=
+serial=
rxmixerset=500
txmixaset=500
txmixbset=500
diff --git a/configs/rpt/usbradio.conf b/configs/rpt/usbradio.conf
index a9e1e658d..faba981d7 100644
--- a/configs/rpt/usbradio.conf
+++ b/configs/rpt/usbradio.conf
@@ -196,7 +196,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample scaling an
; place settings that are different than the template.
;
; Note: the device string is automatically found when the
-; USB setting "devstr=" is empty.
+; USB setting "devstr=" and "serial=" are both empty.
;
; Note: the interface "tune" settings will be added to the
; per-node settings (below).
@@ -205,6 +205,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample scaling an
;;;;; ASL3 Tune settings ;;;;;
devstr=
+serial=
rxmixerset=500
txmixaset=500
txmixbset=500
diff --git a/configs/samples/simpleusb.conf.sample b/configs/samples/simpleusb.conf.sample
index ba4dbd7fe..5edea68e7 100644
--- a/configs/samples/simpleusb.conf.sample
+++ b/configs/samples/simpleusb.conf.sample
@@ -116,6 +116,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample scaling an
;;;;; Tune settings ;;;;;
;devstr=
+;serial=
;rxmixerset=500
;txmixaset=500
;txmixbset=500
diff --git a/configs/samples/usbradio.conf.sample b/configs/samples/usbradio.conf.sample
index 03a092849..cff9c8260 100644
--- a/configs/samples/usbradio.conf.sample
+++ b/configs/samples/usbradio.conf.sample
@@ -184,6 +184,7 @@ legacyaudioscaling = no ; If yes, continue to do raw audio sample scaling an
;;;;; Tune settings ;;;;;
;devstr=
+;serial=
;rxmixerset=500
;txmixaset=500
;txmixbset=500
diff --git a/include/asterisk/res_usbradio.h b/include/asterisk/res_usbradio.h
index 6cf4bffee..a3a3fff32 100644
--- a/include/asterisk/res_usbradio.h
+++ b/include/asterisk/res_usbradio.h
@@ -346,6 +346,17 @@ struct usb_device *ast_radio_hid_device_init(const char *desired_device);
*/
int ast_radio_usb_get_usbdev(const char *devstr);
+/*!
+ * \brief Get serial number from device if available
+ * This function will attempt to get the serial number from a media device
+ *
+ * \param devstr The USB device string
+ * \param buf Pointer to buffer for serial number
+ * \param buflen Length of the serial number buffer
+ * \retval Length of returned serial number; 0 if no serial
+ */
+int ast_radio_usb_get_serial(const char *devstr, char *buf, size_t buflen);
+
/*!
* \brief See if the internal usb_device_list contains the
* specified device string.
diff --git a/res/res_usbradio.c b/res/res_usbradio.c
index 225e4d14f..0243f3fe2 100644
--- a/res/res_usbradio.c
+++ b/res/res_usbradio.c
@@ -598,6 +598,38 @@ int ast_radio_usb_get_usbdev(const char *devstr)
return i;
}
+/*!
+ * \brief Get serial number from device if available
+ * This function will attempt to get the serial number from a media device
+ *
+ * \param devstr The USB device string
+ * \param buf Pointer to buffer for serial number
+ * \param buflen Length of the serial number buffer
+ * \retval Length of returned serial number; 0 if no serial
+ */
+int ast_radio_usb_get_serial(const char *devstr, char *buf, size_t buflen)
+{
+ struct usb_device *usb_dev;
+ struct usb_dev_handle *usb_handle;
+ int length = 0;
+
+ usb_dev = ast_radio_hid_device_init(devstr);
+ if (!usb_dev) {
+ return 0;
+ }
+
+ if (usb_dev->descriptor.iSerialNumber) {
+ usb_handle = usb_open(usb_dev);
+ if (!usb_handle) {
+ return 0;
+ }
+ length = usb_get_string_simple(usb_handle, usb_dev->descriptor.iSerialNumber, buf, buflen);
+ usb_close(usb_handle);
+ }
+
+ return length;
+}
+
int ast_radio_usb_list_check(char *devstr)
{
/* See usb_device_list definition for the format */