static int phone_hangup(struct ast_channel *ast) { struct phone_pvt *p; p = ast->pvt->pvt; if (option_debug) ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name); if (!ast->pvt->pvt) { ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); return 0; } /* XXX Is there anything we can do to really hang up except stop recording? */ ast_setstate(ast, AST_STATE_DOWN); if (ioctl(p->fd, PHONE_REC_STOP)) ast_log(LOG_WARNING, "Failed to stop recording\n"); if (ioctl(p->fd, PHONE_PLAY_STOP)) ast_log(LOG_WARNING, "Failed to stop playing\n"); if (ioctl(p->fd, PHONE_RING_STOP)) ast_log(LOG_WARNING, "Failed to stop ringing\n"); if (ioctl(p->fd, PHONE_CPT_STOP)) ast_log(LOG_WARNING, "Failed to stop sounds\n"); /* If it's an FXO, hang them up */ if (p->mode == MODE_FXO) { if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno)); } /* If they're off hook, give a busy signal */ if (ioctl(p->fd, PHONE_HOOKSTATE)) { if (option_debug) ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n"); ioctl(p->fd, PHONE_BUSY); p->cpt = 1; } p->lastformat = -1; p->lastinput = -1; p->ministate = 0; p->obuflen = 0; p->dialtone = 0; memset(p->ext, 0, sizeof(p->ext)); ((struct phone_pvt *)(ast->pvt->pvt))->owner = NULL; ast_mutex_lock(&usecnt_lock); usecnt--; if (usecnt < 0) ast_log(LOG_WARNING, "Usecnt < 0???\n"); ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name); ast->pvt->pvt = NULL; ast_setstate(ast, AST_STATE_DOWN); restart_monitor(); return 0; }
static int status_session(struct respoke_session *session, enum respoke_status status) { if (!session->channel) { return 0; } switch (status) { case RESPOKE_STATUS_RINGING: ast_queue_control(session->channel, AST_CONTROL_RINGING); ast_channel_lock(session->channel); if (ast_channel_state(session->channel) != AST_STATE_UP) { ast_setstate(session->channel, AST_STATE_RINGING); } ast_channel_unlock(session->channel); break; case RESPOKE_STATUS_PROGRESS: ast_queue_control(session->channel, AST_CONTROL_PROGRESS); break; default: set_cause_code(session, status); ast_queue_hangup(session->channel); break; } return 0; }
static struct ast_frame *aopen_handle_escape(struct ast_modem_pvt *p, char esc) { /* Handle escaped characters -- but sometimes we call it directly as a quick way to cause known responses */ p->fr.frametype = AST_FRAME_NULL; p->fr.subclass = 0; p->fr.data = NULL; p->fr.datalen = 0; p->fr.samples = 0; p->fr.offset = 0; p->fr.mallocd = 0; p->fr.delivery.tv_sec = 0; p->fr.delivery.tv_usec = 0; if (esc) ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc); switch(esc) { case 'R': /* Pseudo ring */ p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_RING; return &p->fr; case 'X': /* Pseudo connect */ p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_RING; if (p->owner) ast_setstate(p->owner, AST_STATE_UP); if (aopen_startrec(p)) return NULL; return &p->fr; case 'b': /* Busy signal */ p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_BUSY; return &p->fr; case 'o': /* Overrun */ ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n"); if (ast_modem_send(p, "\0x10E", 2)) ast_log(LOG_WARNING, "Unable to flush buffers\n"); return &p->fr; case 'u': /* Underrun */ ast_log(LOG_WARNING, "Data underrun\n"); /* Fall Through */ case CHAR_ETX: /* End Transmission */ case 'd': /* Dialtone */ case 'c': /* Calling Tone */ case 'e': /* European version */ case 'a': /* Answer Tone */ case 'f': /* Bell Answer Tone */ case 'T': /* Timing mark */ case 't': /* Handset off hook */ case 'h': /* Handset hungup */ case 0: /* Pseudo signal */ /* Ignore */ return &p->fr; default: ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc); } return &p->fr; }
static int phone_call(struct ast_channel *ast, char *dest, int timeout) { struct phone_pvt *p; PHONE_CID cid; time_t UtcTime; struct tm tm; time(&UtcTime); localtime_r(&UtcTime,&tm); memset(&cid, 0, sizeof(PHONE_CID)); if(&tm != NULL) { snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1)); snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday); snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour); snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min); } /* the standard format of ast->callerid is: "name" <number>, but not always complete */ if (!ast->callerid || ast_strlen_zero(ast->callerid)){ strncpy(cid.name, DEFAULT_CALLER_ID, sizeof(cid.name) - 1); cid.number[0]='\0'; } else { char *n, *l; char callerid[256] = ""; strncpy(callerid, ast->callerid, sizeof(callerid) - 1); ast_callerid_parse(callerid, &n, &l); if (l) { ast_shrink_phone_number(l); if (!ast_isphonenumber(l)) l = NULL; } if (l) strncpy(cid.number, l, sizeof(cid.number) - 1); if (n) strncpy(cid.name, n, sizeof(cid.name) - 1); } p = ast->pvt->pvt; if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name); return -1; } if (option_debug) ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]); IXJ_PHONE_RING_START(cid); ast_setstate(ast, AST_STATE_RINGING); ast_queue_control(ast, AST_CONTROL_RINGING); return 0; }
static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context) { struct ast_channel *tmp; tmp = ast_channel_alloc(1); if (tmp) { snprintf(tmp->name, sizeof(tmp->name), "Phone/%s", i->dev + 5); tmp->type = type; tmp->fds[0] = i->fd; /* XXX Switching formats silently causes kernel panics XXX */ tmp->nativeformats = prefformat; tmp->pvt->rawreadformat = prefformat; tmp->pvt->rawwriteformat = prefformat; ast_setstate(tmp, state); if (state == AST_STATE_RING) tmp->rings = 1; tmp->pvt->pvt = i; tmp->pvt->send_digit = phone_digit; tmp->pvt->call = phone_call; tmp->pvt->hangup = phone_hangup; tmp->pvt->answer = phone_answer; tmp->pvt->read = phone_read; tmp->pvt->write = phone_write; tmp->pvt->exception = phone_exception; strncpy(tmp->context, context, sizeof(tmp->context)-1); if (strlen(i->ext)) strncpy(tmp->exten, i->ext, sizeof(tmp->exten)-1); else strncpy(tmp->exten, "s", sizeof(tmp->exten) - 1); if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)-1); if (strlen(i->callerid)) tmp->callerid = strdup(i->callerid); i->owner = tmp; ast_mutex_lock(&usecnt_lock); usecnt++; ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); if (state != AST_STATE_DOWN) { if (state == AST_STATE_RING) { ioctl(tmp->fds[0], PHONE_RINGBACK); i->cpt = 1; } if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); } } } else ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); return tmp; }
static inline int at_response_conn (pvt_t* pvt) { if (pvt->outgoing) { ast_debug (1, "[%s] Remote end answered\n", pvt->id); channel_queue_control (pvt, AST_CONTROL_ANSWER); } else if (pvt->incoming && pvt->answered) { ast_setstate (pvt->owner, AST_STATE_UP); } return 0; }
/*! * \ingroup applications */ int indicate_congestion(struct ast_channel *chan, const char *data) { ast_indicate(chan, AST_CONTROL_CONGESTION); /* Don't change state of an UP channel, just indicate congestion in audio */ ast_channel_lock(chan); if (ast_channel_state(chan) != AST_STATE_UP) { ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION); ast_setstate(chan, AST_STATE_BUSY); } ast_channel_unlock(chan); wait_for_hangup(chan, data); return -1; }
static int phone_answer(struct ast_channel *ast) { struct phone_pvt *p; p = ast->pvt->pvt; /* In case it's a LineJack, take it off hook */ if (p->mode == MODE_FXO) { if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK)) ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno)); else ast_log(LOG_DEBUG, "Took linejack off hook\n"); } phone_setup(ast); if (option_debug) ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name); ast->rings = 0; ast_setstate(ast, AST_STATE_UP); return 0; }
/*! * \brief queue a frame onto either the p->owner or p->chan * * \note the ast_unreal_pvt MUST have it's ref count bumped before entering this function and * decremented after this function is called. This is a side effect of the deadlock * avoidance that is necessary to lock 2 channels and a tech_pvt. Without a ref counted * ast_unreal_pvt, it is impossible to guarantee it will not be destroyed by another thread * during deadlock avoidance. */ static int unreal_queue_frame(struct ast_unreal_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked) { struct ast_channel *other; /* Recalculate outbound channel */ other = isoutbound ? p->owner : p->chan; if (!other) { return 0; } /* do not queue media frames if a generator is on both unreal channels */ if (us && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) && ast_channel_generator(us) && ast_channel_generator(other)) { return 0; } /* grab a ref on the channel before unlocking the pvt, * other can not go away from us now regardless of locking */ ast_channel_ref(other); if (us && us_locked) { ast_channel_unlock(us); } ao2_unlock(p); if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) { ast_setstate(other, AST_STATE_RINGING); } ast_queue_frame(other, f); other = ast_channel_unref(other); if (us && us_locked) { ast_channel_lock(us); } ao2_lock(p); return 0; }
static int phone_write(struct ast_channel *ast, struct ast_frame *frame) { struct phone_pvt *p = ast->pvt->pvt; int res; int maxfr=0; char *pos; int sofar; int expected; int codecset = 0; char tmpbuf[4]; /* Write a frame of (presumably voice) data */ if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype != AST_FRAME_IMAGE) ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); return 0; } if (!(frame->subclass & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW))) { ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass); return -1; } #if 0 /* If we're not in up mode, go into up mode now */ if (ast->_state != AST_STATE_UP) { ast_setstate(ast, AST_STATE_UP); phone_setup(ast); } #else if (ast->_state != AST_STATE_UP) { /* Don't try tos end audio on-hook */ return 0; } #endif if (frame->subclass == AST_FORMAT_G723_1) { if (p->lastformat != AST_FORMAT_G723_1) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) { ast_log(LOG_WARNING, "Unable to set G723.1 mode\n"); return -1; } if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) { ast_log(LOG_WARNING, "Unable to set G723.1 mode\n"); return -1; } p->lastformat = AST_FORMAT_G723_1; p->lastinput = AST_FORMAT_G723_1; /* Reset output buffer */ p->obuflen = 0; codecset = 1; } if (frame->datalen > 24) { ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen); return -1; } maxfr = 24; } else if (frame->subclass == AST_FORMAT_SLINEAR) { if (p->lastformat != AST_FORMAT_SLINEAR) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) { ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n"); return -1; } if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) { ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n"); return -1; } p->lastformat = AST_FORMAT_SLINEAR; p->lastinput = AST_FORMAT_SLINEAR; codecset = 1; /* Reset output buffer */ p->obuflen = 0; } maxfr = 480; } else if (frame->subclass == AST_FORMAT_ULAW) { if (p->lastformat != AST_FORMAT_ULAW) { ioctl(p->fd, PHONE_PLAY_STOP); ioctl(p->fd, PHONE_REC_STOP); if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) { ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); return -1; } if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); return -1; } p->lastformat = AST_FORMAT_ULAW; p->lastinput = AST_FORMAT_ULAW; codecset = 1; /* Reset output buffer */ p->obuflen = 0; } maxfr = 240; } if (codecset) { ioctl(p->fd, PHONE_REC_DEPTH, 3); ioctl(p->fd, PHONE_PLAY_DEPTH, 3); if (ioctl(p->fd, PHONE_PLAY_START)) { ast_log(LOG_WARNING, "Failed to start playback\n"); return -1; } if (ioctl(p->fd, PHONE_REC_START)) { ast_log(LOG_WARNING, "Failed to start recording\n"); return -1; } } /* If we get here, we have a voice frame of Appropriate data */ sofar = 0; pos = frame->data; while(sofar < frame->datalen) { /* Write in no more than maxfr sized frames */ expected = frame->datalen - sofar; if (maxfr < expected) expected = maxfr; /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX we have to pad it to 24 bytes still. */ if (frame->datalen == 4) { if (p->silencesupression) { memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4); memcpy(tmpbuf, frame->data, 4); expected = 24; res = phone_write_buf(p, tmpbuf, expected, maxfr); } res = 4; expected=4; } else { res = phone_write_buf(p, pos, expected, maxfr); } if (res != expected) { if ((errno != EAGAIN) && (errno != EINTR)) { if (res < 0) ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno)); /* * Card is in non-blocking mode now and it works well now, but there are * lot of messages like this. So, this message is temporarily disabled. */ #if 0 else ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen); #endif return -1; } else /* Pretend it worked */ res = expected; } sofar += res; pos += res; } return 0; }
static struct ast_frame *phone_exception(struct ast_channel *ast) { int res; union telephony_exception phonee; struct phone_pvt *p = ast->pvt->pvt; char digit; /* Some nice norms */ p->fr.datalen = 0; p->fr.samples = 0; p->fr.data = NULL; p->fr.src = type; p->fr.offset = 0; p->fr.mallocd=0; p->fr.delivery.tv_sec = 0; p->fr.delivery.tv_usec = 0; phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION); if (phonee.bits.dtmf_ready) { if (option_debug) ast_log(LOG_DEBUG, "phone_exception(): DTMF\n"); /* We've got a digit -- Just handle this nicely and easily */ digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII); p->fr.subclass = digit; p->fr.frametype = AST_FRAME_DTMF; return &p->fr; } if (phonee.bits.hookstate) { if (option_debug) ast_log(LOG_DEBUG, "Hookstate changed\n"); res = ioctl(p->fd, PHONE_HOOKSTATE); /* See if we've gone on hook, if so, notify by returning NULL */ if (option_debug) ast_log(LOG_DEBUG, "New hookstate: %d\n", res); if (!res && (p->mode != MODE_FXO)) return NULL; else { if (ast->_state == AST_STATE_RINGING) { /* They've picked up the phone */ p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_ANSWER; phone_setup(ast); ast_setstate(ast, AST_STATE_UP); return &p->fr; } else ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->_state); } } #if 1 if (phonee.bits.pstn_ring) ast_verbose("Unit is ringing\n"); if (phonee.bits.caller_id) { ast_verbose("We have caller ID\n"); } if (phonee.bits.pstn_wink) ast_verbose("Detected Wink\n"); #endif /* Strange -- nothing there.. */ p->fr.frametype = AST_FRAME_NULL; p->fr.subclass = 0; return &p->fr; }
static struct ast_frame *bestdata_handle_escape(struct ast_modem_pvt *p, char esc) { char name[30]="",nmbr[30]=""; time_t now; /* Handle escaped characters -- but sometimes we call it directly as a quick way to cause known responses */ p->fr.frametype = AST_FRAME_NULL; p->fr.subclass = 0; p->fr.data = NULL; p->fr.datalen = 0; p->fr.samples = 0; p->fr.offset = 0; p->fr.mallocd = 0; p->fr.delivery.tv_sec = 0; p->fr.delivery.tv_usec = 0; if (esc) ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc); switch(esc) { case 'R': /* Pseudo ring */ time(&now); if (now > (p->lastring + (RINGT / 1000))) { /* if stale, treat as new */ p->gotclid = 0; } if (p->gotclid) { p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_RING; } p->ringt = RINGT; time(&p->lastring); return &p->fr; case 'X': /* Caller-ID Spill */ if (p->gotclid) return &p->fr; name[0] = nmbr[0] = 0; for(;;) { char res[1000]=""; if (ast_modem_read_response(p, 5)) break; strncpy(res, p->response, sizeof(res)-1); ast_modem_trim(res); if (!strncmp(res,"\020.",2)) break; if (!strncmp(res,"NAME",4)) strncpy(name,res + 7, sizeof(name) - 1); if (!strncmp(res,"NMBR",4)) strncpy(nmbr,res + 7, sizeof(nmbr) - 1); } p->gotclid = 1; if ((!strcmp(name,"O")) || (!strcmp(name,"P"))) name[0] = 0; if ((!strcmp(nmbr,"O")) || (!strcmp(nmbr,"P"))) nmbr[0] = 0; if ((name[0]) && (nmbr[0])) snprintf(p->cid,sizeof(p->cid), "\"%s\" <%s>",name,nmbr); else if (name[0]) snprintf(p->cid,sizeof(p->cid), "\"%s\"",name); else if (nmbr[0]) snprintf(p->cid,sizeof(p->cid), "%s",nmbr); if (p->owner) p->owner->callerid = strdup(p->cid); return &p->fr; case '@': /* response from "OK" in command mode */ if (p->owner) ast_setstate(p->owner, AST_STATE_UP); if (bestdata_startrec(p)) return NULL; p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_RING; return &p->fr; case 'b': /* Busy signal */ p->fr.frametype = AST_FRAME_CONTROL; p->fr.subclass = AST_CONTROL_BUSY; return &p->fr; case 'o': /* Overrun */ ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n"); if (ast_modem_send(p, "\0x10E", 2)) ast_log(LOG_WARNING, "Unable to flush buffers\n"); return &p->fr; case '0': /* All the DTMF characters */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '*': case '#': case 'A': case 'B': case 'C': case 'D': p->dtmfrx = esc; /* save this for when its done */ return &p->fr; case '/': /* Start of DTMF tone shielding */ p->dtmfrx = ' '; return &p->fr; case '~': /* DTMF transition to off */ if (p->dtmfrx > ' ') { p->fr.frametype = AST_FRAME_DTMF; p->fr.subclass = p->dtmfrx; } p->dtmfrx = 0; return &p->fr; case 'u': /* Underrun */ ast_log(LOG_WARNING, "Data underrun\n"); /* Fall Through */ case CHAR_ETX: /* End Transmission */ case 'd': /* Dialtone */ case 'c': /* Calling Tone */ case 'e': /* European version */ case 'a': /* Answer Tone */ case 'f': /* Bell Answer Tone */ case 'T': /* Timing mark */ case 't': /* Handset off hook */ case 'h': /* Handset hungup */ case 0: /* Pseudo signal */ /* Ignore */ return &p->fr; default: ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc); } return &p->fr; }