📄 chan_h323.c
字号:
cd->redirect_number = NULL; }}static void __oh323_destroy(struct oh323_pvt *pvt){ struct oh323_pvt *cur, *prev = NULL; AST_SCHED_DEL(sched, pvt->DTMFsched); if (pvt->rtp) { ast_rtp_destroy(pvt->rtp); } /* Free dsp used for in-band DTMF detection */ if (pvt->vad) { ast_dsp_free(pvt->vad); } cleanup_call_details(&pvt->cd); /* Unlink us from the owner if we have one */ if (pvt->owner) { ast_channel_lock(pvt->owner); if (h323debug) ast_log(LOG_DEBUG, "Detaching from %s\n", pvt->owner->name); pvt->owner->tech_pvt = NULL; ast_channel_unlock(pvt->owner); } cur = iflist; while(cur) { if (cur == pvt) { if (prev) prev->next = cur->next; else iflist = cur->next; break; } prev = cur; cur = cur->next; } if (!cur) { ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur); } else { ast_mutex_unlock(&pvt->lock); ast_mutex_destroy(&pvt->lock); free(pvt); }}static void oh323_destroy(struct oh323_pvt *pvt){ if (h323debug) { ast_log(LOG_DEBUG, "Destroying channel %s\n", (pvt->owner ? pvt->owner->name : "<unknown>")); } ast_mutex_lock(&iflock); ast_mutex_lock(&pvt->lock); __oh323_destroy(pvt); ast_mutex_unlock(&iflock);}static int oh323_digit_begin(struct ast_channel *c, char digit){ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; char *token; if (!pvt) { ast_log(LOG_ERROR, "No private structure?! This is bad\n"); return -1; } ast_mutex_lock(&pvt->lock); if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) { /* out-of-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "Begin sending out-of-band digit %c on %s\n", digit, c->name); } ast_rtp_senddigit_begin(pvt->rtp, digit); ast_mutex_unlock(&pvt->lock); } else if (pvt->txDtmfDigit != digit) { /* in-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "Begin sending inband digit %c on %s\n", digit, c->name); } pvt->txDtmfDigit = digit; token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL; ast_mutex_unlock(&pvt->lock); h323_send_tone(token, digit); if (token) { free(token); } } else ast_mutex_unlock(&pvt->lock); oh323_update_info(c); return 0;}/** * Send (play) the specified digit to the channel. * */static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration){ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; char *token; if (!pvt) { ast_log(LOG_ERROR, "No private structure?! This is bad\n"); return -1; } ast_mutex_lock(&pvt->lock); if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && (pvt->dtmf_pt > 0)) { /* out-of-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "End sending out-of-band digit %c on %s, duration %d\n", digit, c->name, duration); } ast_rtp_senddigit_end(pvt->rtp, digit); ast_mutex_unlock(&pvt->lock); } else { /* in-band DTMF */ if (h323debug) { ast_log(LOG_DTMF, "End sending inband digit %c on %s, duration %d\n", digit, c->name, duration); } pvt->txDtmfDigit = ' '; token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL; ast_mutex_unlock(&pvt->lock); h323_send_tone(token, ' '); if (token) { free(token); } } oh323_update_info(c); return 0;}/** * Make a call over the specified channel to the specified * destination. * Returns -1 on error, 0 on success. */static int oh323_call(struct ast_channel *c, char *dest, int timeout){ int res = 0; struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt; const char *addr; char called_addr[1024]; if (h323debug) { ast_log(LOG_DEBUG, "Calling to %s on %s\n", dest, c->name); } if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name); return -1; } ast_mutex_lock(&pvt->lock); if (!gatekeeper_disable) { if (ast_strlen_zero(pvt->exten)) { ast_copy_string(called_addr, dest, sizeof(called_addr)); } else { snprintf(called_addr, sizeof(called_addr), "%s@%s", pvt->exten, dest); } } else { res = htons(pvt->sa.sin_port); addr = ast_inet_ntoa(pvt->sa.sin_addr); if (ast_strlen_zero(pvt->exten)) { snprintf(called_addr, sizeof(called_addr), "%s:%d", addr, res); } else { snprintf(called_addr, sizeof(called_addr), "%s@%s:%d", pvt->exten, addr, res); } } /* make sure null terminated */ called_addr[sizeof(called_addr) - 1] = '\0'; if (c->cid.cid_num) ast_copy_string(pvt->options.cid_num, c->cid.cid_num, sizeof(pvt->options.cid_num)); if (c->cid.cid_name) ast_copy_string(pvt->options.cid_name, c->cid.cid_name, sizeof(pvt->options.cid_name)); if (c->cid.cid_rdnis) { ast_copy_string(pvt->options.cid_rdnis, c->cid.cid_rdnis, sizeof(pvt->options.cid_rdnis)); } pvt->options.presentation = c->cid.cid_pres; pvt->options.type_of_number = c->cid.cid_ton; if ((addr = pbx_builtin_getvar_helper(c, "PRIREDIRECTREASON"))) { if (!strcasecmp(addr, "UNKNOWN")) pvt->options.redirect_reason = 0; else if (!strcasecmp(addr, "BUSY")) pvt->options.redirect_reason = 1; else if (!strcasecmp(addr, "NO_REPLY")) pvt->options.redirect_reason = 2; else if (!strcasecmp(addr, "UNCONDITIONAL")) pvt->options.redirect_reason = 15; else pvt->options.redirect_reason = -1; } else pvt->options.redirect_reason = -1; pvt->options.transfer_capability = c->transfercapability; /* indicate that this is an outgoing call */ pvt->outgoing = 1; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Requested transfer capability: 0x%.2x - %s\n", c->transfercapability, ast_transfercapability2str(c->transfercapability)); if (h323debug) ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec); ast_mutex_unlock(&pvt->lock); res = h323_make_call(called_addr, &(pvt->cd), &pvt->options); if (res) { ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name); return -1; } oh323_update_info(c); return 0;}static int oh323_answer(struct ast_channel *c){ int res; struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; char *token; if (h323debug) ast_log(LOG_DEBUG, "Answering on %s\n", c->name); ast_mutex_lock(&pvt->lock); token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL; ast_mutex_unlock(&pvt->lock); res = h323_answering_call(token, 0); if (token) free(token); oh323_update_info(c); if (c->_state != AST_STATE_UP) { ast_setstate(c, AST_STATE_UP); } return res;}static int oh323_hangup(struct ast_channel *c){ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; int q931cause = AST_CAUSE_NORMAL_CLEARING; char *call_token; if (h323debug) ast_log(LOG_DEBUG, "Hanging up and scheduling destroy of call %s\n", c->name); if (!c->tech_pvt) { ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); return 0; } ast_mutex_lock(&pvt->lock); /* Determine how to disconnect */ if (pvt->owner != c) { ast_log(LOG_WARNING, "Huh? We aren't the owner?\n"); ast_mutex_unlock(&pvt->lock); return 0; } pvt->owner = NULL; c->tech_pvt = NULL; if (c->hangupcause) { q931cause = c->hangupcause; } else { const char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS"); if (cause) { if (!strcmp(cause, "CONGESTION")) { q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; } else if (!strcmp(cause, "BUSY")) { q931cause = AST_CAUSE_USER_BUSY; } else if (!strcmp(cause, "CHANISUNVAIL")) { q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; } else if (!strcmp(cause, "NOANSWER")) { q931cause = AST_CAUSE_NO_ANSWER; } else if (!strcmp(cause, "CANCEL")) { q931cause = AST_CAUSE_CALL_REJECTED; } } } /* Start the process if it's not already started */ if (!pvt->alreadygone && !pvt->hangupcause) { call_token = pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL; if (call_token) { /* Release lock to eliminate deadlock */ ast_mutex_unlock(&pvt->lock); if (h323_clear_call(call_token, q931cause)) { ast_log(LOG_WARNING, "ClearCall failed.\n"); } free(call_token); ast_mutex_lock(&pvt->lock); } } pvt->needdestroy = 1; ast_mutex_unlock(&pvt->lock); /* Update usage counter */ ast_module_unref(ast_module_info->self); return 0;}static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt){ /* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */ struct ast_frame *f; /* Only apply it for the first packet, we just need the correct ip/port */ if (pvt->options.nat) { ast_rtp_setnat(pvt->rtp, pvt->options.nat); pvt->options.nat = 0; } f = ast_rtp_read(pvt->rtp); /* Don't send RFC2833 if we're not supposed to */ if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & H323_DTMF_RFC2833)) { return &ast_null_frame; } if (pvt->owner) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { if (f->subclass != pvt->owner->nativeformats) { /* Try to avoid deadlock */ if (ast_channel_trylock(pvt->owner)) { ast_log(LOG_NOTICE, "Format changed but channel is locked. Ignoring frame...\n"); return &ast_null_frame; } if (h323debug) ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass); pvt->owner->nativeformats = f->subclass; pvt->nativeformats = f->subclass; ast_set_read_format(pvt->owner, pvt->owner->readformat); ast_set_write_format(pvt->owner, pvt->owner->writeformat); ast_channel_unlock(pvt->owner); } /* Do in-band DTMF detection */ if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) { if ((pvt->nativeformats & (AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW))) { if (!ast_channel_trylock(pvt->owner)) { f = ast_dsp_process(pvt->owner, pvt->vad, f); ast_channel_unlock(pvt->owner); } else ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n"); } else if (pvt->nativeformats && !pvt->noInbandDtmf) { ast_log(LOG_NOTICE, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(f->subclass)); pvt->noInbandDtmf = 1; } if (f &&(f->frametype == AST_FRAME_DTMF)) { if (h323debug) ast_log(LOG_DTMF, "Received in-band digit %c.\n", f->subclass); } } } } return f;}static struct ast_frame *oh323_read(struct ast_channel *c){ struct ast_frame *fr; struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt; ast_mutex_lock(&pvt->lock); __oh323_update_info(c, pvt); switch(c->fdno) { case 0: fr = oh323_rtp_read(pvt); break; case 1: if (pvt->rtp) fr = ast_rtcp_read(pvt->rtp); else fr = &ast_null_frame; break; default: ast_log(LOG_ERROR, "Unable to handle fd %d on channel %s\n", c->fdno, c->name); fr = &ast_null_frame; break; } ast_mutex_unlock(&pvt->lock); return fr;}static int oh323_write(struct ast_channel *c, struct ast_frame *frame){ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; int res = 0; if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype == AST_FRAME_IMAGE) { return 0; } else { ast_log(LOG_WARNING, "Can't send %d type frames with H323 write\n", frame->frametype); return 0; } } else { if (!(frame->subclass & c->nativeformats)) { ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", frame->subclass, c->nativeformats, c->readformat, c->writeformat); return 0; } } if (pvt) { ast_mutex_lock(&pvt->lock); if (pvt->rtp && !pvt->recvonly) res = ast_rtp_write(pvt->rtp, frame); __oh323_update_info(c, pvt); ast_mutex_unlock(&pvt->lock); } return res;}static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen){ struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; char *token = (char *)NULL; int res = -1; int got_progress; ast_mutex_lock(&pvt->lock); token = (pvt->cd.call_token ? strdup(pvt->cd.call_token) : NULL); got_progress = pvt->got_progress; if (condition == AST_CONTROL_PROGRESS) pvt->got_progress = 1; else if ((condition == AST_CONTROL_BUSY) || (condition == AST_CONTROL_CONGESTION)) pvt->alreadygone = 1; ast_mutex_unlock(&pvt->lock); if (h323debug) ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, token); switch(condition) { case AST_CONTROL_RINGING: if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) { h323_send_alerting(token); res = (got_progress ? 0 : -1); /* Do not simulate any audio tones if we got PROGRESS message */ } break; case AST_CONTROL_PROGRESS: if (c->_state != AST_STATE_UP) { /* Do not send PROGRESS message more than once */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -