diff --git a/src/format.h b/src/format.h index 1b518dce..49a2ff95 100644 --- a/src/format.h +++ b/src/format.h @@ -48,6 +48,7 @@ typedef struct _format_plugin_tag refbuf_t *(*get_buffer)(source_t *); int (*write_buf_to_client)(client_t *client); void (*write_buf_to_file)(source_t *source, refbuf_t *refbuf); + void (*on_file_close)(source_t *source); int (*create_client_data)(source_t *source, client_t *client); void (*set_tag)(struct _format_plugin_tag *plugin, const char *tag, const char *value, const char *charset); void (*free_plugin)(struct _format_plugin_tag *self); diff --git a/src/format_ebml.c b/src/format_ebml.c index b7954b87..b3318904 100644 --- a/src/format_ebml.c +++ b/src/format_ebml.c @@ -172,6 +172,7 @@ static void ebml_free_plugin(format_plugin_t *plugin); static refbuf_t *ebml_get_buffer(source_t *source); static int ebml_write_buf_to_client(client_t *client); static void ebml_write_buf_to_file(source_t *source, refbuf_t *refbuf); +static void ebml_on_file_close(source_t *source); static int ebml_create_client_data(source_t *source, client_t *client); static void ebml_free_client_data(client_t *client); @@ -206,6 +207,7 @@ int format_ebml_get_plugin(source_t *source) plugin->create_client_data = ebml_create_client_data; plugin->free_plugin = ebml_free_plugin; plugin->write_buf_to_file = ebml_write_buf_to_file; + plugin->on_file_close = ebml_on_file_close; plugin->set_tag = NULL; plugin->apply_settings = NULL; @@ -380,6 +382,12 @@ static void ebml_write_buf_to_file (source_t *source, refbuf_t *refbuf) source_write_dumpfile(source, refbuf->data, refbuf->len); } +static void ebml_on_file_close(source_t *source) +{ + ebml_source_state_t *ebml_source_state = source->format->_state; + ebml_source_state->file_headers_written = false; +} + /* internal ebml parsing */ static void ebml_destroy(ebml_t *ebml) diff --git a/src/format_ogg.c b/src/format_ogg.c index 315e9705..03d294da 100644 --- a/src/format_ogg.c +++ b/src/format_ogg.c @@ -62,6 +62,7 @@ static int create_ogg_client_data(source_t *source, client_t *client); static void free_ogg_client_data(client_t *client); static void write_ogg_to_file(source_t *source, refbuf_t *refbuf); +static void on_file_close(source_t *source); static refbuf_t *ogg_get_buffer(source_t *source); static int write_buf_to_client(client_t *client); @@ -170,6 +171,7 @@ int format_ogg_get_plugin(source_t *source) plugin->get_buffer = ogg_get_buffer; plugin->write_buf_to_client = write_buf_to_client; plugin->write_buf_to_file = write_ogg_to_file; + plugin->on_file_close = on_file_close; plugin->create_client_data = create_ogg_client_data; plugin->free_plugin = format_ogg_free_plugin; plugin->set_tag = NULL; @@ -584,3 +586,9 @@ static void write_ogg_to_file (source_t *source, refbuf_t *refbuf) } source_write_dumpfile(source, refbuf->data, refbuf->len); } + +static void on_file_close(source_t *source) +{ + ogg_state_t *ogg_info = source->format->_state; + ogg_info->file_headers = NULL; +} diff --git a/src/source.c b/src/source.c index e9206d76..c87c189b 100644 --- a/src/source.c +++ b/src/source.c @@ -615,14 +615,37 @@ static void send_to_listener (source_t *source, client_t *client, int deletion_e /* Open the file for stream dumping. * This function should do all processing of the filename. */ -static void source_open_dumpfile(source_t *source) { +static bool source_open_dumpfile(source_t *source) +{ const char *filename = source->dumpfilename; #ifndef _WIN32 /* some of the below functions seems not to be standard winapi functions */ time_t curtime = time(NULL); char buffer[PATH_MAX]; struct tm *loctime; +#endif + if (!filename) { + ICECAST_LOG_WARN("Can not open dump file for source %#H. No filename defined.", source->mount); + event_emit_clientevent("dumpfile-error", NULL, source->mount); + return false; + } + + if (source->dumpfile) { + ICECAST_LOG_WARN("Can not open dump file for source %#H. Dump already running.", source->mount); + event_emit_clientevent("dumpfile-error", NULL, source->mount); + return false; + } + + if (!source->format->write_buf_to_file) { + ICECAST_LOG_WARN("Can not open dump file for source %#H. format does not support dumping.", source->mount); + event_emit_clientevent("dumpfile-error", NULL, source->mount); + return false; + } + + ICECAST_LOG_DDEBUG("source=%p{.mount=%#H, .burst_point=%p, .stream_data=%p, .stream_data_tail=%p, ...}", source, source->mount, source->burst_point, source->stream_data, source->stream_data_tail); + +#ifndef _WIN32 /* Convert it to local time representation. */ loctime = localtime(&curtime); @@ -636,9 +659,13 @@ static void source_open_dumpfile(source_t *source) { source->dumpfile_start = curtime; stats_event(source->mount, "dumpfile_written", "0"); stats_event_time_iso8601(source->mount, "dumpfile_start"); + event_emit_clientevent("dumpfile-opened", NULL, source->mount); + return true; } else { - ICECAST_LOG_WARN("Cannot open dump file \"%s\" for appending: %s, disabling.", - source->dumpfilename, strerror(errno)); + ICECAST_LOG_WARN("Cannot open dump file for source %#H with filename %#H for appending: %s, disabling.", + source->mount, source->dumpfilename, strerror(errno)); + event_emit_clientevent("dumpfile-error", NULL, source->mount); + return false; } } @@ -1527,11 +1554,15 @@ void source_kill_dumpfile(source_t *source) if (!source->dumpfile) return; + if (source->format && source->format->on_file_close) + source->format->on_file_close(source); + fclose(source->dumpfile); source->dumpfile = NULL; source->dumpfile_written = 0; stats_event(source->mount, "dumpfile_written", NULL); stats_event(source->mount, "dumpfile_start", NULL); + event_emit_clientevent("dumpfile-closed", NULL, source->mount); } health_t source_get_health(source_t *source)