📄 chan_gtalk.c
字号:
struct gtalk_candidate *tmp; struct hostent *hp; struct ast_hostent ahp; struct sockaddr_in sin; struct sockaddr_in aux; if (time(NULL) == p->laststun) return 0; tmp = p->theircandidates; p->laststun = time(NULL); while (tmp) { char username[256]; /* Find the IP address of the host */ hp = ast_gethostbyname(tmp->ip, &ahp); sin.sin_family = AF_INET; memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); sin.sin_port = htons(tmp->port); snprintf(username, sizeof(username), "%s%s", tmp->username, p->ourcandidates->username); /* Find out the result of the STUN */ ast_rtp_get_peer(p->rtp, &aux); /* If the STUN result is different from the IP of the hostname, lock on the stun IP of the hostname advertised by the remote client */ if (aux.sin_addr.s_addr && aux.sin_addr.s_addr != sin.sin_addr.s_addr) ast_rtp_stun_request(p->rtp, &aux, username); else ast_rtp_stun_request(p->rtp, &sin, username); if (aux.sin_addr.s_addr && option_debug > 3) { ast_log(LOG_DEBUG, "Receiving RTP traffic from IP %s, matches with remote candidate's IP %s\n", ast_inet_ntoa(aux.sin_addr), tmp->ip); ast_log(LOG_DEBUG, "Sending STUN request to %s\n", tmp->ip); } tmp = tmp->next; } return 1;}static int gtalk_add_candidate(struct gtalk *client, ikspak *pak){ struct gtalk_pvt *p = NULL, *tmp = NULL; struct aji_client *c = client->connection; struct gtalk_candidate *newcandidate = NULL; iks *traversenodes = NULL, *receipt = NULL; char *from; from = iks_find_attrib(pak->x,"to"); if(!from) from = c->jid->full; for (tmp = client->p; tmp; tmp = tmp->next) { if (iks_find_with_attrib(pak->x, "session", "id", tmp->sid)) { p = tmp; break; } } if (!p) return -1; traversenodes = pak->query; while(traversenodes) { if(!strcasecmp(iks_name(traversenodes), "session")) { traversenodes = iks_child(traversenodes); continue; } if(!strcasecmp(iks_name(traversenodes), "transport")) { traversenodes = iks_child(traversenodes); continue; } if(!strcasecmp(iks_name(traversenodes), "candidate")) { newcandidate = ast_calloc(1, sizeof(*newcandidate)); if (!newcandidate) return 0; ast_copy_string(newcandidate->name, iks_find_attrib(traversenodes, "name"), sizeof(newcandidate->name)); ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "address"), sizeof(newcandidate->ip)); newcandidate->port = atoi(iks_find_attrib(traversenodes, "port")); ast_copy_string(newcandidate->username, iks_find_attrib(traversenodes, "username"), sizeof(newcandidate->username)); ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "password"), sizeof(newcandidate->password)); newcandidate->preference = atof(iks_find_attrib(traversenodes, "preference")); if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp")) newcandidate->protocol = AJI_PROTOCOL_UDP; if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp")) newcandidate->protocol = AJI_PROTOCOL_SSLTCP; if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "stun")) newcandidate->type = AJI_CONNECT_STUN; if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "local")) newcandidate->type = AJI_CONNECT_LOCAL; if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay")) newcandidate->type = AJI_CONNECT_RELAY; ast_copy_string(newcandidate->network, iks_find_attrib(traversenodes, "network"), sizeof(newcandidate->network)); newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation")); newcandidate->next = NULL; newcandidate->next = p->theircandidates; p->theircandidates = newcandidate; p->laststun = 0; gtalk_update_stun(p->parent, p); newcandidate = NULL; } traversenodes = iks_next(traversenodes); } receipt = iks_new("iq"); iks_insert_attrib(receipt, "type", "result"); iks_insert_attrib(receipt, "from", from); iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from")); iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id")); iks_send(c->p, receipt); iks_delete(receipt); return 1;}static struct ast_frame *gtalk_rtp_read(struct ast_channel *ast, struct gtalk_pvt *p){ struct ast_frame *f; if (!p->rtp) return &ast_null_frame; f = ast_rtp_read(p->rtp); gtalk_update_stun(p->parent, p); if (p->owner) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) { if (option_debug) ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass); p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass; ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); }/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) { f = ast_dsp_process(p->owner, p->vad, f); if (option_debug && f && (f->frametype == AST_FRAME_DTMF)) ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass); } */ } } return f;}static struct ast_frame *gtalk_read(struct ast_channel *ast){ struct ast_frame *fr; struct gtalk_pvt *p = ast->tech_pvt; ast_mutex_lock(&p->lock); fr = gtalk_rtp_read(ast, p); ast_mutex_unlock(&p->lock); return fr;}/*! \brief Send frame to media channel (rtp) */static int gtalk_write(struct ast_channel *ast, struct ast_frame *frame){ struct gtalk_pvt *p = ast->tech_pvt; int res = 0; switch (frame->frametype) { case AST_FRAME_VOICE: if (!(frame->subclass & ast->nativeformats)) { ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat); return 0; } if (p) { ast_mutex_lock(&p->lock); if (p->rtp) { res = ast_rtp_write(p->rtp, frame); } ast_mutex_unlock(&p->lock); } break; case AST_FRAME_VIDEO: if (p) { ast_mutex_lock(&p->lock); if (p->vrtp) { res = ast_rtp_write(p->vrtp, frame); } ast_mutex_unlock(&p->lock); } break; case AST_FRAME_IMAGE: return 0; break; default: ast_log(LOG_WARNING, "Can't send %d type frames with Gtalk write\n", frame->frametype); return 0; } return res;}static int gtalk_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){ struct gtalk_pvt *p = newchan->tech_pvt; ast_mutex_lock(&p->lock); if ((p->owner != oldchan)) { ast_mutex_unlock(&p->lock); return -1; } if (p->owner == oldchan) p->owner = newchan; ast_mutex_unlock(&p->lock); return 0;}static int gtalk_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen){ int res = 0; switch (condition) { case AST_CONTROL_HOLD: ast_moh_start(ast, data, NULL); break; case AST_CONTROL_UNHOLD: ast_moh_stop(ast); break; default: ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition); res = -1; } return res;}static int gtalk_digit_begin(struct ast_channel *chan, char digit){ return gtalk_digit(chan, digit, 0);}static int gtalk_digit_end(struct ast_channel *chan, char digit, unsigned int duration){ return gtalk_digit(chan, digit, duration);}static int gtalk_digit(struct ast_channel *ast, char digit, unsigned int duration){ struct gtalk_pvt *p = ast->tech_pvt; struct gtalk *client = p->parent; iks *iq, *gtalk, *dtmf; char buffer[2] = {digit, '\0'}; iq = iks_new("iq"); gtalk = iks_new("gtalk"); dtmf = iks_new("dtmf"); if(!iq || !gtalk || !dtmf) { if(iq) iks_delete(iq); if(gtalk) iks_delete(gtalk); if(dtmf) iks_delete(dtmf); ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n"); return -1; } iks_insert_attrib(iq, "type", "set"); iks_insert_attrib(iq, "to", p->them); iks_insert_attrib(iq, "from", p->us); iks_insert_attrib(iq, "id", client->connection->mid); ast_aji_increment_mid(client->connection->mid); iks_insert_attrib(gtalk, "xmlns", "http://jabber.org/protocol/gtalk"); iks_insert_attrib(gtalk, "action", "session-info"); iks_insert_attrib(gtalk, "initiator", p->initiator ? p->us: p->them); iks_insert_attrib(gtalk, "sid", p->sid); iks_insert_attrib(dtmf, "xmlns", "http://jabber.org/protocol/gtalk/info/dtmf"); iks_insert_attrib(dtmf, "code", buffer); iks_insert_node(iq, gtalk); iks_insert_node(gtalk, dtmf); ast_mutex_lock(&p->lock); if (ast->dtmff.frametype == AST_FRAME_DTMF_BEGIN || duration == 0) { iks_insert_attrib(dtmf, "action", "button-down"); } else if (ast->dtmff.frametype == AST_FRAME_DTMF_END || duration != 0) { iks_insert_attrib(dtmf, "action", "button-up"); } iks_send(client->connection->p, iq); iks_delete(iq); iks_delete(gtalk); iks_delete(dtmf); ast_mutex_unlock(&p->lock); return 0;}static int gtalk_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen){ ast_log(LOG_NOTICE, "XXX Implement gtalk sendhtml XXX\n"); return -1;}/* Not in use right now.static int gtalk_auto_congest(void *nothing){ struct gtalk_pvt *p = nothing; ast_mutex_lock(&p->lock); if (p->owner) { if (!ast_channel_trylock(p->owner)) { ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name); ast_queue_control(p->owner, AST_CONTROL_CONGESTION); ast_channel_unlock(p->owner); } } ast_mutex_unlock(&p->lock); return 0;}*//*! \brief Initiate new call, part of PBX interface * dest is the dial string */static int gtalk_call(struct ast_channel *ast, char *dest, int timeout){ struct gtalk_pvt *p = ast->tech_pvt; if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "gtalk_call called on %s, neither down nor reserved\n", ast->name); return -1; } ast_setstate(ast, AST_STATE_RING); if (!p->ringrule) { ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring)); p->ringrule = iks_filter_add_rule(p->parent->connection->f, gtalk_ringing_ack, p, IKS_RULE_ID, p->ring, IKS_RULE_DONE); } else ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n"); gtalk_invite(p, p->them, p->us, p->sid, 1); gtalk_create_candidates(p->parent, p, p->sid, p->them, p->us); return 0;}/*! \brief Hangup a call through the gtalk proxy channel */static int gtalk_hangup(struct ast_channel *ast){ struct gtalk_pvt *p = ast->tech_pvt; struct gtalk *client; ast_mutex_lock(&p->lock); client = p->parent; p->owner = NULL; ast->tech_pvt = NULL; if (!p->alreadygone) gtalk_action(client, p, "terminate"); ast_mutex_unlock(&p->lock); gtalk_free_pvt(client, p); ast_module_unref(ast_module_info->self); return 0;}/*! \brief Part of PBX interface */static struct ast_channel *gtalk_request(const char *type, int format, void *data, int *cause){ struct gtalk_pvt *p = NULL; struct gtalk *client = NULL; char *sender = NULL, *to = NULL, *s = NULL; struct ast_channel *chan = NULL; if (data) { s = ast_strdupa(data); if (s) { sender = strsep(&s, "/"); if (sender && (sender[0] != '\0')) to = strsep(&s, "/"); if (!to) { ast_log(LOG_ERROR, "Bad arguments in Gtalk Dialstring: %s\n", (char*) data); return NULL; } } } client = find_gtalk(to, sender); if (!client) { ast_log(LOG_WARNING, "Could not find recipient.\n"); return NULL; } if (!strcasecmp(client->name, "guest")){ /* the guest account is not tied to any configured XMPP client, let's set it now */ client->connection = ast_aji_get_client(sender); if (!client->connection) { ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender); ASTOBJ_UNREF(client, gtalk_member_destroy); return NULL; } } ASTOBJ_WRLOCK(client); p = gtalk_alloc(client, strchr(sender, '@') ? sender : client->connection->jid->full, strchr(to, '@') ? to : client->user, NULL); if (p) chan = gtalk_new(client, p, AST_STATE_DOWN, to);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -