Beispiel #1
0
/* Setup SPAN logging according to Asterisk debug level */
static int set_logging(logging_state_t *state)
{
	int level = SPAN_LOG_WARNING + option_debug;

	span_log_set_message_handler(state, span_message);
	span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 

	return 0;
}
Beispiel #2
0
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
{
	struct ast_channel *chan = (struct ast_channel *) user_data;

	struct ast_frame outf = {
		.frametype = AST_FRAME_MODEM,
		.subclass.integer = AST_MODEM_T38,
		.src = __FUNCTION__,
	};

	/* TODO: Asterisk does not provide means of resending the same packet multiple
	  times so count is ignored at the moment */

	AST_FRAME_SET_BUFFER(&outf, buf, 0, len);

	if (ast_write(chan, &outf) < 0) {
		ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
		return -1;
	}

	return 0;
}

static void phase_e_handler(t30_state_t *f, void *user_data, int result)
{
	const char *local_ident;
	const char *far_ident;
	char buf[20];
	fax_session *s = (fax_session *) user_data;
	t30_stats_t stat;
	int pages_transferred;

	ast_debug(1, "Fax phase E handler. result=%d\n", result);

	t30_get_transfer_statistics(f, &stat);

	s = (fax_session *) user_data;

	if (result != T30_ERR_OK) {
		s->finished = -1;

		/* FAXSTATUS is already set to FAILED */
		pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));

		ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));

		return;
	}

	s->finished = 1;

	local_ident = S_OR(t30_get_tx_ident(f), "");
	far_ident = S_OR(t30_get_rx_ident(f), "");
	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
	pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
	pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
#if SPANDSP_RELEASE_DATE >= 20090220
	pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
#else
	pages_transferred = stat.pages_transferred;
#endif
	snprintf(buf, sizeof(buf), "%d", pages_transferred);
	pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
	snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
	pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
	snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
	pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);

	ast_debug(1, "Fax transmitted successfully.\n");
	ast_debug(1, "  Remote station ID: %s\n", far_ident);
	ast_debug(1, "  Pages transferred: %d\n", pages_transferred);
	ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
	ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);

	ast_manager_event(s->chan, EVENT_FLAG_CALL,
		s->direction ? "FaxSent" : "FaxReceived",
		"Channel: %s\r\n"
		"Exten: %s\r\n"
		"CallerID: %s\r\n"
		"CallerIDName: %s\r\n"
		"ConnectedLineNum: %s\r\n"
		"ConnectedLineName: %s\r\n"
		"RemoteStationID: %s\r\n"
		"LocalStationID: %s\r\n"
		"PagesTransferred: %d\r\n"
		"Resolution: %d\r\n"
		"TransferRate: %d\r\n"
		"FileName: %s\r\n",
		ast_channel_name(s->chan),
		ast_channel_exten(s->chan),
		S_COR(ast_channel_caller(s->chan)->id.number.valid, ast_channel_caller(s->chan)->id.number.str, ""),
		S_COR(ast_channel_caller(s->chan)->id.name.valid, ast_channel_caller(s->chan)->id.name.str, ""),
		S_COR(ast_channel_connected(s->chan)->id.number.valid, ast_channel_connected(s->chan)->id.number.str, ""),
		S_COR(ast_channel_connected(s->chan)->id.name.valid, ast_channel_connected(s->chan)->id.name.str, ""),
		far_ident,
		local_ident,
		pages_transferred,
		stat.y_resolution,
		stat.bit_rate,
		s->file_name);
}

/* === Helper functions to configure fax === */

