static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; struct ast_format format; const char *conf_name = data; chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CBRec/conf-%s-uid-%d", conf_name, (int) ast_random()); if (!chan) { return NULL; } if (ast_channel_add_bridge_role(chan, "recorder")) { ast_channel_release(chan); return NULL; } ast_format_set(&format, AST_FORMAT_SLINEAR, 0); ast_channel_tech_set(chan, conf_record_get_tech()); ast_format_cap_add_all(ast_channel_nativeformats(chan)); ast_format_copy(ast_channel_writeformat(chan), &format); ast_format_copy(ast_channel_rawwriteformat(chan), &format); ast_format_copy(ast_channel_readformat(chan), &format); ast_format_copy(ast_channel_rawreadformat(chan), &format); return chan; }
static void *playtones_alloc(struct ast_channel *chan, void *params) { struct playtones_def *pd = params; struct playtones_state *ps = NULL; if (!(ps = ast_calloc(1, sizeof(*ps)))) { return NULL; } ast_format_copy(&ps->origwfmt, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan)); playtones_release(NULL, ps); ps = NULL; } else { ps->vol = pd->vol; ps->reppos = pd->reppos; ps->nitems = pd->nitems; ps->items = pd->items; ps->oldnpos = -1; } /* Let interrupts interrupt :) */ if (pd->interruptible) { ast_set_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); } else { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); } return ps; }
static int dahdiscan_exec(struct ast_channel *chan, const char *data) { const char *spec = "DAHDI"; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '#', .volume = '\0', .exit = '*', }; struct ast_format *oldwf; int res; char *mygroup = NULL; /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); if (!ast_strlen_zero(data)) { mygroup = ast_strdupa(data); } ast_set_flag(&flags, OPTION_DTMF_EXIT); ast_set_flag(&flags, OPTION_DTMF_CYCLE); ast_set_flag(&flags, OPTION_DAHDI_SCAN); oldwf = ao2_bump(ast_channel_writeformat(chan)); if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); ao2_cleanup(oldwf); return -1; } res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); ao2_cleanup(oldwf); return res; } static int unload_module(void) { int res = 0; res |= ast_unregister_application(app_chan); res |= ast_unregister_application(app_ext); res |= ast_unregister_application(app_dahdiscan); return res; }
static int dahdiscan_exec(struct ast_channel *chan, const char *data) { const char *spec = "DAHDI"; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '#', .volume = '\0', .exit = '*', }; struct ast_format oldwf; int res; char *mygroup = NULL; ast_clear_flag(&flags, AST_FLAGS_ALL); ast_format_clear(&oldwf); if (!ast_strlen_zero(data)) { mygroup = ast_strdupa(data); } ast_set_flag(&flags, OPTION_DTMF_EXIT); ast_set_flag(&flags, OPTION_DTMF_CYCLE); ast_set_flag(&flags, OPTION_DAHDI_SCAN); ast_format_copy(&oldwf, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; } static int unload_module(void) { int res = 0; res |= ast_unregister_application(app_chan); res |= ast_unregister_application(app_ext); res |= ast_unregister_application(app_dahdiscan); return res; }
/*! \brief Function called when we should prepare to call the destination */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) { char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control; struct ast_rtp_instance *instance; struct ast_sockaddr control_address; struct ast_sockaddr destination_address; struct ast_channel *chan; struct ast_format fmt; ast_best_codec(cap, &fmt); ast_sockaddr_setnull(&control_address); /* If no type was given we can't do anything */ if (ast_strlen_zero(multicast_type)) { goto failure; } if (!(destination = strchr(tmp, '/'))) { goto failure; } *destination++ = '\0'; if ((control = strchr(destination, '/'))) { *control++ = '\0'; if (!ast_sockaddr_parse(&control_address, control, PARSE_PORT_REQUIRE)) { goto failure; } } if (!ast_sockaddr_parse(&destination_address, destination, PARSE_PORT_REQUIRE)) { goto failure; } if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) { goto failure; } if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", requestor ? ast_channel_linkedid(requestor) : "", 0, "MulticastRTP/%p", instance))) { ast_rtp_instance_destroy(instance); goto failure; } ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan)); ast_rtp_instance_set_remote_address(instance, &destination_address); ast_channel_tech_set(chan, &multicast_rtp_tech); ast_format_cap_add(ast_channel_nativeformats(chan), &fmt); ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_channel_tech_pvt_set(chan, instance); return chan; failure: *cause = AST_CAUSE_FAILURE; return NULL; }
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) { RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup); enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT; int fmts = 0; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && ast_format_cap_count(session->direct_media_cap); if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); return -1; } /* get the endpoint capabilities */ if (direct_media_enabled) { ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); format_cap_only_type(caps, media_type); } else { ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } /* get the capabilities on the peer */ get_codecs(session, stream, &codecs); ast_rtp_codecs_payload_formats(&codecs, peer, &fmts); /* get the joint capabilities between peer and endpoint */ ast_format_cap_get_compatible(caps, peer, joint); if (!ast_format_cap_count(joint)) { struct ast_str *usbuf = ast_str_alloca(64); struct ast_str *thembuf = ast_str_alloca(64); ast_rtp_codecs_payloads_destroy(&codecs); ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n", session_media->stream_type, ast_format_cap_get_names(caps, &usbuf), ast_format_cap_get_names(peer, &thembuf)); return -1; } ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp); ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN); if (session->channel) { struct ast_format *fmt; ast_channel_lock(session->channel); ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(caps, media_type); /* * XXX Historically we picked the "best" joint format to use * and stuck with it. It would be nice to just append the * determined joint media capabilities to give translation * more formats to choose from when necessary. Unfortunately, * there are some areas of the system where this doesn't work * very well. (The softmix bridge in particular is reluctant * to pick higher fidelity formats and has a problem with * asymmetric sample rates.) */ fmt = ast_format_cap_get_format(joint, 0); ast_format_cap_append(caps, fmt, 0); /* * Apply the new formats to the channel, potentially changing * raw read/write formats and translation path while doing so. */ ast_channel_nativeformats_set(session->channel, caps); ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); ast_channel_unlock(session->channel); ao2_ref(fmt, -1); } ast_rtp_codecs_payloads_destroy(&codecs); return 0; }
static int chanspy_exec(struct ast_channel *chan, const char *data) { char *myenforced = NULL; char *mygroup = NULL; char *recbase = NULL; int fd = 0; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '*', .volume = '#', .exit = '\0', }; RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup); int volfactor = 0; int res; char *mailbox = NULL; char *name_context = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(spec); AST_APP_ARG(options); ); char *opts[OPT_ARG_ARRAY_SIZE]; char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); if (args.spec && !strcmp(args.spec, "all")) args.spec = NULL; if (args.options) { char tmp; ast_app_parse_options(spy_opts, &flags, opts, args.options); if (ast_test_flag(&flags, OPTION_GROUP)) mygroup = opts[OPT_ARG_GROUP]; if (ast_test_flag(&flags, OPTION_RECORD) && !(recbase = opts[OPT_ARG_RECORD])) recbase = "chanspy"; if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { tmp = opts[OPT_ARG_EXIT][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.exit = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { tmp = opts[OPT_ARG_CYCLE][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.cycle = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { int vol; if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); else volfactor = vol; } if (ast_test_flag(&flags, OPTION_PRIVATE)) ast_set_flag(&flags, OPTION_WHISPER); if (ast_test_flag(&flags, OPTION_ENFORCED)) myenforced = opts[OPT_ARG_ENFORCED]; if (ast_test_flag(&flags, OPTION_NAME)) { if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { char *delimiter; if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { mailbox = opts[OPT_ARG_NAME]; *delimiter++ = '\0'; name_context = delimiter; } else { mailbox = opts[OPT_ARG_NAME]; } } } } else { ast_clear_flag(&flags, AST_FLAGS_ALL); } oldwf = ao2_bump(ast_channel_writeformat(chan)); if (ast_set_write_format(chan, ast_format_slin) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } if (recbase) { char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); fd = 0; } } res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); if (fd) close(fd); if (oldwf && ast_set_write_format(chan, oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) { ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n"); } return res; }
static int transmit_audio(fax_session *s) { int res = -1; struct ast_format original_read_fmt; struct ast_format original_write_fmt; fax_state_t fax; t30_state_t *t30state; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change; enum ast_t38_state t38_state; struct ast_control_t38_parameters t38_parameters = { .version = 0, .max_ifp = 800, .rate = AST_T38_RATE_14400, .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, .fill_bit_removal = 1, /* * spandsp has API calls to support MMR and JBIG transcoding, but they aren't * implemented quite yet... so don't offer them to the remote endpoint * .transcoding_mmr = 1, * .transcoding_jbig = 1, */ }; ast_format_clear(&original_read_fmt); ast_format_clear(&original_write_fmt); /* if in called party mode, try to use T.38 */ if (s->caller_mode == FALSE) { /* check if we are already in T.38 mode (unlikely), or if we can request * a switch... if so, request it now and wait for the result, rather * than starting an audio FAX session that will have to be cancelled */ if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) { return 1; } else if ((t38_state != T38_STATE_UNAVAILABLE) && (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE, (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_NEGOTIATED: ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan)); res = 1; break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); if (res == 1) { return 1; } else { break; } } ast_frfree(inf); } } } #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &fax.t30; #else /* for spandsp release 0.0.5 */ t30state = &fax.t30_state; #endif ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan)); if (original_read_fmt.id != AST_FORMAT_SLINEAR) { res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); goto done; } } ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan)); if (original_write_fmt.id != AST_FORMAT_SLINEAR) { res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); goto done; } } /* Initialize T30 terminal */ fax_init(&fax, s->caller_mode); /* Setup logging */ set_logging(&fax.logging); set_logging(&t30state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); fax_set_transmit_on_idle(&fax, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); start = state_change = ast_tvnow(); ast_activate_generator(s->chan, &generator, &fax); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen); /* Check the frame type. Format also must be checked because there is a chance that a frame in old format was already queued before we set channel format to slinear so it will still be received by ast_read */ if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) { if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) { /* I know fax_rx never returns errors. The check here is for good style only */ ast_log(LOG_WARNING, "fax_rx returned error\n"); res = -1; break; } if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_NEGOTIATED) { /* T38 switchover completed */ s->t38parameters = *parameters; ast_debug(1, "T38 negotiated, finishing audio loop\n"); res = 1; break; } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) { t38_parameters.request_response = AST_T38_NEGOTIATED; ast_debug(1, "T38 request received, accepting\n"); /* Complete T38 switchover */ ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); /* Do not break audio loop, wait until channel driver finally acks switchover * with AST_T38_NEGOTIATED */ } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); ast_deactivate_generator(s->chan); /* If we are switching to T38, remove phase E handler. Otherwise it will be executed by t30_terminate, display diagnostics and set status variables although no transmittion has taken place yet. */ if (res > 0) { t30_set_phase_e_handler(t30state, NULL, NULL); } t30_terminate(t30state); fax_release(&fax); done: if (original_write_fmt.id != AST_FORMAT_SLINEAR) { if (ast_set_write_format(s->chan, &original_write_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan)); } if (original_read_fmt.id != AST_FORMAT_SLINEAR) { if (ast_set_read_format(s->chan, &original_read_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan)); } return res; } static int transmit_t38(fax_session *s) { int res = 0; t38_terminal_state_t t38; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change, last_frame; t30_state_t *t30state; t38_core_state_t *t38state; #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &t38.t30; t38state = &t38.t38_fe.t38; #else /* for spandsp releases 0.0.5 */ t30state = &t38.t30_state; t38state = &t38.t38; #endif /* Initialize terminal */ memset(&t38, 0, sizeof(t38)); if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) { ast_log(LOG_WARNING, "Unable to start T.38 termination.\n"); res = -1; goto disable_t38; } t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp); if (s->t38parameters.fill_bit_removal) { t38_set_fill_bit_removal(t38state, TRUE); } if (s->t38parameters.transcoding_mmr) { t38_set_mmr_transcoding(t38state, TRUE); } if (s->t38parameters.transcoding_jbig) { t38_set_jbig_transcoding(t38state, TRUE); } /* Setup logging */ set_logging(&t38.logging); set_logging(&t30state->logging); set_logging(&t38state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); now = start = state_change = ast_tvnow(); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } last_frame = now; /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000)); if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen); if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) { t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno); if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_TERMINATED) { ast_debug(1, "T38 down, finishing\n"); break; } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); t30_terminate(t30state); t38_terminal_release(&t38); disable_t38: /* if we are not the caller, it's our job to shut down the T.38 * session when the FAX transmisson is complete. */ if ((s->caller_mode == FALSE) && (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) { struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, }; if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_TERMINATED: ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan)); break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); break; } ast_frfree(inf); } } } return res; }
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { long elapsed_seconds = 0; int hour = 0, min = 0, sec = 0; struct ast_str *format_buf = ast_str_alloca(64); char cgrp[256]; char pgrp[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); struct ast_bridge *bridge; memset(buf, 0, size); if (!c) return 0; elapsed_seconds = ast_channel_get_duration(c); hour = elapsed_seconds / 3600; min = (elapsed_seconds % 3600) / 60; sec = elapsed_seconds % 60; ast_channel_lock(c); bridge = ast_channel_get_bridge(c); ast_channel_unlock(c); snprintf(buf,size, "Name= %s\n" "Type= %s\n" "UniqueID= %s\n" "LinkedID= %s\n" "CallerIDNum= %s\n" "CallerIDName= %s\n" "ConnectedLineIDNum= %s\n" "ConnectedLineIDName=%s\n" "DNIDDigits= %s\n" "RDNIS= %s\n" "Parkinglot= %s\n" "Language= %s\n" "State= %s (%u)\n" "Rings= %d\n" "NativeFormat= %s\n" "WriteFormat= %s\n" "ReadFormat= %s\n" "RawWriteFormat= %s\n" "RawReadFormat= %s\n" "WriteTranscode= %s %s\n" "ReadTranscode= %s %s\n" "1stFileDescriptor= %d\n" "Framesin= %u %s\n" "Framesout= %u %s\n" "TimetoHangup= %ld\n" "ElapsedTime= %dh%dm%ds\n" "BridgeID= %s\n" "Context= %s\n" "Extension= %s\n" "Priority= %d\n" "CallGroup= %s\n" "PickupGroup= %s\n" "Application= %s\n" "Data= %s\n" "Blocking_in= %s\n", ast_channel_name(c), ast_channel_tech(c)->type, ast_channel_uniqueid(c), ast_channel_linkedid(c), S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"), S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"), S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"), S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"), S_OR(ast_channel_dialed(c)->number.str, "(N/A)"), S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, "(N/A)"), ast_channel_parkinglot(c), ast_channel_language(c), ast_state2str(ast_channel_state(c)), ast_channel_state(c), ast_channel_rings(c), ast_format_cap_get_names(ast_channel_nativeformats(c), &format_buf), ast_format_get_name(ast_channel_writeformat(c)), ast_format_get_name(ast_channel_readformat(c)), ast_format_get_name(ast_channel_rawwriteformat(c)), ast_format_get_name(ast_channel_rawreadformat(c)), ast_channel_writetrans(c) ? "Yes" : "No", ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath), ast_channel_readtrans(c) ? "Yes" : "No", ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath), ast_channel_fd(c, 0), ast_channel_fin(c) & ~DEBUGCHAN_FLAG, (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", ast_channel_fout(c) & ~DEBUGCHAN_FLAG, (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)ast_channel_whentohangup(c)->tv_sec, hour, min, sec, bridge ? bridge->uniqueid : "(Not bridged)", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_print_group(cgrp, sizeof(cgrp), ast_channel_callgroup(c)), ast_print_group(pgrp, sizeof(pgrp), ast_channel_pickupgroup(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)", ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)", (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)")); ao2_cleanup(bridge); return 0; }
int ast_channel_data_add_structure(struct ast_data *tree, struct ast_channel *chan, int add_bridged) { struct ast_data *data_bridged; struct ast_data *data_cdr; struct ast_data *data_flags; struct ast_data *data_zones; struct ast_data *enum_node; struct ast_data *data_softhangup; #if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ struct ast_data *data_callerid; char value_str[100]; #endif if (!tree) { return -1; } ast_data_add_structure(ast_channel, tree, chan); if (add_bridged) { RAII_VAR(struct ast_channel *, bc, ast_channel_bridge_peer(chan), ast_channel_cleanup); if (bc) { data_bridged = ast_data_add_node(tree, "bridged"); if (!data_bridged) { return -1; } ast_channel_data_add_structure(data_bridged, bc, 0); } } ast_data_add_codec(tree, "oldwriteformat", ast_channel_oldwriteformat(chan)); ast_data_add_codec(tree, "readformat", ast_channel_readformat(chan)); ast_data_add_codec(tree, "writeformat", ast_channel_writeformat(chan)); ast_data_add_codec(tree, "rawreadformat", ast_channel_rawreadformat(chan)); ast_data_add_codec(tree, "rawwriteformat", ast_channel_rawwriteformat(chan)); ast_data_add_codecs(tree, "nativeformats", ast_channel_nativeformats(chan)); /* state */ enum_node = ast_data_add_node(tree, "state"); if (!enum_node) { return -1; } ast_data_add_str(enum_node, "text", ast_state2str(ast_channel_state(chan))); ast_data_add_int(enum_node, "value", ast_channel_state(chan)); /* hangupcause */ enum_node = ast_data_add_node(tree, "hangupcause"); if (!enum_node) { return -1; } ast_data_add_str(enum_node, "text", ast_cause2str(ast_channel_hangupcause(chan))); ast_data_add_int(enum_node, "value", ast_channel_hangupcause(chan)); /* amaflags */ enum_node = ast_data_add_node(tree, "amaflags"); if (!enum_node) { return -1; } ast_data_add_str(enum_node, "text", ast_channel_amaflags2string(ast_channel_amaflags(chan))); ast_data_add_int(enum_node, "value", ast_channel_amaflags(chan)); /* transfercapability */ enum_node = ast_data_add_node(tree, "transfercapability"); if (!enum_node) { return -1; } ast_data_add_str(enum_node, "text", ast_transfercapability2str(ast_channel_transfercapability(chan))); ast_data_add_int(enum_node, "value", ast_channel_transfercapability(chan)); /* _softphangup */ data_softhangup = ast_data_add_node(tree, "softhangup"); if (!data_softhangup) { return -1; } ast_data_add_bool(data_softhangup, "dev", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_DEV); ast_data_add_bool(data_softhangup, "asyncgoto", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO); ast_data_add_bool(data_softhangup, "shutdown", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_SHUTDOWN); ast_data_add_bool(data_softhangup, "timeout", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_TIMEOUT); ast_data_add_bool(data_softhangup, "appunload", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_APPUNLOAD); ast_data_add_bool(data_softhangup, "explicit", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_EXPLICIT); ast_data_add_bool(data_softhangup, "unbridge", ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_UNBRIDGE); /* channel flags */ data_flags = ast_data_add_node(tree, "flags"); if (!data_flags) { return -1; } channel_data_add_flags(data_flags, chan); ast_data_add_uint(tree, "timetohangup", ast_channel_whentohangup(chan)->tv_sec); #if 0 /* XXX AstData: ast_callerid no longer exists. (Equivalent code not readily apparent.) */ /* callerid */ data_callerid = ast_data_add_node(tree, "callerid"); if (!data_callerid) { return -1; } ast_data_add_structure(ast_callerid, data_callerid, &(chan->cid)); /* insert the callerid ton */ enum_node = ast_data_add_node(data_callerid, "cid_ton"); if (!enum_node) { return -1; } ast_data_add_int(enum_node, "value", chan->cid.cid_ton); snprintf(value_str, sizeof(value_str), "TON: %s/Plan: %s", party_number_ton2str(chan->cid.cid_ton), party_number_plan2str(chan->cid.cid_ton)); ast_data_add_str(enum_node, "text", value_str); #endif /* tone zone */ if (ast_channel_zone(chan)) { data_zones = ast_data_add_node(tree, "zone"); if (!data_zones) { return -1; } ast_tone_zone_data_add_structure(data_zones, ast_channel_zone(chan)); } /* insert cdr */ data_cdr = ast_data_add_node(tree, "cdr"); if (!data_cdr) { return -1; } return 0; }
struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan) { struct ast_channel_snapshot *snapshot; struct ast_bridge *bridge; char nativeformats[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); struct ast_party_id effective_connected_id; struct ast_callid *callid; /* no snapshots for dummy channels */ if (!ast_channel_tech(chan)) { return NULL; } snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor); if (!snapshot || ast_string_field_init(snapshot, 1024)) { ao2_cleanup(snapshot); return NULL; } ast_string_field_set(snapshot, name, ast_channel_name(chan)); ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type); ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan)); ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan)); ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan)); ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan)); ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan)); ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan)); if (ast_channel_appl(chan)) { ast_string_field_set(snapshot, appl, ast_channel_appl(chan)); } if (ast_channel_data(chan)) { ast_string_field_set(snapshot, data, ast_channel_data(chan)); } ast_string_field_set(snapshot, context, ast_channel_context(chan)); ast_string_field_set(snapshot, exten, ast_channel_exten(chan)); ast_string_field_set(snapshot, caller_name, S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "")); ast_string_field_set(snapshot, caller_number, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "")); ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); ast_string_field_set(snapshot, caller_subaddr, S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, "")); ast_string_field_set(snapshot, dialed_subaddr, S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, "")); ast_string_field_set(snapshot, caller_ani, S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "")); ast_string_field_set(snapshot, caller_rdnis, S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "")); ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); ast_string_field_set(snapshot, connected_name, S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "")); ast_string_field_set(snapshot, connected_number, S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "")); ast_string_field_set(snapshot, language, ast_channel_language(chan)); if ((bridge = ast_channel_get_bridge(chan))) { ast_string_field_set(snapshot, bridgeid, bridge->uniqueid); ao2_cleanup(bridge); } ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan))); ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan))); ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan))); ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath)); ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath)); effective_connected_id = ast_channel_connected_effective_id(chan); ast_string_field_set(snapshot, effective_name, S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "")); ast_string_field_set(snapshot, effective_number, S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "")); if ((callid = ast_channel_callid(chan))) { ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid); ast_callid_unref(callid); } snapshot->creationtime = ast_channel_creationtime(chan); snapshot->hanguptime = *(ast_channel_whentohangup(chan)); snapshot->state = ast_channel_state(chan); snapshot->priority = ast_channel_priority(chan); snapshot->amaflags = ast_channel_amaflags(chan); snapshot->hangupcause = ast_channel_hangupcause(chan); ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF); snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id); snapshot->callgroup = ast_channel_callgroup(chan); snapshot->pickupgroup = ast_channel_pickupgroup(chan); ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan)); snapshot->manager_vars = ast_channel_get_manager_vars(chan); snapshot->channel_vars = ast_channel_get_vars(chan); snapshot->tech_properties = ast_channel_tech(chan)->properties; return snapshot; }
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) { RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy); RAII_VAR(struct ast_format_cap *, peer, NULL, ast_format_cap_destroy); RAII_VAR(struct ast_format_cap *, joint, NULL, ast_format_cap_destroy); enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); struct ast_rtp_codecs codecs; struct ast_format fmt; int fmts = 0; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && !ast_format_cap_is_empty(session->direct_media_cap); if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) || !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); return -1; } /* get the endpoint capabilities */ if (direct_media_enabled) { ast_format_cap_joint_copy(session->endpoint->media.codecs, session->direct_media_cap, caps); } else { ast_format_cap_copy(caps, session->endpoint->media.codecs); } format_cap_only_type(caps, media_type); /* get the capabilities on the peer */ get_codecs(session, stream, &codecs); ast_rtp_codecs_payload_formats(&codecs, peer, &fmts); /* get the joint capabilities between peer and endpoint */ if (!(joint = ast_format_cap_joint(caps, peer))) { char usbuf[64], thembuf[64]; ast_rtp_codecs_payloads_destroy(&codecs); ast_getformatname_multiple(usbuf, sizeof(usbuf), caps); ast_getformatname_multiple(thembuf, sizeof(thembuf), peer); ast_log(LOG_WARNING, "No joint capabilities between our configuration(%s) and incoming SDP(%s)\n", usbuf, thembuf); return -1; } ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp); ast_format_cap_copy(caps, session->req_caps); ast_format_cap_remove_bytype(caps, media_type); ast_format_cap_append(caps, joint); ast_format_cap_append(session->req_caps, caps); if (session->channel) { ast_format_cap_copy(caps, ast_channel_nativeformats(session->channel)); ast_format_cap_remove_bytype(caps, media_type); ast_codec_choose(&session->endpoint->media.prefs, joint, 1, &fmt); ast_format_cap_add(caps, &fmt); /* Apply the new formats to the channel, potentially changing read/write formats while doing so */ ast_format_cap_copy(ast_channel_nativeformats(session->channel), caps); ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); } ast_rtp_codecs_payloads_destroy(&codecs); return 0; }
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap) { struct ast_unreal_pvt *unreal; static const struct ast_jb_conf jb_conf = { .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = "", .target_extra = -1, }; unreal = ao2_alloc(size, destructor); if (!unreal) { return NULL; } unreal->reqcap = ast_format_cap_dup(cap); if (!unreal->reqcap) { ao2_ref(unreal, -1); return NULL; } memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf)); return unreal; } struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { struct ast_channel *owner; struct ast_channel *chan; struct ast_format fmt; struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL}; int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); /* set unique ids for the two channels */ if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) { id1.uniqueid = assignedids->uniqueid; id2.uniqueid = assignedids->uniqueid2; } /* if id1 given but not id2, use default of id1;2 */ if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) { char *uniqueid2; uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2); strcpy(uniqueid2, id1.uniqueid);/* Safe */ strcat(uniqueid2, ";2");/* Safe */ id2.uniqueid = uniqueid2; } /* * Allocate two new Asterisk channels * * Make sure that the ;2 channel gets the same linkedid as ;1. * You can't pass linkedid to both allocations since if linkedid * isn't set, then each channel will generate its own linkedid. */ if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL, exten, context, &id1, requestor, 0, "%s/%s-%08x;1", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n"); return NULL; } if (callid) { ast_channel_callid_set(owner, callid); } ast_channel_tech_set(owner, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(owner, p); ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap); /* Determine our read/write format and set it on each channel */ ast_best_codec(p->reqcap, &fmt); ast_format_copy(ast_channel_writeformat(owner), &fmt); ast_format_copy(ast_channel_rawwriteformat(owner), &fmt); ast_format_copy(ast_channel_readformat(owner), &fmt); ast_format_copy(ast_channel_rawreadformat(owner), &fmt); ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE); ast_jb_configure(owner, &p->jb_conf); if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) { ao2_ref(p, -1); ast_channel_unlock(owner); ast_channel_release(owner); return NULL; } p->owner = owner; ast_channel_unlock(owner); if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL, exten, context, &id2, owner, 0, "%s/%s-%08x;2", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n"); ao2_ref(p, -1); ast_channel_release(owner); return NULL; } if (callid) { ast_channel_callid_set(chan, callid); } ast_channel_tech_set(chan, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(chan, p); ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap); /* Format was already determined when setting up owner */ ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE); p->chan = chan; ast_channel_unlock(chan); return owner; }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; char tmp[512]; struct ast_format_cap *tmpcap; if (!strcasecmp(data, "audionativeformat")) { if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_AUDIO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "videonativeformat")) { if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), AST_FORMAT_TYPE_VIDEO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "audioreadformat")) { ast_copy_string(buf, ast_getformatname(ast_channel_readformat(chan)), len); } else if (!strcasecmp(data, "audiowriteformat")) { ast_copy_string(buf, ast_getformatname(ast_channel_writeformat(chan)), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); ast_channel_unlock(chan); #endif } else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len); else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, ast_channel_language(chan), len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, ast_channel_musicclass(chan), len); else if (!strcasecmp(data, "name")) { locked_copy_string(chan, buf, ast_channel_name(chan), len); } else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len); else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len); else if (!strcasecmp(data, "accountcode")) locked_copy_string(chan, buf, ast_channel_accountcode(chan), len); else if (!strcasecmp(data, "checkhangup")) { ast_channel_lock(chan); ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len); ast_channel_unlock(chan); } else if (!strcasecmp(data, "peeraccount")) locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len); else if (!strcasecmp(data, "hangupsource")) locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len); else if (!strcasecmp(data, "appname") && ast_channel_appl(chan)) locked_copy_string(chan, buf, ast_channel_appl(chan), len); else if (!strcasecmp(data, "appdata") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_data(chan), len); else if (!strcasecmp(data, "exten") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_exten(chan), len); else if (!strcasecmp(data, "context") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_context(chan), len); else if (!strcasecmp(data, "userfield") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_userfield(chan), len); else if (!strcasecmp(data, "channame") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_name(chan), len); else if (!strcasecmp(data, "linkedid")) { ast_channel_lock(chan); if (ast_strlen_zero(ast_channel_linkedid(chan))) { /* fall back on the channel's uniqueid if linkedid is unset */ ast_copy_string(buf, ast_channel_uniqueid(chan), len); } else { ast_copy_string(buf, ast_channel_linkedid(chan), len); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { struct ast_channel *p; ast_channel_lock(chan); p = ast_bridged_channel(chan); if (p || ast_channel_tech(chan) || ast_channel_cdr(chan)) /* dummy channel? if so, we hid the peer name in the language */ ast_copy_string(buf, (p ? ast_channel_name(p) : ""), len); else { /* a dummy channel can still pass along bridged peer info via the BRIDGEPEER variable */ const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); if (!ast_strlen_zero(pname)) ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ else buf[0] = 0; } ast_channel_unlock(chan); } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len); } else if (!strcasecmp(data, "transfercapability")) { locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len); } else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len); } else if (!strcasecmp(data, "pickupgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len); } else if (!strcasecmp(data, "amaflags")) { char amabuf[256]; snprintf(amabuf,sizeof(amabuf), "%d", ast_channel_amaflags(chan)); locked_copy_string(chan, buf, amabuf, len); } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; ast_channel_lock(chan); if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { struct ast_secure_call_store *encrypt = ds->data; if (!strcasecmp(data, "secure_bridge_signaling")) { snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); } else if (!strcasecmp(data, "secure_bridge_media")) { snprintf(buf, len, "%s", encrypt->media ? "1" : ""); } } ast_channel_unlock(chan); } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; struct ast_format_cap *tmpcap; if (!chan) { ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); return -1; } if (!strcasecmp(data, "audionativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { struct ast_str *codec_buf = ast_str_alloca(128); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO); ast_channel_unlock(chan); ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "videonativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { struct ast_str *codec_buf = ast_str_alloca(128); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO); ast_channel_unlock(chan); ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "audioreadformat")) { locked_copy_string(chan, buf, ast_format_get_name(ast_channel_readformat(chan)), len); } else if (!strcasecmp(data, "audiowriteformat")) { locked_copy_string(chan, buf, ast_format_get_name(ast_channel_writeformat(chan)), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { locked_copy_string(chan, buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); #endif } else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) { locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len); } else if (!strcasecmp(data, "dtmf_features")) { if (ast_bridge_features_ds_get_string(chan, buf, len)) { buf[0] = '\0'; } } else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, ast_channel_language(chan), len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, ast_channel_musicclass(chan), len); else if (!strcasecmp(data, "name")) { locked_copy_string(chan, buf, ast_channel_name(chan), len); } else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len); else if (!strcasecmp(data, "onhold")) { locked_copy_string(chan, buf, ast_channel_hold_state(chan) == AST_CONTROL_HOLD ? "1" : "0", len); } else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len); else if (!strcasecmp(data, "accountcode")) locked_copy_string(chan, buf, ast_channel_accountcode(chan), len); else if (!strcasecmp(data, "checkhangup")) { locked_copy_string(chan, buf, ast_check_hangup(chan) ? "1" : "0", len); } else if (!strcasecmp(data, "peeraccount")) locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len); else if (!strcasecmp(data, "hangupsource")) locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len); else if (!strcasecmp(data, "appname") && ast_channel_appl(chan)) locked_copy_string(chan, buf, ast_channel_appl(chan), len); else if (!strcasecmp(data, "appdata") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_data(chan), len); else if (!strcasecmp(data, "exten") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_exten(chan), len); else if (!strcasecmp(data, "context") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_context(chan), len); else if (!strcasecmp(data, "userfield") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_userfield(chan), len); else if (!strcasecmp(data, "channame") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_name(chan), len); else if (!strcasecmp(data, "linkedid")) { ast_channel_lock(chan); if (ast_strlen_zero(ast_channel_linkedid(chan))) { /* fall back on the channel's uniqueid if linkedid is unset */ ast_copy_string(buf, ast_channel_uniqueid(chan), len); } else { ast_copy_string(buf, ast_channel_linkedid(chan), len); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { struct ast_channel *peer; peer = ast_channel_bridge_peer(chan); if (peer) { /* Only real channels could have a bridge peer this way. */ ast_channel_lock(peer); ast_copy_string(buf, ast_channel_name(peer), len); ast_channel_unlock(peer); ast_channel_unref(peer); } else { buf[0] = '\0'; ast_channel_lock(chan); if (!ast_channel_tech(chan)) { const char *pname; /* * A dummy channel can still pass along bridged peer info * via the BRIDGEPEER variable. * * A horrible kludge, but... how else? */ pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); if (!ast_strlen_zero(pname)) { ast_copy_string(buf, pname, len); } } ast_channel_unlock(chan); } } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len); } else if (!strcasecmp(data, "transfercapability")) { locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len); } else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len); } else if (!strcasecmp(data, "pickupgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len); } else if (!strcasecmp(data, "namedcallgroup")) { struct ast_str *tmp_str = ast_str_alloca(1024); locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_callgroups(chan)), len); } else if (!strcasecmp(data, "namedpickupgroup")) { struct ast_str *tmp_str = ast_str_alloca(1024); locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len); } else if (!strcasecmp(data, "after_bridge_goto")) { ast_bridge_read_after_goto(chan, buf, len); } else if (!strcasecmp(data, "amaflags")) { ast_channel_lock(chan); snprintf(buf, len, "%u", ast_channel_amaflags(chan)); ast_channel_unlock(chan); } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; buf[0] = '\0'; ast_channel_lock(chan); if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { struct ast_secure_call_store *encrypt = ds->data; if (!strcasecmp(data, "secure_bridge_signaling")) { snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); } else if (!strcasecmp(data, "secure_bridge_media")) { snprintf(buf, len, "%s", encrypt->media ? "1" : ""); } } ast_channel_unlock(chan); } else if (!strcasecmp(data, "max_forwards")) { ast_channel_lock(chan); snprintf(buf, len, "%d", ast_max_forwards_get(chan)); ast_channel_unlock(chan); } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait) { unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL }; int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0; struct ast_format writeformat; struct ast_format readformat; ast_format_copy(&writeformat, ast_channel_writeformat(chan)); ast_format_copy(&readformat, ast_channel_readformat(chan)); for (x = 0; x < msglen; x += (msg[x+1]+2)) { if (msg[x] == ADSI_SWITCH_TO_DATA) { ast_debug(1, "Switch to data is sent!\n"); waitforswitch++; newdatamode = ADSI_FLAG_DATAMODE; } if (msg[x] == ADSI_SWITCH_TO_VOICE) { ast_debug(1, "Switch to voice is sent!\n"); waitforswitch++; newdatamode = 0; } } msgs[0] = msg; msglens[0] = msglen; msgtypes[0] = msgtype; if (msglen > 253) { ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen); return -1; } ast_stopstream(chan); if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) { ast_log(LOG_WARNING, "Unable to set write format to ULAW\n"); return -1; } if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) { ast_log(LOG_WARNING, "Unable to set read format to ULAW\n"); if (writeformat.id) { if (ast_set_write_format(chan, &writeformat)) { ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat)); } } return -1; } res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes); if (dowait) { ast_debug(1, "Wait for switch is '%d'\n", waitforswitch); while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) { res = 0; ast_debug(1, "Waiting for 'B'...\n"); } } if (!res) { ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode); } if (writeformat.id) { ast_set_write_format(chan, &writeformat); } if (readformat.id) { ast_set_read_format(chan, &readformat); } if (!res) { res = ast_safe_sleep(chan, 100 ); } return res; }
static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) { int res = 0; int fds[2]; int needed = 0; struct ast_format *owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[2048]; } myf = { .f = { 0, }, }; if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } /* Answer if it's not already going */ if (ast_channel_state(chan) != AST_STATE_UP) ast_answer(chan); ast_stopstream(chan); ast_indicate(chan, -1); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); ao2_cleanup(owriteformat); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = ast_format_slin; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.data.ptr = myf.frdata; res = send_waveform_to_fd(waveform, length, fds[1]); if (res >= 0) { /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { res = ast_waitfor(chan, 1000); if (res < 1) { res = -1; break; } f = ast_read(chan); if (!f) { ast_log(LOG_WARNING, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); if (intkeys && strchr(intkeys, f->subclass.integer)) { res = f->subclass.integer; ast_frfree(f); break; } } if (f->frametype == AST_FRAME_VOICE) { /* Treat as a generator */ needed = f->samples * 2; if (needed > sizeof(myf.frdata)) { ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n", (int)sizeof(myf.frdata) / 2, needed/2); needed = sizeof(myf.frdata); } res = read(fds[0], myf.frdata, needed); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); break; } if (res < needed) { /* last frame */ ast_debug(1, "Last frame\n"); res = 0; ast_frfree(f); break; } } else { ast_debug(1, "No more waveform\n"); res = 0; } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); ao2_cleanup(owriteformat); return res; }
/*! * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic. * * \param chan Asterisk Channel * \param data Application data * * \retval 0 success * \retval -1 failure */ static int alarmreceiver_exec(struct ast_channel *chan, const char *data) { int res = 0; int no_checksum = 0; event_node_t *elp, *efree; char signalling_type[64] = ""; event_node_t *event_head = NULL; if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n"); if (ast_set_write_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } } if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) && (ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) { ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n"); if (ast_set_read_format(chan, ast_format_ulaw)) { ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan)); return -1; } } /* Set default values for this invocation of the application */ ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type)); call_start_time = ast_tvnow(); /* Answer the channel if it is not already */ if (ast_channel_state(chan) != AST_STATE_UP) { ast_verb(4, "AlarmReceiver: Answering channel\n"); if (ast_answer(chan)) { return -1; } } /* Wait for the connection to settle post-answer */ ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n"); if (ast_safe_sleep(chan, answait)) { return -1; } /* Attempt to receive the events */ receive_ademco_event(chan, &event_head, signalling_type, &no_checksum); /* Events queued by receiver, write them all out here if so configured */ if (!log_individual_events) { res = log_events(chan, signalling_type, event_head, no_checksum); } /* Do we exec a command line at the end? */ if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) { ast_debug(1,"Alarmreceiver: executing: %s\n", event_app); ast_safe_system(event_app); } /* Free up the data allocated in our linked list */ for (elp = event_head; (elp != NULL);) { efree = elp; elp = elp->next; ast_free(efree); } return 0; }
static int extenspy_exec(struct ast_channel *chan, const char *data) { char *ptr, *exten = NULL; char *mygroup = NULL; char *recbase = NULL; int fd = 0; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '*', .volume = '#', .exit = '\0', }; struct ast_format oldwf; int volfactor = 0; int res; char *mailbox = NULL; char *name_context = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(context); AST_APP_ARG(options); ); char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); ast_format_clear(&oldwf); if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { exten = args.context; *ptr++ = '\0'; args.context = ptr; } if (ast_strlen_zero(args.context)) args.context = ast_strdupa(ast_channel_context(chan)); if (args.options) { char *opts[OPT_ARG_ARRAY_SIZE]; char tmp; ast_app_parse_options(spy_opts, &flags, opts, args.options); if (ast_test_flag(&flags, OPTION_GROUP)) mygroup = opts[OPT_ARG_GROUP]; if (ast_test_flag(&flags, OPTION_RECORD) && !(recbase = opts[OPT_ARG_RECORD])) recbase = "chanspy"; if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { tmp = opts[OPT_ARG_EXIT][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.exit = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { tmp = opts[OPT_ARG_CYCLE][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.cycle = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { int vol; if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); else volfactor = vol; } if (ast_test_flag(&flags, OPTION_PRIVATE)) ast_set_flag(&flags, OPTION_WHISPER); if (ast_test_flag(&flags, OPTION_NAME)) { if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { char *delimiter; if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { mailbox = opts[OPT_ARG_NAME]; *delimiter++ = '\0'; name_context = delimiter; } else { mailbox = opts[OPT_ARG_NAME]; } } } } else { /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); } ast_format_copy(&oldwf, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } if (recbase) { char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); fd = 0; } } res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); if (fd) close(fd); if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; }
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) { RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup); RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup); enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT; int fmts = 0; int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) && ast_format_cap_count(session->direct_media_cap); int dsp_features = 0; if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) || !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type); return -1; } /* get the endpoint capabilities */ if (direct_media_enabled) { ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps); format_cap_only_type(caps, media_type); } else { ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type); } /* get the capabilities on the peer */ get_codecs(session, stream, &codecs, session_media); ast_rtp_codecs_payload_formats(&codecs, peer, &fmts); /* get the joint capabilities between peer and endpoint */ ast_format_cap_get_compatible(caps, peer, joint); if (!ast_format_cap_count(joint)) { struct ast_str *usbuf = ast_str_alloca(256); struct ast_str *thembuf = ast_str_alloca(256); ast_rtp_codecs_payloads_destroy(&codecs); ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n", session_media->stream_type, ast_format_cap_get_names(caps, &usbuf), ast_format_cap_get_names(peer, &thembuf)); return -1; } ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp), session_media->rtp); ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN); if (session->channel) { ast_channel_lock(session->channel); ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN); ast_format_cap_remove_by_type(caps, media_type); ast_format_cap_append_from_cap(caps, joint, media_type); /* * Apply the new formats to the channel, potentially changing * raw read/write formats and translation path while doing so. */ ast_channel_nativeformats_set(session->channel, caps); if (media_type == AST_MEDIA_TYPE_AUDIO) { ast_set_read_format(session->channel, ast_channel_readformat(session->channel)); ast_set_write_format(session->channel, ast_channel_writeformat(session->channel)); } if ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO) && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833) && (session->dsp)) { dsp_features = ast_dsp_get_features(session->dsp); dsp_features &= ~DSP_FEATURE_DIGIT_DETECT; if (dsp_features) { ast_dsp_set_features(session->dsp, dsp_features); } else { ast_dsp_free(session->dsp); session->dsp = NULL; } } ast_channel_unlock(session->channel); } ast_rtp_codecs_payloads_destroy(&codecs); return 0; }
static int mp3_exec(struct ast_channel *chan, const char *data) { int res=0; int fds[2]; int ms = -1; int pid = -1; RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup); int timeout = 2000; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf = { .f = { 0, }, }; struct ast_format * native_format; unsigned int sampling_rate; struct ast_format * write_format; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } ast_stopstream(chan); native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0); sampling_rate = ast_format_get_sample_rate(native_format); write_format = ast_format_cache_get_slin_by_rate(sampling_rate); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = write_format; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; myf.f.data.ptr = myf.frdata; res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } /* Wait 1000 ms first */ next = ast_tvnow(); next.tv_sec += 1; if (res >= 0) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; if (ast_write(chan, &myf.f) < 0) { res = -1; break; } } else { ast_debug(1, "No more mp3\n"); res = 0; break; } next = ast_tvadd(next, ast_samp2tv(myf.f.samples, sampling_rate)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } if (ms) { f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); ast_frfree(f); res = 0; break; } ast_frfree(f); } } } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && owriteformat) ast_set_write_format(chan, owriteformat); ast_frfree(&myf.f); return res; }