From 16f075f95d55466856cf7f3fdea2c503b2fcd7cf Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sun, 8 Nov 2009 12:22:39 +0100 Subject: now it's possible to interrupt hanging file operations (e.g. slow http) --- deadbeef.h | 3 +++ main.c | 9 ++++++--- plugins.c | 1 + plugins/mpgmad/mpgmad.c | 3 ++- plugins/vfs_curl/vfs_curl.c | 24 ++++++++++++++++++++++++ plugins/vorbis/vorbis.c | 3 ++- session.c | 1 + streamer.c | 28 +++++++++++++++++++++++++++- vfs.c | 7 +++++++ vfs.h | 1 + 10 files changed, 74 insertions(+), 6 deletions(-) diff --git a/deadbeef.h b/deadbeef.h index 20fccd5d..b97de2e8 100644 --- a/deadbeef.h +++ b/deadbeef.h @@ -240,6 +240,7 @@ typedef struct { const char *(*fget_content_type) (DB_FILE *stream); const char *(*fget_content_name) (DB_FILE *stream); const char *(*fget_content_genre) (DB_FILE *stream); + void (*fstop) (DB_FILE *stream); // message passing int (*sendmessage) (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2); // configuration access @@ -293,6 +294,7 @@ typedef struct DB_plugin_s { } DB_plugin_t; typedef struct { + DB_FILE *file; int bps; int channels; int samplerate; @@ -396,6 +398,7 @@ typedef struct DB_vfs_s { int64_t (*tell) (DB_FILE *stream); void (*rewind) (DB_FILE *stream); int64_t (*getlength)(DB_FILE *stream); + void (*stop)(DB_FILE *stream); const char * (*get_content_type) (DB_FILE *stream); const char * (*get_content_name) (DB_FILE *stream); const char * (*get_content_genre) (DB_FILE *stream); diff --git a/main.c b/main.c index a97475a8..a09da293 100644 --- a/main.c +++ b/main.c @@ -733,18 +733,21 @@ main (int argc, char *argv[]) { gtk_widget_show (mainwin); gtk_main (); + // save config + pl_save (defpl); + conf_save (); + // stop receiving messages from outside + server_close (); + // at this point we can simply do exit(0), but let's clean up for debugging gtkpl_free (&main_playlist); gtkpl_free (&search_playlist); - server_close (); gdk_threads_leave (); messagepump_free (); p_free (); streamer_free (); codec_free_locking (); session_save (sessfile); - pl_save (defpl); pl_free (); - conf_save (); conf_free (); plug_unload_all (); return 0; diff --git a/plugins.c b/plugins.c index 3ed508e5..4fe09eaa 100644 --- a/plugins.c +++ b/plugins.c @@ -113,6 +113,7 @@ static DB_functions_t deadbeef_api = { .fget_content_type = vfs_get_content_type, .fget_content_name = vfs_get_content_name, .fget_content_genre = vfs_get_content_genre, + .fstop = vfs_fstop, // message passing .sendmessage = messagepump_push, // configuration access diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 8e54b6c8..763b7fb1 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -470,7 +470,7 @@ cmp3_scan_stream (buffer_t *buffer, int sample) { static int cmp3_init (DB_playItem_t *it) { memset (&buffer, 0, sizeof (buffer)); - buffer.file = deadbeef->fopen (it->fname); + buffer.file = plugin.info.file = deadbeef->fopen (it->fname); if (!buffer.file) { return -1; } @@ -783,6 +783,7 @@ cmp3_decode_float32 (void) { static void cmp3_free (void) { + plugin.info.file = NULL; if (buffer.file) { deadbeef->fclose (buffer.file); buffer.file = NULL; diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c index 3619ab6e..42211fe3 100644 --- a/plugins/vfs_curl/vfs_curl.c +++ b/plugins/vfs_curl/vfs_curl.c @@ -290,6 +290,7 @@ http_curl_write_abort (void *ptr, size_t size, size_t nmemb, void *stream) { static int http_curl_control (void *stream, double dltotal, double dlnow, double ultotal, double ulnow) { + trace ("http_curl_control\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; if (fp->status == STATUS_ABORTED) { @@ -342,6 +343,8 @@ http_thread_func (uintptr_t ctx) { curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, http_content_header_handler); curl_easy_setopt (curl, CURLOPT_HEADERDATA, ctx); curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, http_curl_control); + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, ctx); // enable up to 10 redirects curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 10); @@ -589,6 +592,9 @@ http_getlength (DB_FILE *stream) { trace ("http_getlength\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->status == STATUS_ABORTED) { + return -1; + } if (!fp->tid) { http_start_streamer (fp); } @@ -604,6 +610,9 @@ http_get_content_type (DB_FILE *stream) { trace ("http_get_content_type\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->status == STATUS_ABORTED) { + return NULL; + } if (fp->gotheader) { return fp->content_type; } @@ -622,6 +631,9 @@ http_get_content_name (DB_FILE *stream) { trace ("http_get_content_name\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->status == STATUS_ABORTED) { + return NULL; + } if (fp->gotheader) { return fp->content_name; } @@ -640,6 +652,9 @@ http_get_content_genre (DB_FILE *stream) { trace ("http_get_content_genre\n"); assert (stream); HTTP_FILE *fp = (HTTP_FILE *)stream; + if (fp->status == STATUS_ABORTED) { + return NULL; + } if (fp->gotheader) { return fp->content_genre; } @@ -653,6 +668,14 @@ http_get_content_genre (DB_FILE *stream) { return fp->content_genre; } +static void +http_stop (DB_FILE *stream) { + trace ("http_stop\n"); + assert (stream); + HTTP_FILE *fp = (HTTP_FILE *)stream; + fp->status = STATUS_ABORTED; +} + static const char *scheme_names[] = { "http://", "ftp://", NULL }; // standard stdio vfs @@ -676,6 +699,7 @@ static DB_vfs_t plugin = { .get_content_type = http_get_content_type, .get_content_name = http_get_content_name, .get_content_genre = http_get_content_type, + .stop = http_stop, .scheme_names = scheme_names, .streaming = 1 }; diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 8a32bd86..31e252eb 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -110,7 +110,7 @@ cvorbis_init (DB_playItem_t *it) { cur_bit_stream = -1; ptrack = it; - file = deadbeef->fopen (it->fname); + file = plugin.info.file = deadbeef->fopen (it->fname); if (!file) { return -1; } @@ -191,6 +191,7 @@ cvorbis_init (DB_playItem_t *it) { static void cvorbis_free (void) { + plugin.info.file = NULL; if (file) { ptrack = NULL; ov_clear (&vorbis_file); diff --git a/session.c b/session.c index a757c469..d99e3c4a 100644 --- a/session.c +++ b/session.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "session.h" #include "common.h" #include "deadbeef.h" diff --git a/streamer.c b/streamer.c index 2d7cd377..97d5154e 100644 --- a/streamer.c +++ b/streamer.c @@ -57,6 +57,7 @@ static float g_fbuffer[INPUT_BUFFER_SIZE]; #define SRC_BUFFER_SIZE (INPUT_BUFFER_SIZE*2) static float g_srcbuffer[SRC_BUFFER_SIZE]; static int streaming_terminate; +static playItem_t *streamer_initializing_item; // buffer up to 3 seconds at 44100Hz stereo #define STREAM_BUFFER_SIZE 0x80000 // slightly more than 3 seconds of 44100 stereo @@ -88,10 +89,14 @@ static playItem_t *orig_streaming_song; static int streamer_buffering; +// to allow interruption of stall file requests +static DB_FILE *streamer_file; + playItem_t * streamer_get_streaming_track (void) { return orig_streaming_song; } + // playlist must call that whenever item was removed void streamer_song_removed_notify (playItem_t *it) { @@ -133,7 +138,7 @@ streamer_set_current (playItem_t *it) { } if (!it->decoder && it->filetype && !strcmp (it->filetype, "content")) { // try to get content-type - DB_FILE *fp = vfs_fopen (it->fname); + DB_FILE *fp = streamer_file = vfs_fopen (it->fname); const char *ext = NULL; if (fp) { const char *ct = vfs_get_content_type (fp); @@ -146,6 +151,7 @@ streamer_set_current (playItem_t *it) { ext = "ogg"; } } + streamer_file = NULL; vfs_fclose (fp); } if (ext) { @@ -165,7 +171,13 @@ streamer_set_current (playItem_t *it) { } } if (it->decoder) { + streamer_lock (); + streamer_initializing_item = it; + streamer_unlock (); int ret = it->decoder->init (DB_PLAYITEM (it)); + streamer_lock (); + streamer_initializing_item = NULL; + streamer_unlock (); pl_item_copy (&str_streaming_song, it); if (ret < 0) { trace ("decoder->init returned %d\n", ret); @@ -218,6 +230,20 @@ streamer_set_nextsong (int song, int pstate) { // no sense to wait until end of previous song, reset buffer bytes_until_next_song = 0; playpos = 0; + // try to interrupt file operation + streamer_lock (); + if (streamer_file && streamer_file->vfs->streaming) { + trace ("interrupting streamer file access...\n"); + vfs_fstop (streamer_file); + } + else if (streamer_initializing_item) { + playItem_t *it = streamer_initializing_item; + if (it->decoder->info.file && it->decoder->info.file->vfs->streaming) { + trace ("interrupting plugin stream %p...\n", it->decoder->info.file); + vfs_fstop (it->decoder->info.file); + } + } + streamer_unlock (); } } diff --git a/vfs.c b/vfs.c index 2c038fac..23b1628d 100644 --- a/vfs.c +++ b/vfs.c @@ -99,3 +99,10 @@ vfs_get_content_genre (DB_FILE *stream) { } return NULL; } + +void +vfs_fstop (DB_FILE *stream) { + if (stream->vfs->stop) { + stream->vfs->stop (stream); + } +} diff --git a/vfs.h b/vfs.h index 599e63e4..65610cf2 100644 --- a/vfs.h +++ b/vfs.h @@ -32,5 +32,6 @@ int64_t vfs_fgetlength (DB_FILE *stream); const char *vfs_get_content_type (DB_FILE *stream); const char *vfs_get_content_name (DB_FILE *stream); const char *vfs_get_content_genre (DB_FILE *stream); +void vfs_fstop (DB_FILE *stream); #endif // __VFS_H -- cgit v1.2.3