/* Setup SPAN logging according to Asterisk debug level */
static int set_logging(logging_state_t *state)
{
	int level = SPAN_LOG_WARNING + option_debug;

	span_log_set_message_handler(state, span_message);
	span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 

	return 0;
}
Beispiel #3
0
int main(int argc, char *argv[])
{
    logging_state_t *log;
    int i;
    uint8_t buf[1000];
    struct timespec delay;

    /* Set up a logger */
    if ((log = span_log_init(NULL, 123, "TAG")) == NULL)
    {
        fprintf(stderr, "Failed to initialise log.\n");
        exit(2);
    }
    /* Try it */
    span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
    if (span_log(log, SPAN_LOG_FLOW, "Logging to fprintf, as simple as %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");

    /* Now set a custom log handler */
    span_log_set_message_handler(log, &message_handler, NULL);
    span_log_set_sample_rate(log, 44100);

    /* Try the different logging elements */
    span_log_set_level(log, SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
    if (span_log(log, SPAN_LOG_FLOW, "Log with tag %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");
    span_log_set_level(log, SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    if (span_log(log, SPAN_LOG_FLOW, "Log with protocol %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");
    span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_FLOW);
    if (span_log(log, SPAN_LOG_ERROR, "Log with severity log %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");

    span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
    span_log_set_tag(log, "NewTag");
    if (span_log(log, SPAN_LOG_FLOW, "Log with new tag %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");

    span_log_set_protocol(log, "Protocol");
    if (span_log(log, SPAN_LOG_FLOW, "Log with protocol %d %d %d\n", 1, 2, 3))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");

    /* Test logging of buffer contents */
    for (i = 0;  i < 1000;  i++)
        buf[i] = i;
    if (span_log_buf(log, SPAN_LOG_FLOW, "Buf", buf, 10))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");
    if (span_log_buf(log, SPAN_LOG_FLOW, "Buf", buf, 1000))
        fprintf(stderr, "Logged.\n");
    else
        fprintf(stderr, "Not logged.\n");

    /* Test the correct severities will be logged */
    for (i = 0;  i < 10;  i++)
    {
        if (!span_log_test(log, i))
        {
            if (i != 6)
                tests_failed = true;
            break;
        }
    }

    /* Check timestamping by samples */
    span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW | SPAN_LOG_SHOW_SAMPLE_TIME);
    for (i = 0;  i < 10;  i++)
    {
        span_log(log, SPAN_LOG_FLOW, "Time tagged log %d %d %d\n", 1, 2, 3);
        span_log_bump_samples(log, 441*2);
    }

    /* Check timestamping by current date and time */
    span_log_set_message_handler(log, &message_handler2, NULL);
    span_log_set_level(log, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW | SPAN_LOG_SHOW_DATE);
    for (i = 0;  i < 10;  i++)
    {
        span_log(log, SPAN_LOG_FLOW, "Date/time tagged log %d %d %d\n", 1, 2, 3);
        delay.tv_sec = 0;
        delay.tv_nsec = 20000000;
        nanosleep(&delay, NULL);
    }
    if (tests_failed  ||  !msg_done)
    {
        printf("Tests failed - %d %d.\n", tests_failed, msg_done);
        return 2;
    }

    span_log_set_message_handler(log, &message_handler, NULL);

    printf("Tests passed.\n");
    return 0;
}
Beispiel #4
0
static int fax_audio(struct cw_channel *chan, fax_state_t *fax, const char *file, int calling_party, int verbose)
{
    char *x;
    struct cw_frame *inf = NULL;
    struct cw_frame outf;
    int ready = 1;
    int samples = 0;
    int res = 0;
    int len = 0;
    int generator_mode = 0;
    uint64_t begin = 0;
    uint64_t received_frames = 0;
    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET];
    uint8_t *buf = __buf + CW_FRIENDLY_OFFSET;
#if 0
    struct cw_frame *dspf = NULL;
    struct cw_dsp *dsp = NULL;
#endif
    uint64_t voice_frames;
    t30_state_t *t30;

    memset(fax, 0, sizeof(*fax));
    if (fax_init(fax, calling_party) == NULL)
    {
        cw_log(LOG_WARNING, "Unable to start FAX\n");
        return -1;
    }
    t30 = fax_get_t30_state(fax);
    fax_set_transmit_on_idle(fax, TRUE);
    span_log_set_message_handler(&fax->logging, span_message);
    span_log_set_message_handler(&t30->logging, span_message);
    if (verbose)
    {
        span_log_set_level(&fax->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
        span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    }

    fax_set_common(chan, t30, file, calling_party, verbose);
    fax_set_transmit_on_idle(fax, TRUE);

    if (calling_party)
    {
        voice_frames = 0;
    }
    else
    {
#if 0
        /* Initializing the DSP */
        if ((dsp = cw_dsp_new()) == NULL)
        {
            cw_log(LOG_WARNING, "Unable to allocate DSP!\n");
        }
        else
        {
            cw_dsp_set_threshold(dsp, 256); 
            cw_dsp_set_features(dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_CNG_DETECT);
            cw_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
        }
#endif
        voice_frames = 1;
    }

    /* This is the main loop */
    begin = nowis();
    while (ready  &&  ready_to_talk(chan))
    {
        if (chan->t38_status == T38_NEGOTIATED)
            break;

        if ((res = cw_waitfor(chan, 20)) < 0)
        {
            ready = 0;
            break;
        }

        if (!t30_call_active(t30))
            break;

        if ((inf = cw_read(chan)) == NULL)
        {
            ready = 0;
            break;
        }

        /* We got a frame */
        if (inf->frametype == CW_FRAME_VOICE)
        {
#if 0
            if (dsp)
            {
                if ((dspf = cw_frdup(inf)))
                    dspf = cw_dsp_process(chan, dsp, dspf);

                if (dspf)
                {
                    if (dspf->frametype == CW_FRAME_DTMF)
                    {
                        if (dspf->subclass == 'f')
                        {
                            cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n");
                            cw_app_request_t38(chan);
                            /* Prevent any further attempts to negotiate T.38 */
                            cw_dsp_free(dsp);
                            dsp = NULL;
                    
                        }
                    }
                    cw_fr_free(dspf);
                    dspf = NULL;
                }
            }
#else
            if (voice_frames)
            {
                /* Wait a little before trying to switch to T.38, as some things don't seem
                   to like entirely missing the audio. */
                if (++voice_frames == 100)
                {
                    cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n");
                    cw_app_request_t38(chan);
                    voice_frames = 0;
                }
            }
#endif
            received_frames++;

            if (fax_rx(fax, inf->data, inf->samples))
                break;

            samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
            if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0)
            {
                cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX");
                outf.datalen = len*sizeof(int16_t);
                outf.samples = len;
                outf.data = &buf[CW_FRIENDLY_OFFSET];
                outf.offset = CW_FRIENDLY_OFFSET;

                if (cw_write(chan, &outf) < 0)
                {
                    cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
                    break;
                }
            }
        }
        else
        {
            if ((nowis() - begin) > 1000000)
            {
                if (received_frames < 20)
                {
                    /* Just to be sure we have had no frames ... */
                    cw_log(LOG_NOTICE, "Switching to generator mode\n");
                    generator_mode = 1;
                    break;
                }
            }
        }
        cw_fr_free(inf);
        inf = NULL;
    }

    if (inf)
    {
        cw_fr_free(inf);
        inf = NULL;
    }
    if (generator_mode)
    {
        /* This is activated when we don't receive any frame for X seconds (see above)... */
        cw_log(LOG_NOTICE, "Starting generator\n");
#if 0
        if (dsp)
            cw_dsp_reset(dsp);
#endif
        cw_generator_activate(chan, &faxgen, fax);

        while (ready  &&  ready_to_talk(chan))
        {
            if (chan->t38_status == T38_NEGOTIATED)
                break;

            if ((res = cw_waitfor(chan, 20)) < 0)
            {
                ready = 0;
                break;
            }

            if (!t30_call_active(t30))
                break;

            if ((inf = cw_read(chan)) == NULL)
            {
                ready = 0;
                break;
            }

            /* We got a frame */
            if (inf->frametype == CW_FRAME_VOICE)
            {
#if 0
                if (dsp)
                {
                    if ((dspf = cw_frdup(inf)))
                        dspf = cw_dsp_process(chan, dsp, dspf);

                    if (dspf)
                    {
                        if (dspf->frametype == CW_FRAME_DTMF)
                        {
                            if (dspf->subclass == 'f')
                            {
                                cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n");
                                cw_app_request_t38(chan);
                                /* Prevent any further attempts to negotiate T.38 */
                                cw_dsp_free(dsp);
                                dsp = NULL;
                            }
                        }
                        cw_fr_free(dspf);
                        dspf = NULL;
                    }
                }
#else
                if (voice_frames)
                {
                    if (++voice_frames == 100)
                    {
                        cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n");
                        cw_app_request_t38(chan);
                        voice_frames = 0;
                    }
                }
#endif
                if (fax_rx(fax, inf->data, inf->samples))
                {
                    ready = 0;
                    break;
                }
            }

            cw_fr_free(inf);
            inf = NULL;
        }

        if (inf)
        {
            cw_fr_free(inf);
            inf = NULL;
        }
        cw_log(LOG_NOTICE, "Stopping generator\n");
        cw_generator_deactivate(chan);
    }
#if 0
    if (dsp)
        cw_dsp_free(dsp);
#endif
    return ready;
}
Beispiel #5
0
static int fax_t38(struct cw_channel *chan, t38_terminal_state_t *t38, const char *file, int calling_party, int verbose)
{
    char *x;
    struct cw_frame *inf = NULL;
    int ready = 1;
    int res = 0;
    uint64_t now;
    uint64_t passage;
    t30_state_t *t30;
    t38_core_state_t *t38_core;

    memset(t38, 0, sizeof(*t38));

    if (t38_terminal_init(t38, calling_party, t38_tx_packet_handler, chan) == NULL)
    {
        cw_log(LOG_WARNING, "Unable to start T.38 termination.\n");
        return -1;
    }
    t30 = t38_terminal_get_t30_state(t38);
    t38_core = t38_terminal_get_t38_core_state(t38);
    span_log_set_message_handler(&t38->logging, span_message);
    span_log_set_message_handler(&t30->logging, span_message);
    span_log_set_message_handler(&t38_core->logging, span_message);

    if (verbose)
    {
        span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
        span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
        span_log_set_level(&t38_core->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
    }

    fax_set_common(chan, t30, file, calling_party, verbose);

    passage = nowis();

    t38_terminal_set_tep_mode(t38, TRUE);
    while (ready  &&  ready_to_talk(chan))
    {
        if (chan->t38_status != T38_NEGOTIATED)
            break;

        if ((res = cw_waitfor(chan, 20)) < 0)
        {
            ready = 0;
            break;
        }

        now = nowis();
        t38_terminal_send_timeout(t38, (now - passage)/125);
        passage = now;
        /* End application when T38/T30 has finished */
        if (!t30_call_active(t30)) 
            break;

        if ((inf = cw_read(chan)) == NULL)
        {
            ready = 0;
            break;
        }

        if (inf->frametype == CW_FRAME_MODEM  &&  inf->subclass == CW_MODEM_T38)
            t38_core_rx_ifp_packet(t38_core, inf->data, inf->datalen, inf->seq_no);

        cw_fr_free(inf);
    }

    return ready;
}
int modem_close(modem_t *modem) 
{
	int r = 0;
	switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING);

	switch_clear_flag(modem, MODEM_FLAG_RUNNING);

#ifndef WIN32
	if (modem->master > -1) {
		shutdown(modem->master, 2);
		close(modem->master);
		modem->master = -1;
#else
	if (modem->master) {
		SetEvent(modem->threadAbort);
		CloseHandle(modem->threadAbort);
		CloseHandle(modem->master);
		modem->master = 0;
#endif
		
		r++;
	}

	if (modem->slave > -1) {
		shutdown(modem->slave, 2);
		close(modem->slave);
		modem->slave = -1;
		r++;
	}


   	if (modem->t31_state) {
		t31_free(modem->t31_state);
		modem->t31_state = NULL;
	}

	unlink(modem->devlink);

	if (was_running) {
		switch_mutex_lock(globals.mutex);
		globals.REF_COUNT--;
		switch_mutex_unlock(globals.mutex);
	}

	return r;
}


switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler)
{
	switch_status_t status = SWITCH_STATUS_SUCCESS;
#ifdef WIN32
	COMMTIMEOUTS timeouts={0};
#endif
	
	memset(modem, 0, sizeof(*modem));

	modem->master = -1;
	modem->slave = -1;

	/* windows will have to try something like:
	   http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED

	 */

#if USE_OPENPTY
    if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) {

	if (modem->master < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n");
		status = SWITCH_STATUS_FALSE;
		goto end;
    }

	modem->stty = ttyname(modem->slave);
#else
#if WIN32
	modem->slot = 4+globals.NEXT_ID++; /* need work here we start at COM4 for now*/
	snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot);

	modem->master = CreateFile(modem->devlink,
	GENERIC_READ | GENERIC_WRITE,
	0,
	0,
	OPEN_EXISTING,
	FILE_FLAG_OVERLAPPED,
	0);
	if(modem->master==INVALID_HANDLE_VALUE) {
		status = SWITCH_STATUS_FALSE;
		if(GetLastError()==ERROR_FILE_NOT_FOUND) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n");
			goto end;
		}
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n");
		goto end;
	}
#elif !defined(HAVE_POSIX_OPENPT)
    modem->master = open("/dev/ptmx", O_RDWR);
#else
    modem->master = posix_openpt(O_RDWR | O_NOCTTY);
#endif

#ifndef WIN32
    if (modem->master < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n");
		
    }

    if (grantpt(modem->master) < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n");
		
    }

    if (unlockpt(modem->master) < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n");
		
    }

    modem->stty = ptsname(modem->master);

    if (modem->stty == NULL) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n");
		
    }

    modem->slave = open(modem->stty, O_RDWR);

    if (modem->slave < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty);
    }
#endif

#ifdef SOLARIS
    ioctl(modem->slave, I_PUSH, "ptem");  /* push ptem */
    ioctl(modem->slave, I_PUSH, "ldterm");    /* push ldterm*/
#endif
#endif

#ifndef WIN32
	modem->slot = globals.NEXT_ID++;
	snprintf(modem->devlink, sizeof(modem->devlink), "/dev/FS%d", modem->slot);
	
    unlink(modem->devlink);

    if (symlink(modem->stty, modem->devlink)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink);
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
    }

    if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) {
	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master));
	    modem_close(modem);
	    status = SWITCH_STATUS_FALSE;
	    goto end;
    }
#else
	timeouts.ReadIntervalTimeout=50;
	timeouts.ReadTotalTimeoutConstant=50;
	timeouts.ReadTotalTimeoutMultiplier=10;

	timeouts.WriteTotalTimeoutConstant=50;
	timeouts.WriteTotalTimeoutMultiplier=10;

	SetCommMask(modem->master, EV_RXCHAR);

	if(!SetCommTimeouts(modem->master, &timeouts)){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink);
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
	}
	modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL);
#endif
	
	if (!(modem->t31_state = t31_init(NULL, t31_at_tx_handler, modem, t31_call_control_handler, modem, NULL, NULL))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n");
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
	}

	if (spandsp_globals.modem_verbose) {
		span_log_set_message_handler(&modem->t31_state->logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v17_rx.logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v29_rx.logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging, spanfax_log_message, NULL);

		modem->t31_state->logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v17_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v29_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
	}

	modem->control_handler = control_handler;
	modem->flags = 0;
	switch_set_flag(modem, MODEM_FLAG_RUNNING);

	switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED, globals.pool);
	switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
	switch_thread_cond_create(&modem->cond, globals.pool);

	modem_set_state(modem, MODEM_STATE_INIT);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty);

	switch_mutex_lock(globals.mutex);
	globals.REF_COUNT++;
	switch_mutex_unlock(globals.mutex);

end:
	return status;
}

static switch_endpoint_interface_t *modem_endpoint_interface = NULL;

struct private_object {
	switch_mutex_t *mutex;
	switch_core_session_t *session;
	switch_channel_t *channel;
	switch_codec_t read_codec;
	switch_codec_t write_codec;
	switch_frame_t read_frame;
	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
	switch_timer_t timer;
	modem_t *modem;
	switch_caller_profile_t *caller_profile;
	int dead;
};

typedef struct private_object private_t;

static switch_status_t channel_on_init(switch_core_session_t *session);
static switch_status_t channel_on_hangup(switch_core_session_t *session);
static switch_status_t channel_on_destroy(switch_core_session_t *session);
static switch_status_t channel_on_routing(switch_core_session_t *session);
static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
													switch_caller_profile_t *outbound_profile,
													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
													switch_call_cause_t *cancel_cause);
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);


/* 
   State methods they get called when the state changes to the specific state 
   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
*/
static switch_status_t channel_on_init(switch_core_session_t *session)
{
	switch_channel_t *channel;
	private_t *tech_pvt = NULL;
	int to_ticks = 60, ring_ticks = 10, rt = ring_ticks;
	int rest = 500000;
	
	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);

	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
#ifndef WIN32
		int tioflags;
#endif
		char call_time[16];
		char call_date[16];
		switch_size_t retsize;
		switch_time_exp_t tm;

		switch_time_exp_lt(&tm, switch_micro_time_now());
		switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm);
		switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm);

