📄 chan_h323.c
字号:
pvt = find_call_locked(call_reference, token); if (!pvt) { ast_log(LOG_ERROR, "Received digit '%c' (%u ms) for call %s without private structure\n", digit, duration, token); return -1; } if (h323debug) ast_log(LOG_DTMF, "Received %s digit '%c' (%u ms) for call %s\n", (digit == ' ' ? "update for" : "new"), (digit == ' ' ? pvt->curDTMF : digit), duration, token); if (pvt->owner && !ast_channel_trylock(pvt->owner)) { if (digit == '!') res = ast_queue_control(pvt->owner, AST_CONTROL_FLASH); else { struct ast_frame f = { .frametype = AST_FRAME_DTMF_END, .subclass = digit, .samples = duration * 8, .len = duration, .src = "SEND_DIGIT", }; if (digit == ' ') { /* signalUpdate message */ f.subclass = pvt->curDTMF; AST_SCHED_DEL(sched, pvt->DTMFsched); } else { /* Regular input or signal message */ if (pvt->DTMFsched >= 0) { /* We still don't send DTMF END from previous event, send it now */ AST_SCHED_DEL(sched, pvt->DTMFsched); f.subclass = pvt->curDTMF; f.samples = f.len = 0; ast_queue_frame(pvt->owner, &f); /* Restore values */ f.subclass = digit; f.samples = duration * 8; f.len = duration; } if (duration) { /* This is a signal, signalUpdate follows */ f.frametype = AST_FRAME_DTMF_BEGIN; pvt->DTMFsched = ast_sched_add(sched, duration, oh323_simulate_dtmf_end, pvt); if (h323debug) ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", duration, pvt->DTMFsched); } pvt->curDTMF = digit; } res = ast_queue_frame(pvt->owner, &f); } ast_channel_unlock(pvt->owner); } else { if (digit == '!') pvt->newcontrol = AST_CONTROL_FLASH; else { pvt->newduration = duration; pvt->newdigit = digit; } res = 0; } ast_mutex_unlock(&pvt->lock); return res;}/** * Callback function used to inform the H.323 stack of the local rtp ip/port details * * Returns the local RTP information */static struct rtp_info *external_rtp_create(unsigned call_reference, const char * token){ struct oh323_pvt *pvt; struct sockaddr_in us; struct rtp_info *info; info = (struct rtp_info *)malloc(sizeof(struct rtp_info)); if (!info) { ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n"); return NULL; } pvt = find_call_locked(call_reference, token); if (!pvt) { free(info); ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference); return NULL; } if (!pvt->rtp) __oh323_rtp_create(pvt); if (!pvt->rtp) { ast_mutex_unlock(&pvt->lock); free(info); ast_log(LOG_ERROR, "No RTP stream is available for call %s (%d)", token, call_reference); return NULL; } /* figure out our local RTP port and tell the H.323 stack about it */ ast_rtp_get_us(pvt->rtp, &us); ast_mutex_unlock(&pvt->lock); ast_copy_string(info->addr, ast_inet_ntoa(us.sin_addr), sizeof(info->addr)); info->port = ntohs(us.sin_port); if (h323debug) ast_log(LOG_DEBUG, "Sending RTP 'US' %s:%d\n", info->addr, info->port); return info;}/** * Definition taken from rtp.c for rtpPayloadType because we need it here. */struct rtpPayloadType { int isAstFormat; /* whether the following code is an AST_FORMAT */ int code;};/** * Call-back function passing remote ip/port information from H.323 to asterisk * * Returns nothing */static void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt){ struct oh323_pvt *pvt; struct sockaddr_in them; struct rtpPayloadType rtptype; int nativeformats_changed; enum { NEED_NONE, NEED_HOLD, NEED_UNHOLD } rtp_change = NEED_NONE; if (h323debug) ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token); /* Find the call or allocate a private structure if call not found */ pvt = find_call_locked(call_reference, token); if (!pvt) { ast_log(LOG_ERROR, "Something is wrong: rtp\n"); return; } if (pvt->alreadygone) { ast_mutex_unlock(&pvt->lock); return; } if (!pvt->rtp) __oh323_rtp_create(pvt); them.sin_family = AF_INET; /* only works for IPv4 */ them.sin_addr.s_addr = inet_addr(remoteIp); them.sin_port = htons(remotePort); if (them.sin_addr.s_addr) { ast_rtp_set_peer(pvt->rtp, &them); if (pvt->recvonly) { pvt->recvonly = 0; rtp_change = NEED_UNHOLD; } } else { ast_rtp_stop(pvt->rtp); if (!pvt->recvonly) { pvt->recvonly = 1; rtp_change = NEED_HOLD; } } /* Change native format to reflect information taken from OLC/OLCAck */ nativeformats_changed = 0; if (pt != 128 && pvt->rtp) { /* Payload type is invalid, so try to use previously decided */ rtptype = ast_rtp_lookup_pt(pvt->rtp, pt); if (h323debug) ast_log(LOG_DEBUG, "Native format is set to %d from %d by RTP payload type %d\n", rtptype.code, pvt->nativeformats, pt); if (pvt->nativeformats != rtptype.code) { pvt->nativeformats = rtptype.code; nativeformats_changed = 1; } } else if (h323debug) ast_log(LOG_NOTICE, "Payload type is unknown, formats isn't changed\n"); /* Don't try to lock the channel if nothing changed */ if (nativeformats_changed || pvt->options.progress_audio || (rtp_change != NEED_NONE)) { if (pvt->owner && !ast_channel_trylock(pvt->owner)) { /* Re-build translation path only if native format(s) has been changed */ if (pvt->owner->nativeformats != pvt->nativeformats) { if (h323debug) ast_log(LOG_DEBUG, "Native format changed to %d from %d, read format is %d, write format is %d\n", pvt->nativeformats, pvt->owner->nativeformats, pvt->owner->readformat, pvt->owner->writeformat); pvt->owner->nativeformats = pvt->nativeformats; ast_set_read_format(pvt->owner, pvt->owner->readformat); ast_set_write_format(pvt->owner, pvt->owner->writeformat); } if (pvt->options.progress_audio) ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS); switch (rtp_change) { case NEED_HOLD: ast_queue_control(pvt->owner, AST_CONTROL_HOLD); break; case NEED_UNHOLD: ast_queue_control(pvt->owner, AST_CONTROL_UNHOLD); break; default: break; } ast_channel_unlock(pvt->owner); } else { if (pvt->options.progress_audio) pvt->newcontrol = AST_CONTROL_PROGRESS; else if (rtp_change == NEED_HOLD) pvt->newcontrol = AST_CONTROL_HOLD; else if (rtp_change == NEED_UNHOLD) pvt->newcontrol = AST_CONTROL_UNHOLD; if (h323debug) ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token); } } ast_mutex_unlock(&pvt->lock); if (h323debug) ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token); return;}/** * Call-back function to signal asterisk that the channel has been answered * Returns nothing */static void connection_made(unsigned call_reference, const char *token){ struct oh323_pvt *pvt; if (h323debug) ast_log(LOG_DEBUG, "Call %s answered\n", token); pvt = find_call_locked(call_reference, token); if (!pvt) { ast_log(LOG_ERROR, "Something is wrong: connection\n"); return; } /* Inform asterisk about remote party connected only on outgoing calls */ if (!pvt->outgoing) { ast_mutex_unlock(&pvt->lock); return; } /* Do not send ANSWER message more than once */ if (!pvt->connection_established) { pvt->connection_established = 1; update_state(pvt, -1, AST_CONTROL_ANSWER); } ast_mutex_unlock(&pvt->lock); return;}static int progress(unsigned call_reference, const char *token, int inband){ struct oh323_pvt *pvt; if (h323debug) ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated")); pvt = find_call_locked(call_reference, token); if (!pvt) { ast_log(LOG_ERROR, "Private structure not found in progress.\n"); return -1; } if (!pvt->owner) { ast_mutex_unlock(&pvt->lock); ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n"); return -1; } update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)); ast_mutex_unlock(&pvt->lock); return 0;}/** * Call-back function for incoming calls * * Returns 1 on success */static call_options_t *setup_incoming_call(call_details_t *cd){ struct oh323_pvt *pvt; struct oh323_user *user = NULL; struct oh323_alias *alias = NULL; if (h323debug) ast_log(LOG_DEBUG, "Setting up incoming call for %s\n", cd->call_token); /* allocate the call*/ pvt = oh323_alloc(cd->call_reference); if (!pvt) { ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n"); cleanup_call_details(cd); return NULL; } /* Populate the call details in the private structure */ memcpy(&pvt->cd, cd, sizeof(pvt->cd)); memcpy(&pvt->options, &global_options, sizeof(pvt->options)); pvt->jointcapability = pvt->options.capability; if (h323debug) { ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n"); ast_verbose(VERBOSE_PREFIX_3 " \tCall token: [%s]\n", pvt->cd.call_token); ast_verbose(VERBOSE_PREFIX_3 " \tCalling party name: [%s]\n", pvt->cd.call_source_name); ast_verbose(VERBOSE_PREFIX_3 " \tCalling party number: [%s]\n", pvt->cd.call_source_e164); ast_verbose(VERBOSE_PREFIX_3 " \tCalled party name: [%s]\n", pvt->cd.call_dest_alias); ast_verbose(VERBOSE_PREFIX_3 " \tCalled party number: [%s]\n", pvt->cd.call_dest_e164); if (pvt->cd.redirect_reason >= 0) ast_verbose(VERBOSE_PREFIX_3 " \tRedirecting party number: [%s] (reason %d)\n", pvt->cd.redirect_number, pvt->cd.redirect_reason); ast_verbose(VERBOSE_PREFIX_3 " \tCalling party IP: [%s]\n", pvt->cd.sourceIp); } /* Decide if we are allowing Gatekeeper routed calls*/ if ((!strcasecmp(cd->sourceIp, gatekeeper)) && (gkroute == -1) && !gatekeeper_disable) { if (!ast_strlen_zero(cd->call_dest_e164)) { ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); } else { alias = find_alias(cd->call_dest_alias, 1); if (!alias) { ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd->call_dest_alias); oh323_destroy(pvt); return NULL; } ast_copy_string(pvt->exten, alias->name, sizeof(pvt->exten)); ast_copy_string(pvt->context, alias->context, sizeof(pvt->context)); } } else { /* Either this call is not from the Gatekeeper or we are not allowing gk routed calls */ user = find_user(cd, 1); if (!user) { if (!acceptAnonymous) { ast_log(LOG_NOTICE, "Anonymous call from '%s@%s' rejected\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp); oh323_destroy(pvt); return NULL; } if (ast_strlen_zero(default_context)) { ast_log(LOG_ERROR, "Call from '%s@%s' rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp); oh323_destroy(pvt); return NULL; } ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); if (!ast_strlen_zero(pvt->cd.call_dest_e164)) { ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); } else { ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten)); } if (h323debug) ast_log(LOG_DEBUG, "Sending %s@%s to context [%s] extension %s\n", cd->call_source_aliases, cd->sourceIp, pvt->context, pvt->exten); } else { if (user->host) { if (strcasecmp(cd->sourceIp, ast_inet_ntoa(user->addr.sin_addr))) { if (ast_strlen_zero(user->context)) { if (ast_strlen_zero(default_context)) { ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd->sourceIp); oh323_destroy(pvt); ASTOBJ_UNREF(user, oh323_destroy_user); return NULL; } ast_copy_string(pvt->context, default_context, sizeof(pvt->context)); } else { ast_copy_string(pvt->context, user->context, sizeof(pvt->context)); } pvt->exten[0] = 'i'; pvt->exten[1] = '\0'; ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s)s\n", user->name, cd->sourceIp); oh323_destroy(pvt); ASTOBJ_UNREF(user, oh323_destroy_user); return NULL; /* XXX: Hmmm... Why to setup context if we drop connection immediately??? */ } } ast_copy_string(pvt->context, user->context, sizeof(pvt->context)); memcpy(&pvt->options, &user->options, sizeof(pvt->options)); pvt->jointcapability = pvt->options.capability; if (!ast_strlen_zero(pvt->cd.call_dest_e164)) { ast_copy_string(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten)); } else { ast_copy_string(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten)); } if (!ast_strlen_zero(user->accountcode)) { ast_copy_string(pvt->accountcode, user->accountcode, sizeof(pvt->accountcode)); } if (user->amaflags) { pvt->amaflags = user->amaflags; } ASTOBJ_UNREF(user, oh323_destroy_user); } } return &pvt->options;}/** * Call-back function to start PBX when OpenH323 ready to serve incoming call * * Returns 1 on success */static int answer_call(unsigned call_reference, const char *token){ struct oh323_pvt *pvt; struct ast_channel *c = NULL; enum {ext_original, ext_s, ext_i, ext_notexists} try_exten; char tmp_exten[sizeof(pvt->exten)]; if (h323debug) ast_log(LOG_DEBUG, "Preparing Asterisk to answer for %s\n", token); /* Find the call or allocate a private structure if call not found */ pvt = find_call_locked(call_reference, token); if (!pvt) { ast_log(LOG_ERROR, "Something is wrong: answer_call\n"); return 0; } /* Check if requested extension@context pair exists in the dialplan */ ast_copy_string(tmp_exten, pvt->exten, sizeof(tmp_exten)); /* Try to find best extension in specified context */ if ((tmp_exten[0] != '\0') && (tmp_exten[1] == '\0')) { if (tmp_exten[0] == 's') try_exten = ext_s; else if (tmp_exten[0] == 'i') try_exten = ext_i; else try_exten = ext_original; } else try_exten = ext_original; do { if (ast_exists_extension(NULL, pvt->context, tmp_exten, 1, NULL)) break; switch (try_exten) { case ext_original: tmp_exten[0] = 's'; tmp_exten[1] = '\0'; try_exten = ext_s; break; case ext_s: tmp_exten[0] = 'i'; try_exten = ext_i; break; case ext_i: try_exten = ext_notexists; break; default: break; } } while (try
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -