Squashed commit of the following:

commit d15fd4a547
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Tue Jul 6 14:07:42 2021 +0200

    Also free the character data.

commit 8869187215
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Mon Jul 5 16:11:32 2021 +0200

    Make documentation and parameters consistant.

commit 4b15aea2ee
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Thu Jun 10 15:34:00 2021 +0200

    Update documentation.

commit 6ec1b3035d
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Thu Jun 10 15:33:12 2021 +0200

    Do not use metadata for setting the recording file; use output_destination instead.

commit f65a76e8a3
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Wed Jun 9 15:56:02 2021 +0200

    Only append file extension if skip_filename_extension is not set.

commit 92e9d7c679
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Wed Jun 9 14:12:48 2021 +0200

    Rename the option to better match its usage.

commit 11128bff49
Author: Damir Nedžibović <damir.nedzibovic@enreach.com>
Date:   Wed Jun 9 13:19:10 2021 +0200

    Implement support for seting an output file and folder per recording.

Change-Id: I1579d62467eaf06a7aa1ac11e59dbb374f150deb
pull/1307/head
Damir Nedžibović 4 years ago committed by Richard Fuchs
parent 94a5feea7d
commit cc09099660

@ -1753,6 +1753,9 @@ call legs, therefore all keys other than `call-id` are currently ignored.
If the chosen recording method doesn't support in-kernel packet forwarding, enabling call recording If the chosen recording method doesn't support in-kernel packet forwarding, enabling call recording
via this messages will force packet forwarding to happen in userspace only. via this messages will force packet forwarding to happen in userspace only.
If the optional 'output-destination' key is set, then its value will be used
as an output file. Note that a filename extension will not be added.
`stop recording` Message `stop recording` Message
------------------------- -------------------------

@ -1445,7 +1445,7 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t
detect_setup_recording(call, &flags.record_call_str, &flags.metadata); detect_setup_recording(call, &flags.record_call_str, &flags.metadata);
if (flags.record_call) { if (flags.record_call) {
call->recording_on = 1; call->recording_on = 1;
recording_start(call, NULL, &flags.metadata); recording_start(call, NULL, &flags.metadata, NULL);
} }
if (flags.drop_traffic_start) { if (flags.drop_traffic_start) {
@ -1914,16 +1914,18 @@ const char *call_start_recording_ng(bencode_item_t *input, bencode_item_t *outpu
str callid; str callid;
struct call *call; struct call *call;
str metadata; str metadata;
str output_dest;
if (!bencode_dictionary_get_str(input, "call-id", &callid)) if (!bencode_dictionary_get_str(input, "call-id", &callid))
return "No call-id in message"; return "No call-id in message";
bencode_dictionary_get_str(input, "metadata", &metadata); bencode_dictionary_get_str(input, "metadata", &metadata);
bencode_dictionary_get_str(input, "output-destination", &output_dest);
call = call_get_opmode(&callid, OP_OTHER); call = call_get_opmode(&callid, OP_OTHER);
if (!call) if (!call)
return "Unknown call-id"; return "Unknown call-id";
call->recording_on = 1; call->recording_on = 1;
recording_start(call, NULL, &metadata); recording_start(call, NULL, &metadata, &output_dest);
rwlock_unlock_w(&call->master_lock); rwlock_unlock_w(&call->master_lock);
obj_put(call); obj_put(call);
@ -2034,7 +2036,7 @@ const char *call_start_forwarding_ng(bencode_item_t *input, bencode_item_t *outp
call->rec_forwarding = 1; call->rec_forwarding = 1;
} }
recording_start(call, NULL, &flags.metadata); recording_start(call, NULL, &flags.metadata, NULL);
errstr = NULL; errstr = NULL;
out: out:
if (call) { if (call) {

@ -244,6 +244,12 @@ static void update_metadata(struct call *call, str *metadata) {
} }
} }
static void update_output_dest(struct call *call, str *output_dest) {
if (!output_dest || !output_dest->s || !call->recording)
return;
recording_meta_chunk(call->recording, "OUTPUT_DESTINATION", output_dest);
}
// lock must be held // lock must be held
static void update_flags_proc(struct call *call) { static void update_flags_proc(struct call *call) {
append_meta_chunk_null(call->recording, "RECORDING %u", call->recording_on ? 1 : 0); append_meta_chunk_null(call->recording, "RECORDING %u", call->recording_on ? 1 : 0);
@ -259,9 +265,11 @@ static void recording_update_flags(struct call *call) {
} }
// lock must be held // lock must be held
void recording_start(struct call *call, const char *prefix, str *metadata) { void recording_start(struct call *call, const char *prefix, str *metadata, str *output_dest) {
update_metadata(call, metadata); update_metadata(call, metadata);
update_output_dest(call, output_dest);
if (call->recording) { if (call->recording) {
// already active // already active
recording_update_flags(call); recording_update_flags(call);
@ -350,7 +358,7 @@ void detect_setup_recording(struct call *call, const str *recordcall, str *metad
if (!str_cmp(recordcall, "yes") || !str_cmp(recordcall, "on")) { if (!str_cmp(recordcall, "yes") || !str_cmp(recordcall, "on")) {
call->recording_on = 1; call->recording_on = 1;
recording_start(call, NULL, NULL); recording_start(call, NULL, NULL, NULL);
} }
else if (!str_cmp(recordcall, "no") || !str_cmp(recordcall, "off")) { else if (!str_cmp(recordcall, "no") || !str_cmp(recordcall, "off")) {
call->recording_on = 0; call->recording_on = 0;

@ -1923,7 +1923,7 @@ static void json_restore_call(struct redis *r, const str *callid, int foreign) {
if (!redis_hash_get_str(&s, &call, "recording_meta_prefix")) { if (!redis_hash_get_str(&s, &call, "recording_meta_prefix")) {
// coverity[check_return : FALSE] // coverity[check_return : FALSE]
redis_hash_get_str(&meta, &call, "recording_metadata"); redis_hash_get_str(&meta, &call, "recording_metadata");
recording_start(c, s.s, &meta); recording_start(c, s.s, &meta, NULL);
} }
err = NULL; err = NULL;

@ -117,7 +117,7 @@ void recording_fs_free(void);
*/ */
void detect_setup_recording(struct call *call, const str *recordcall, str *metadata); void detect_setup_recording(struct call *call, const str *recordcall, str *metadata);
void recording_start(struct call *call, const char *prefix, str *metadata); void recording_start(struct call *call, const char *prefix, str *metadata, str *output_dest);
void recording_stop(struct call *call, str *metadata); void recording_stop(struct call *call, str *metadata);

@ -149,7 +149,6 @@ static void meta_ptime(metafile_t *mf, unsigned long mnum, int ptime)
mf->media_ptimes[mnum] = ptime; mf->media_ptimes[mnum] = ptime;
} }
// mf is locked // mf is locked
static void meta_metadata(metafile_t *mf, char *content) { static void meta_metadata(metafile_t *mf, char *content) {
mf->metadata = g_string_chunk_insert(mf->gsc, content); mf->metadata = g_string_chunk_insert(mf->gsc, content);
@ -192,6 +191,8 @@ static void meta_section(metafile_t *mf, char *section, char *content, unsigned
mf->forwarding_on = u ? 1 : 0; mf->forwarding_on = u ? 1 : 0;
else if (sscanf_match(section, "STREAM %lu FORWARDING %u", &lu, &u) == 2) else if (sscanf_match(section, "STREAM %lu FORWARDING %u", &lu, &u) == 2)
stream_forwarding_on(mf, lu, u); stream_forwarding_on(mf, lu, u);
else if (!strcmp(section, "OUTPUT_DESTINATION"))
mf->output_dest = g_string_chunk_insert(mf->gsc, content);
} }

@ -81,6 +81,19 @@ static void create_parent_dirs(char *dir) {
} }
} }
static output_t *output_alloc(const char *path, const char *name) {
output_t *ret = g_slice_alloc0(sizeof(*ret));
ret->file_path = g_strdup(path);
ret->file_name = g_strdup(name);
ret->full_filename = g_strdup_printf("%s/%s", path, name);
ret->file_format = output_file_format;
ret->encoder = encoder_new();
ret->channel_mult = 1;
ret->requested_format.format = -1;
ret->actual_format.format = -1;
return ret;
}
output_t *output_new(const char *path, const char *call, const char *type) { output_t *output_new(const char *path, const char *call, const char *type) {
// construct output file name // construct output file name
@ -159,23 +172,20 @@ output_t *output_new(const char *path, const char *call, const char *type) {
} }
done:; done:;
output_t *ret = g_slice_alloc0(sizeof(*ret)); output_t *ret = output_alloc(path, f->str);
ret->file_path = g_strdup(path);
ret->file_name = f->str; // stealing the content
ret->full_filename = g_strdup_printf("%s/%s", path, f->str);
ret->file_format = output_file_format;
ret->encoder = encoder_new();
ret->channel_mult = 1;
ret->requested_format.format = -1;
ret->actual_format.format = -1;
create_parent_dirs(ret->full_filename); create_parent_dirs(ret->full_filename);
g_string_free(f, FALSE); g_string_free(f, TRUE);
return ret; return ret;
} }
output_t *output_new_from_full_path(const char *path, char *name) {
output_t *ret = output_alloc(path, name);
create_parent_dirs(ret->full_filename);
return ret;
}
int output_config(output_t *output, const format_t *requested_format, format_t *actual_format) { int output_config(output_t *output, const format_t *requested_format, format_t *actual_format) {
const char *err; const char *err;
@ -238,9 +248,15 @@ int output_config(output_t *output, const format_t *requested_format, format_t *
char *full_fn = NULL; char *full_fn = NULL;
char suff[16] = ""; char suff[16] = "";
for (int i = 1; i < 20; i++) { for (int i = 1; i < 20; i++) {
if (!output->skip_filename_extension) {
full_fn = g_strdup_printf("%s%s.%s", output->full_filename, suff, output->file_format); full_fn = g_strdup_printf("%s%s.%s", output->full_filename, suff, output->file_format);
}
else {
full_fn = g_strdup_printf("%s%s", output->full_filename, suff);
}
if (!g_file_test(full_fn, G_FILE_TEST_EXISTS)) if (!g_file_test(full_fn, G_FILE_TEST_EXISTS))
goto got_fn; goto got_fn;
ilog(LOG_INFO, "Storing record in %s", full_fn);
snprintf(suff, sizeof(suff), "-%i", i); snprintf(suff, sizeof(suff), "-%i", i);
g_free(full_fn); g_free(full_fn);
} }

@ -11,6 +11,7 @@ extern int mp3_bitrate;
void output_init(const char *format); void output_init(const char *format);
output_t *output_new(const char *path, const char *call, const char *type); output_t *output_new(const char *path, const char *call, const char *type);
output_t *output_new_from_full_path(const char *path, char *name);
void output_close(output_t *); void output_close(output_t *);
int output_config(output_t *output, const format_t *requested_format, format_t *actual_format); int output_config(output_t *output, const format_t *requested_format, format_t *actual_format);

@ -152,7 +152,6 @@ void ssrc_free(void *p) {
g_slice_free1(sizeof(*s), s); g_slice_free1(sizeof(*s), s);
} }
// mf must be unlocked; returns ssrc locked // mf must be unlocked; returns ssrc locked
static ssrc_t *ssrc_get(stream_t *stream, unsigned long ssrc) { static ssrc_t *ssrc_get(stream_t *stream, unsigned long ssrc) {
metafile_t *mf = stream->metafile; metafile_t *mf = stream->metafile;
@ -177,9 +176,26 @@ out:
dbg("Init for SSRC %s%lx%s of stream #%lu", FMT_M(ret->ssrc), stream->id); dbg("Init for SSRC %s%lx%s of stream #%lu", FMT_M(ret->ssrc), stream->id);
if (mf->recording_on && !ret->output && output_single) { if (mf->recording_on && !ret->output && output_single) {
dbg("Metadata %s, output destination %s", mf->metadata, mf->output_dest);
if (mf->output_dest) {
char path[256];
strncpy(path, mf->output_dest, sizeof(path));
char *sep = strrchr(path, '/');
if (sep) {
char *filename = sep + 1;
*sep = 0;
ret->output = output_new_from_full_path(path, filename);
ret->output->skip_filename_extension = TRUE;
}
else {
ret->output = output_new_from_full_path(output_dir, path);
}
}
else {
char buf[16]; char buf[16];
snprintf(buf, sizeof(buf), "%08lx", ssrc); snprintf(buf, sizeof(buf), "%08lx", ssrc);
ret->output = output_new(output_dir, mf->parent, buf); ret->output = output_new(output_dir, mf->parent, buf);
}
db_do_stream(mf, ret->output, "single", stream, ssrc); db_do_stream(mf, ret->output, "single", stream, ssrc);
} }
if ((stream->forwarding_on || mf->forwarding_on) && !ret->tls_fwd_stream) { if ((stream->forwarding_on || mf->forwarding_on) && !ret->tls_fwd_stream) {

@ -111,6 +111,7 @@ struct metafile_s {
char *call_id; char *call_id;
char *metadata; char *metadata;
char *metadata_db; char *metadata_db;
char *output_dest;
off_t pos; off_t pos;
unsigned long long db_id; unsigned long long db_id;
@ -146,6 +147,7 @@ struct output_s {
*filename; // path + filename + suffix *filename; // path + filename + suffix
const char *file_format; const char *file_format;
unsigned long long db_id; unsigned long long db_id;
gboolean skip_filename_extension;
unsigned int channel_mult; unsigned int channel_mult;
AVFormatContext *fmtctx; AVFormatContext *fmtctx;

Loading…
Cancel
Save