#ifndef WIN32
		ioctl(tech_pvt->modem->slave, TIOCMGET, &tioflags);
		tioflags |= TIOCM_RI;
		ioctl(tech_pvt->modem->slave, TIOCMSET, &tioflags);
#endif

		at_reset_call_info(&tech_pvt->modem->t31_state->at_state);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "DATE", call_date);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "TIME", call_time);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NAME", tech_pvt->caller_profile->caller_id_name);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NMBR", tech_pvt->caller_profile->caller_id_number);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "ANID", tech_pvt->caller_profile->ani);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "USER", tech_pvt->caller_profile->username);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "CDID", tech_pvt->caller_profile->context);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NDID", tech_pvt->caller_profile->destination_number);

		modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING);
		t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING);
		
		while(to_ticks > 0 && switch_channel_up(channel) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) {
			if (--rt <= 0) {
				t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING);
				rt = ring_ticks;
			}
			
			switch_yield(rest);
			to_ticks--;
		}
		
		if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) {
			t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER);
			switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER);
		} else {
			t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED);
			modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED);
			switch_channel_mark_answered(channel);
		}
	}

	switch_channel_set_state(channel, CS_ROUTING);
	
	return SWITCH_STATUS_SUCCESS;
}
Beispiel #7
0
static int fax_initGW(fax_params_t *f_params)
{
    t38_gateway_state_t *t38_gw;
    t38_core_state_t *t38_core;
    logging_state_t *logging;
    session_t *session;
    int log_level;
    int ret_val = 0;
    int fec_entries = DEFAULT_FEC_ENTRIES;
    int fec_span = DEFAULT_FEC_SPAN;
    int supported_modems;

    if(!f_params)
    {
        ret_val = -1; goto _exit;
    }

    session = f_params->session;

    app_trace(TRACE_INFO, "Fax %04x. Init T.38-fax gateway", session->ses_id);

    memset(f_params->pvt.t38_gw_state, 0, sizeof(t38_gateway_state_t));

    if(t38_gateway_init(f_params->pvt.t38_gw_state, t38_tx_packet_handler,
                         f_params) == NULL)
    {
        app_trace(TRACE_ERR, "Fax %04x. Cannot initialize T.38 structs",
                  session->ses_id);
        ret_val = -2; goto _exit;
    }

    t38_gw = f_params->pvt.t38_gw_state;

    t38_core = f_params->pvt.t38_core = t38_gateway_get_t38_core_state(t38_gw);

    t38_gateway_set_transmit_on_idle(t38_gw, TRANSMIT_ON_IDLE);
    t38_gateway_set_tep_mode(t38_gw, TEP_MODE);

    if(udptl_init(f_params->pvt.udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY,
                  fec_span, fec_entries,
                  (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet,
                  (void *) f_params->pvt.t38_core) == NULL)
    {
        app_trace(TRACE_ERR, "Fax %04x. Cannot initialize UDPTL structs",
                  session->ses_id);
        ret_val = -3; goto _exit;
    }

    if(f_params->pvt.verbose)
    {
        log_level = SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG |
                SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL |
                SPAN_LOG_FLOW;

        logging = t38_gateway_get_logging_state(t38_gw);
        span_log_set_message_handler(logging, fax_spandspLog);
        span_log_set_level(logging, log_level);
        span_log_set_tag(logging, f_params->log_tag);

        logging = t38_core_get_logging_state(t38_core);
        span_log_set_message_handler(logging, fax_spandspLog);
        span_log_set_level(logging, log_level);
        span_log_set_tag(logging, f_params->log_tag);
    }

	supported_modems = T30_SUPPORT_V29 | T30_SUPPORT_V27TER;
	if(!f_params->pvt.disable_v17) supported_modems |= T30_SUPPORT_V17;

	t38_gateway_set_supported_modems(t38_gw, supported_modems);
	t38_gateway_set_ecm_capability(t38_gw, f_params->pvt.use_ecm);

_exit:
	return ret_val;
}
Beispiel #8
0
/*
 *  Init appropriate spandsp objects to receive fax
 */
static int spanfax_init(fax_session_t *f_session, fax_transport_mod_e trans_mode)
{
    t38_terminal_state_t *t38;
    t38_core_state_t *t38_core;
    t30_state_t *t30;
    logging_state_t *logging;
    int log_level;

    int fec_entries = DEFAULT_FEC_ENTRIES;
    int fec_span = DEFAULT_FEC_SPAN;

    printf("fax: %s: start!\n", __func__);

    switch(trans_mode) {
        case FAX_TRANSPORT_T38_MOD:

            memset(f_session->pvt.t38_state, 0, sizeof(t38_terminal_state_t));

			if (t38_terminal_init(f_session->pvt.t38_state, f_session->pvt.caller,
								  t38_tx_packet_handler, f_session) == NULL) {
				printf("fax: Cannot initialize T.38 structs\n");
				return 0;
			}

			t38 = f_session->pvt.t38_state;
			t30 = t38_terminal_get_t30_state(t38);

			t38_core = f_session->pvt.t38_core = t38_terminal_get_t38_core_state(t38);
			t38_terminal_set_config(t38, 0);
			t38_terminal_set_tep_mode(t38, 0);

			if (udptl_init(f_session->pvt.udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY,
						   fec_span, fec_entries, (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet,
						   (void *) f_session->pvt.t38_core) == NULL) {
				printf("fax: Cannot initialize UDPTL structs\n");
				return 0;
			}

			if (f_session->pvt.verbose) {
				log_level = SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG |
						SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL |
						SPAN_LOG_FLOW;

				logging = t38_terminal_get_logging_state(t38);
				span_log_set_message_handler(logging, spanfax_log_message);
				span_log_set_level(logging, log_level);
				span_log_set_tag(logging, f_session->log_tag);

				logging = t38_core_get_logging_state(t38_core);
				span_log_set_message_handler(logging, spanfax_log_message);
				span_log_set_level(logging, log_level);
				span_log_set_tag(logging, f_session->log_tag);

				logging = t30_get_logging_state(t30);
				span_log_set_message_handler(logging, spanfax_log_message);
				span_log_set_level(logging, log_level);
				span_log_set_tag(logging, f_session->log_tag);
			}

            break;
        case FAX_TRANSPORT_AUDIO_MOD:
        default:
            return 0;
            break;
    }

	/* All the things which are common to audio and T.38 FAX setup */

	t30_set_tx_ident(t30, f_session->pvt.ident);
	t30_set_tx_page_header_info(t30, f_session->pvt.header);

	t30_set_phase_e_handler(t30, phase_e_handler, f_session);
	t30_set_phase_d_handler(t30, phase_d_handler, f_session);
	t30_set_phase_b_handler(t30, phase_b_handler, f_session);

	t30_set_supported_image_sizes(t30, T30_SUPPORT_US_LETTER_LENGTH
								  | T30_SUPPORT_US_LEGAL_LENGTH
								  | T30_SUPPORT_UNLIMITED_LENGTH
								  | T30_SUPPORT_215MM_WIDTH
								  | T30_SUPPORT_255MM_WIDTH
								  | T30_SUPPORT_303MM_WIDTH
								  );
	t30_set_supported_resolutions(t30, T30_SUPPORT_STANDARD_RESOLUTION
								  | T30_SUPPORT_FINE_RESOLUTION
								  | T30_SUPPORT_SUPERFINE_RESOLUTION
								  | T30_SUPPORT_R16_RESOLUTION
								  |	T30_SUPPORT_R8_RESOLUTION
								  | T30_SUPPORT_300_300_RESOLUTION
								  | T30_SUPPORT_400_400_RESOLUTION
								  | T30_SUPPORT_600_600_RESOLUTION
								  |	T30_SUPPORT_1200_1200_RESOLUTION
								  |	T30_SUPPORT_300_600_RESOLUTION
								  | T30_SUPPORT_400_800_RESOLUTION
								  | T30_SUPPORT_600_1200_RESOLUTION
								  );
#if 0
	t30_set_supported_colour_resolutions(t30, 0);
#endif

	if (f_session->pvt.disable_v17) {
		t30_set_supported_modems(t30, T30_SUPPORT_V29 | T30_SUPPORT_V27TER);
	} else {
		t30_set_supported_modems(t30, T30_SUPPORT_V29 | T30_SUPPORT_V27TER
								 | T30_SUPPORT_V17);
	}

	if (f_session->pvt.use_ecm) {
		t30_set_ecm_capability(t30, TRUE);
		t30_set_supported_compressions(t30,
									   T30_SUPPORT_T4_1D_COMPRESSION
									   | T30_SUPPORT_T4_2D_COMPRESSION
									   | T30_SUPPORT_T6_COMPRESSION
									   | T30_SUPPORT_T85_COMPRESSION
									   | T30_SUPPORT_T85_L0_COMPRESSION);
	} else {
		t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION
									   | T30_SUPPORT_T4_2D_COMPRESSION);
	}

	if (f_session->pvt.caller) {
		t30_set_tx_file(t30, f_session->pvt.filename, -1, -1);
	} else {
		t30_set_rx_file(t30, f_session->pvt.filename, -1);
	}

	return 0;
}