summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-29 22:47:50 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-09-29 22:47:50 +0200
commitfc2689bbd0af9323a366d6fe6b37f613e28fc53f (patch)
tree32cef377a22338d1bde1e26d32e0313318651550
parent7ad596b7eb25cc2ab18b439d6159b0e12205c2f5 (diff)
vfs_curl WIP
-rw-r--r--Makefile.am3
-rw-r--r--callbacks.c5
-rw-r--r--configure.ac17
-rw-r--r--deadbeef.h1
-rw-r--r--gtkplaylist.c4
-rw-r--r--playlist.c4
-rw-r--r--plugins/lastfm/Makefile.am4
-rw-r--r--plugins/vfs_curl/Makefile.am7
-rw-r--r--plugins/vfs_curl/vfs_curl.c246
-rw-r--r--vfs.c5
-rw-r--r--vfs_stdio.c17
11 files changed, 297 insertions, 16 deletions
diff --git a/Makefile.am b/Makefile.am
index 1e0a07d2..2c23dcb8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,7 +14,8 @@ SUBDIRS = gme/Game_Music_Emu-0.5.2\
${VORBIS_DIR}\
${FLAC_DIR}\
${WAVPACK_DIR}\
- ${SNDFILE_DIR}
+ ${SNDFILE_DIR}\
+ ${VFS_CURL_DIR}
dumbpath=@top_srcdir@/dumb
sidpath=@top_srcdir@/sid/sidplay-libs-2.1.0
diff --git a/callbacks.c b/callbacks.c
index f03c36c4..082715cb 100644
--- a/callbacks.c
+++ b/callbacks.c
@@ -597,9 +597,10 @@ on_playlist_drag_data_received (GtkWidget *widget,
GTKPL_PROLOGUE;
gchar *ptr=(char*)data->data;
if (target_type == 0) { // uris
- if (!strncmp(ptr,"file:///",8)) {
+ fprintf (stderr, "calling gtkpl_handle_fm_drag_drop\n");
+// if (!strncmp(ptr,"file:///",8)) {
gtkpl_handle_fm_drag_drop (ps, y, ptr, data->length);
- }
+// }
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
diff --git a/configure.ac b/configure.ac
index 2f268ce4..062cdd28 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,12 +47,16 @@ if test ${HAVE_SSE2}; then
fi
AC_SUBST(SIMD_FLAGS)
-dnl lastfm plugin
+dnl curl lib
AC_CHECK_LIB([curl], [main], [HAVE_CURL=1])
if test ${HAVE_CURL}; then
- LFM_LIBS="-lcurl"
+ CURL_LIBS="-lcurl"
+ AC_SUBST(CURL_LIBS)
+fi
+
+dnl lastfm plugin
+if test ${HAVE_CURL}; then
LFM_DIR="plugins/lastfm"
- AC_SUBST(LFM_LIBS)
AC_SUBST(LFM_DIR)
fi
@@ -106,6 +110,12 @@ if test ${HAVE_SNDFILE} ; then
AC_SUBST(SNDFILE_DIR)
fi
+dnl lastfm plugin
+if test ${HAVE_CURL}; then
+ VFS_CURL_DIR="plugins/vfs_curl"
+ AC_SUBST(VFS_CURL_DIR)
+fi
+
AC_OUTPUT([
Makefile
pixmaps/Makefile
@@ -122,6 +132,7 @@ plugins/vorbis/Makefile
plugins/flac/Makefile
plugins/wavpack/Makefile
plugins/sndfile/Makefile
+plugins/vfs_curl/Makefile
deadbeef.desktop
])
diff --git a/deadbeef.h b/deadbeef.h
index 9c8fdb86..fc8a6b96 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -326,6 +326,7 @@ typedef struct DB_vfs_s {
long (*tell) (DB_FILE *stream);
void (*rewind) (DB_FILE *stream);
const char **scheme_names; // NULL-terminated list of supported schemes, e.g. {"http", "ftp", NULL}
+ unsigned streaming : 1;
} DB_vfs_t;
#ifdef __cplusplus
diff --git a/gtkplaylist.c b/gtkplaylist.c
index 7307462a..2c97a3f5 100644
--- a/gtkplaylist.c
+++ b/gtkplaylist.c
@@ -1088,9 +1088,9 @@ gtkpl_add_fm_dropped_files (gtkplaylist_t *ps, char *ptr, int length, int drop_y
//strncpy (fname, p, pe - p);
//fname[pe - p] = 0;
int abort = 0;
- playItem_t *inserted = pl_insert_dir (after, fname + 7, &abort, gtkpl_add_file_info_cb, NULL);
+ playItem_t *inserted = pl_insert_dir (after, fname, &abort, gtkpl_add_file_info_cb, NULL);
if (!inserted && !abort) {
- inserted = pl_insert_file (after, fname + 7, &abort, gtkpl_add_file_info_cb, NULL);
+ inserted = pl_insert_file (after, fname, &abort, gtkpl_add_file_info_cb, NULL);
}
if (inserted) {
after = inserted;
diff --git a/playlist.c b/playlist.c
index 2f3b54eb..5370f299 100644
--- a/playlist.c
+++ b/playlist.c
@@ -372,11 +372,15 @@ pl_insert_file (playItem_t *after, const char *fname, int *pabort, int (*cb)(pla
}
}
}
+ fprintf (stderr, "no decoder found for %s\n", fname);
return NULL;
}
playItem_t *
pl_insert_dir (playItem_t *after, const char *dirname, int *pabort, int (*cb)(playItem_t *it, void *data), void *user_data) {
+ if (!memcmp (dirname, "file://", 7)) {
+ dirname += 7;
+ }
struct stat buf;
lstat (dirname, &buf);
if (S_ISLNK(buf.st_mode)) {
diff --git a/plugins/lastfm/Makefile.am b/plugins/lastfm/Makefile.am
index c9e1e9b3..9aec3cf4 100644
--- a/plugins/lastfm/Makefile.am
+++ b/plugins/lastfm/Makefile.am
@@ -3,6 +3,6 @@ pkglib_LTLIBRARIES = lastfm.la
lastfm_la_SOURCES = lastfm.c
lastfm_la_LDFLAGS = -module
-lastfm_la_LIBADD = $(LDADD) $(LFM_LIBS)
-AM_CFLAGS = $(LASTFM_DEPS_CFLAGS) -std=c99
+lastfm_la_LIBADD = $(LDADD) $(CURL_LIBS)
+AM_CFLAGS = -std=c99
diff --git a/plugins/vfs_curl/Makefile.am b/plugins/vfs_curl/Makefile.am
new file mode 100644
index 00000000..189596a5
--- /dev/null
+++ b/plugins/vfs_curl/Makefile.am
@@ -0,0 +1,7 @@
+vfs_curldir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = vfs_curl.la
+vfs_curl_la_SOURCES = vfs_curl.c
+vfs_curl_la_LDFLAGS = -module
+
+vfs_curl_la_LIBADD = $(LDADD) $(CURL_LIBS)
+AM_CFLAGS = $(CFLAGS) -std=c99
diff --git a/plugins/vfs_curl/vfs_curl.c b/plugins/vfs_curl/vfs_curl.c
new file mode 100644
index 00000000..8ff59d98
--- /dev/null
+++ b/plugins/vfs_curl/vfs_curl.c
@@ -0,0 +1,246 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009 Alexey Yakovenko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <curl/curl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include "../../deadbeef.h"
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static DB_functions_t *deadbeef;
+
+#define BUFFER_SIZE (0x10000/2)
+#define BUFFER_MASK 0xffff
+
+#define STATUS_INITIAL 0
+#define STATUS_READING 1
+#define STATUS_FINISHED 2
+#define STATUS_ABORTED 3
+#define STATUS_REWIND 4
+
+typedef struct {
+ DB_vfs_t *vfs;
+ // buffer must be 2x size of BUFFER_SIZE, to be able to seek back a bit
+ uint8_t buffer[BUFFER_SIZE*2];
+ int pos; // position in stream; use "& BUFFER_MASK" to make it index into ringbuffer
+ int remaining; // remaining bytes in buffer read from stream
+ int status;
+ char *url;
+ intptr_t tid; // thread id which does http requests
+ intptr_t mutex;
+} HTTP_FILE;
+
+static DB_vfs_t plugin;
+
+static char http_err[CURL_ERROR_SIZE];
+
+static size_t
+lastfm_curl_write (void *ptr, size_t size, size_t nmemb, void *stream) {
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ int avail = size * nmemb;
+ for (;;) {
+ if (fp->status == STATUS_REWIND) {
+ return 0;
+ }
+ if (fp->status == STATUS_ABORTED) {
+ break;
+ }
+ deadbeef->mutex_lock (fp->mutex);
+ int sz = BUFFER_SIZE - fp->remaining;
+ int cp = min (avail, 10000);
+ if (sz >= cp) {
+ cp = min (avail, sz);
+ int writepos = (fp->pos + fp->remaining) & BUFFER_MASK;
+ // copy data
+ int part1 = BUFFER_SIZE * 2 - writepos;
+ part1 = min (part1, cp);
+ int part2 = sz - part1;
+ memcpy (fp->buffer+writepos, ptr, part1);
+ ptr += part1;
+ avail -= part1;
+ fp->remaining += part1;
+ if (part2 > 0) {
+ memcpy (fp->buffer, ptr, part2);
+ ptr += part2;
+ avail -= part2;
+ fp->remaining += part2;
+ }
+ }
+ deadbeef->mutex_unlock (fp->mutex);
+ if (avail >= size*nmemb) {
+ break;
+ }
+ usleep (3000);
+ }
+
+ return nmemb * size - avail;
+}
+
+static void
+http_thread_func (uintptr_t ctx) {
+ HTTP_FILE *fp = (HTTP_FILE *)ctx;
+ CURL *curl;
+ curl = curl_easy_init ();
+ for (;;) {
+ fp->pos = 0;
+ fp->remaining = 0;
+ curl_easy_setopt (curl, CURLOPT_URL, fp->url);
+ curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1);
+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, lastfm_curl_write);
+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, ctx);
+ curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, http_err);
+ curl_easy_setopt (curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE - fp->remaining);
+ curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ fp->status = STATUS_READING;
+ int status = curl_easy_perform (curl);
+ trace ("curl: curl_easy_perform status=%d\n", status);
+ if (fp->status != STATUS_REWIND) {
+ break;
+ }
+ }
+ curl_easy_cleanup (curl);
+ fp->status = STATUS_FINISHED;
+}
+
+static DB_FILE *
+http_open (const char *fname) {
+ HTTP_FILE *fp = malloc (sizeof (HTTP_FILE));
+ memset (fp, 0, sizeof (HTTP_FILE));
+ fp->vfs = &plugin;
+ fp->url = strdup (fname);
+ return (DB_FILE*)fp;
+}
+
+static void
+http_close (DB_FILE *stream) {
+ assert (stream);
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ if (fp->tid) {
+ fp->status = STATUS_ABORTED;
+ deadbeef->thread_join (fp->tid);
+ deadbeef->mutex_free (fp->mutex);
+ }
+ free (fp->url);
+ free (stream);
+}
+
+static size_t
+http_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
+ assert (stream);
+ assert (ptr);
+ assert (size * nmemb <= BUFFER_SIZE);
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ if (!fp->tid) {
+ fp->mutex = deadbeef->mutex_create ();
+ fp->tid = deadbeef->thread_start (http_thread_func, (uintptr_t)fp);
+ }
+ // wait until data is available
+ while (fp->remaining < size * nmemb && fp->status != STATUS_FINISHED) {
+ sleep (3000);
+ }
+ deadbeef->mutex_lock (fp->mutex);
+ int sz = size * nmemb;
+ int readpos = fp->pos & BUFFER_MASK;
+ int part1 = BUFFER_SIZE*2-(fp->pos&BUFFER_MASK);
+ part1 = min (part1, sz);
+ part1 = min (part1, fp->remaining);
+ memcpy (ptr, fp->buffer+readpos, part1);
+ fp->remaining -= part1;
+ fp->pos += part1;
+ sz -= part1;
+ if (fp->remaining > 0) {
+ int part2 = min (fp->remaining, sz);
+ memcpy (((char *)ptr) + part1, fp->buffer, part2);
+ fp->remaining -= part2;
+ fp->pos += part2;
+ sz -= part2;
+ }
+ deadbeef->mutex_unlock (fp->mutex);
+ return size * nmemb - sz;
+}
+
+static int
+http_seek (DB_FILE *stream, long offset, int whence) {
+ assert (stream);
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ if (!fp->tid) {
+ if (offset == 0 && (whence == SEEK_SET || whence == SEEK_CUR)) {
+ return 0;
+ }
+ else {
+ trace ("vfs_curl: cannot do seek(%d,%d)\n", offset, whence);
+ return -1;
+ }
+ }
+ // FIXME: can do some limited seeking
+ trace ("vfs_curl: seeking not implemented\n");
+ return -1;
+}
+
+static long
+http_tell (DB_FILE *stream) {
+ assert (stream);
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ return fp->pos;
+}
+
+static void
+http_rewind (DB_FILE *stream) {
+ assert (stream);
+ HTTP_FILE *fp = (HTTP_FILE *)stream;
+ if (fp->tid) {
+ deadbeef->mutex_lock (fp->mutex);
+ fp->status = STATUS_REWIND;
+ deadbeef->mutex_unlock (fp->mutex);
+ }
+}
+
+static const char *scheme_names[] = { "http://", NULL };
+
+// standard stdio vfs
+static DB_vfs_t plugin = {
+ DB_PLUGIN_SET_API_VERSION
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
+ .plugin.type = DB_PLUGIN_VFS,
+ .plugin.name = "CURL VFS (streaming over http)",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .open = http_open,
+ .close = http_close,
+ .read = http_read,
+ .seek = http_seek,
+ .tell = http_tell,
+ .rewind = http_rewind,
+ .scheme_names = scheme_names,
+ .streaming = 1
+};
+
+DB_plugin_t *
+vfs_curl_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/vfs.c b/vfs.c
index a4b456d2..7f4e8458 100644
--- a/vfs.c
+++ b/vfs.c
@@ -17,11 +17,16 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <string.h>
+#include <stdio.h>
#include "vfs.h"
#include "plugins.h"
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
DB_FILE *
vfs_fopen (const char *fname) {
+ trace ("vfs_open %s\n", fname);
DB_vfs_t **plugs = plug_get_vfs_list ();
DB_vfs_t *fallback = NULL;
int i;
diff --git a/vfs_stdio.c b/vfs_stdio.c
index bc0f1183..9d63c141 100644
--- a/vfs_stdio.c
+++ b/vfs_stdio.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
static DB_functions_t *deadbeef;
typedef struct {
@@ -29,8 +30,11 @@ typedef struct {
static DB_vfs_t plugin;
-DB_FILE *
+static DB_FILE *
stdio_open (const char *fname) {
+ if (!memcmp (fname, "file://", 7)) {
+ fname += 7;
+ }
FILE *file = fopen (fname, "rb");
if (!file) {
return NULL;
@@ -41,32 +45,33 @@ stdio_open (const char *fname) {
return (DB_FILE*)fp;
}
-void
+static void
stdio_close (DB_FILE *stream) {
assert (stream);
fclose (((STDIO_FILE *)stream)->stream);
free (stream);
}
-size_t stdio_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
+static size_t
+stdio_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
assert (stream);
assert (ptr);
return fread (ptr, size, nmemb, ((STDIO_FILE *)stream)->stream);
}
-int
+static int
stdio_seek (DB_FILE *stream, long offset, int whence) {
assert (stream);
return fseek (((STDIO_FILE *)stream)->stream, offset, whence);
}
-long
+static long
stdio_tell (DB_FILE *stream) {
assert (stream);
return ftell (((STDIO_FILE *)stream)->stream);
}
-void
+static void
stdio_rewind (DB_FILE *stream) {
assert (stream);
rewind (((STDIO_FILE *)stream)->stream);