/* Needs to be called with d->lock */ sccp_channel_t * sccp_dev_allocate_channel(sccp_device_t * d, sccp_line_t * l, int outgoing, char * dial) { sccp_channel_t * c = NULL; struct ast_channel * tmp = NULL; pthread_t t; int callId; if (!d->session) { ast_log(LOG_ERROR, "Tried to open channel on device without a session\n"); return NULL; } // If there is no current line, then we can't make a call in, or out. if (!d->currentLine) { ast_log(LOG_ERROR, "Tried to open channel on a device with no selected line\n"); return NULL; } if (l == NULL) l = d->currentLine; ast_mutex_lock(&callCountLock); callId = callCount++; ast_mutex_unlock(&callCountLock); c = malloc(sizeof(sccp_channel_t)); memset(c, 0, sizeof(sccp_channel_t)); c->callid = callId; c->line = l; ast_mutex_lock(&l->lock); l->channelCount++; ast_mutex_unlock(&l->lock); ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); tmp = sccp_new_channel(c, AST_STATE_OFFHOOK); ast_log(LOG_DEBUG, "New channel name is: %s\n", tmp->name); ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); ast_mutex_lock(&chanlock); c->lnext = chans; chans = c; ast_mutex_unlock(&chanlock); c->owner = tmp; c->next = l->channels; l->channels = c; l->activeChannel = c; if (outgoing) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); c->isOutgoing = 1; d->active_channel = c; ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); sccp_dev_set_speaker(d, StationSpeakerOn); sccp_channel_set_callstate(c, TsOffHook); sccp_dev_statusprompt_set(d, c, NULL, 0); sccp_dev_set_keyset(d, c, KEYMODE_OFFHOOK); sccp_dev_set_sptone(d, "InsideDialTone"); if (dial) { strncpy(tmp->exten, dial, AST_MAX_EXTENSION); if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "PBX exited non-zero\n"); sccp_dev_statusprompt_set(l->device, c, "PBX Error", 10); sccp_dev_set_sptone(l->device, "ReorderTone"); ast_indicate(tmp, AST_CONTROL_CONGESTION); } ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, channels = %p\n", c->lnext, c, chans); } else if (pthread_create(&t, &attr, sccp_start_channel, tmp)) { ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno)); ast_hangup(tmp); free(c); return NULL; } } else { // It's an incoming call. } ast_log(LOG_DEBUG, "After: #Channel ->lnext = %p, c = %p, chans = %p\n", c->lnext, c, chans); return c; }
void * sccp_pbx_startchannel(void *data) { struct cw_channel * chan = data; sccp_channel_t * c; sccp_line_t * l; sccp_device_t * d; uint8_t res_exten = 0, res_wait = 0, res_timeout = 0; c = CS_CW_CHANNEL_PVT(chan); if ( !c || !(l = c->line) || !(d = c->device) ) { cw_hangup(chan); return NULL; } sccp_log(1)( VERBOSE_PREFIX_3 "%s: New call on line %s\n", d->id, l->name); cw_mutex_lock(&c->lock); c->calltype = SKINNY_CALLTYPE_OUTBOUND; c->hangupok = 0; cw_mutex_unlock(&c->lock); sccp_channel_set_callingparty(c, l->cid_name, l->cid_num); if (!cw_strlen_zero(c->dialedNumber)) { /* we have a number to dial. Let's do it */ sccp_log(10)( VERBOSE_PREFIX_3 "%s: Dialing %s on channel %s-%d\n", l->device->id, c->dialedNumber, l->name, c->callid); sccp_channel_set_calledparty(c, c->dialedNumber, c->dialedNumber); sccp_indicate_lock(c, SCCP_CHANNELSTATE_DIALING); goto dial; } /* we have to collect the number */ /* the phone is on TsOffHook state */ sccp_log(10)( VERBOSE_PREFIX_3 "%s: Waiting for the number to dial on channel %s-%d\n", l->device->id, l->name, c->callid); /* let's use the keypad to collect digits */ cw_mutex_lock(&c->lock); c->digittimeout = time(0)+GLOB(firstdigittimeout); cw_mutex_unlock(&c->lock); res_exten = 1; do { pthread_testcancel(); usleep(100); cw_mutex_lock(&c->lock); if (!cw_strlen_zero(c->dialedNumber)) { res_exten = (c->dialedNumber[0] == '*' || cw_matchmore_extension(chan, chan->context, c->dialedNumber, 1, l->cid_num)); } if (! (res_wait = ( c->state == SCCP_CHANNELSTATE_DOWN || chan->_state == CW_STATE_DOWN || chan->_softhangup || c->calltype == SKINNY_CALLTYPE_INBOUND)) ) { if (CS_CW_CHANNEL_PVT(chan)) { res_timeout = (time(0) < c->digittimeout); } else res_timeout = 0; } cw_mutex_unlock(&c->lock); } while ( (res_wait == 0) && res_exten && res_timeout); if (res_wait != 0) { /* CW_STATE_DOWN or softhangup */ sccp_log(10)(VERBOSE_PREFIX_3 "%s: return from the startchannel for DOWN, HANGUP or PICKUP cause\n", l->device->id); cw_mutex_lock(&c->lock); c->hangupok = 1; cw_mutex_unlock(&c->lock); return NULL; } dial: cw_mutex_lock(&c->lock); cw_copy_string(chan->exten, c->dialedNumber, sizeof(chan->exten)); cw_copy_string(d->lastNumber, c->dialedNumber, sizeof(d->lastNumber)); sccp_channel_set_calledparty(c, c->dialedNumber, c->dialedNumber); /* proceed call state is needed to display the called number. The phone will not display callinfo in offhook state */ sccp_channel_set_callstate(c, SKINNY_CALLSTATE_PROCEED); sccp_channel_send_callinfo(c); sccp_dev_clearprompt(d,c->line->instance, c->callid); sccp_dev_displayprompt(d, c->line->instance, c->callid, SKINNY_DISP_CALL_PROCEED, 0); c->hangupok = 1; cw_mutex_unlock(&c->lock); if ( !cw_strlen_zero(c->dialedNumber) && cw_exists_extension(chan, chan->context, c->dialedNumber, 1, l->cid_num) ) { /* found an extension, let's dial it */ sccp_log(10)(VERBOSE_PREFIX_3 "%s: channel %s-%d is dialing number %s\n", l->device->id, l->name, c->callid, c->dialedNumber); /* Answer dialplan command works only when in RINGING OR RING cw_state */ sccp_cw_setstate(c, CW_STATE_RING); if (cw_pbx_run(chan)) { sccp_indicate_lock(c, SCCP_CHANNELSTATE_INVALIDNUMBER); } } else { /* timeout and no extension match */ sccp_indicate_lock(c, SCCP_CHANNELSTATE_INVALIDNUMBER); } sccp_log(10)(VERBOSE_PREFIX_3 "%s: return from the startchannel on exit\n", l->device->id); return NULL; }