static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, enum ast_media_type type, int one_to_one) { int i; int num; struct ast_stream_topology *topology; /* * Since this is an echo application if we get a frame in on a stream * we simply want to echo it back out onto the same stream number. */ num = ast_channel_is_multistream(chan) ? frame->stream_num : -1; if (ast_write_stream(chan, num, frame)) { return stream_echo_write_error(chan, frame, num); } /* * If the frame's type and given type don't match, or we are operating in * a one to one stream echo mode then there is nothing left to do. * * Note, if the channel is not multi-stream capable then one_to_one will * always be true, so it is safe to also not check for that here too. */ if (one_to_one || ast_format_get_type(frame->subclass.format) != type) { return 0; } /* * However, if we are operating in a single stream echoed to many stream * mode, and the frame's type matches the given type then we also need to * find the other streams of the same type and write out to those streams * as well. * * If we are here, then it's accepted that whatever stream number the frame * was read from for the given type is the only one set to send/receive, * while the others of the same type are set to receive only. Since we * shouldn't assume any order to the streams, we'll loop back through all * streams in the channel's topology writing only to those of the same type. * And, of course also not the stream which has already been written to. */ topology = ast_channel_get_stream_topology(chan); for (i = 0; i < ast_stream_topology_get_count(topology); ++i) { struct ast_stream *stream = ast_stream_topology_get_stream(topology, i); if (num != i && ast_stream_get_type(stream) == type) { if (ast_write_stream(chan, i, frame)) { return stream_echo_write_error(chan, frame, i); } } } return 0; }
void ast_ari_recordings_get_stored_file(struct ast_tcptls_session_instance *ser, struct ast_variable *headers, struct ast_ari_recordings_get_stored_file_args *args, struct ast_ari_response *response) { RAII_VAR(struct stasis_app_stored_recording *, recording, stasis_app_stored_recording_find_by_name(args->recording_name), ao2_cleanup); static const char *format_type_names[AST_MEDIA_TYPE_TEXT + 1] = { [AST_MEDIA_TYPE_UNKNOWN] = "binary", [AST_MEDIA_TYPE_AUDIO] = "audio", [AST_MEDIA_TYPE_VIDEO] = "video", [AST_MEDIA_TYPE_IMAGE] = "image", [AST_MEDIA_TYPE_TEXT] = "text", }; struct ast_format *format; response->message = ast_json_null(); if (!recording) { ast_ari_response_error(response, 404, "Not Found", "Recording not found"); return; } format = ast_get_format_for_file_ext(stasis_app_stored_recording_get_extension(recording)); if (!format) { ast_ari_response_error(response, 500, "Internal Server Error", "Format specified by recording not available or loaded"); return; } response->fd = open(stasis_app_stored_recording_get_filename(recording), O_RDONLY); if (response->fd < 0) { ast_ari_response_error(response, 403, "Forbidden", "Recording could not be opened"); return; } ast_str_append(&response->headers, 0, "Content-Type: %s/%s\r\n", format_type_names[ast_format_get_type(format)], stasis_app_stored_recording_get_extension(recording)); ast_ari_response_ok(response, ast_json_null()); }
static int stream_echo_write_error(struct ast_channel *chan, struct ast_frame *frame, int pos) { char frame_type[32]; const char *media_type; struct ast_stream *stream; ast_frame_type2str(frame->frametype, frame_type, sizeof(frame_type)); stream = pos < 0 ? ast_channel_get_default_stream(chan, ast_format_get_type(frame->subclass.format)) : ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), pos); media_type = ast_codec_media_type2str(ast_stream_get_type(stream)); ast_log(LOG_ERROR, "%s - unable to write frame type '%s' to stream type '%s' at " "position '%d'\n", ast_channel_name(chan), frame_type, media_type, ast_stream_get_position(stream)); return -1; }