]> code.delx.au - pulseaudio/commitdiff
add sound file streaming
authorLennart Poettering <lennart@poettering.net>
Wed, 1 Sep 2004 15:55:48 +0000 (15:55 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 1 Sep 2004 15:55:48 +0000 (15:55 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@171 fefdeb5f-60dc-0310-8127-8f9354f1896f

doc/todo
polyp/Makefile.am
polyp/cli-command.c
polyp/play-memchunk.c
polyp/play-memchunk.h
polyp/sound-file-stream.c [new file with mode: 0644]
polyp/sound-file-stream.h [new file with mode: 0644]

index 6aacd3a5fdc928010c36508167877f97ed8645c4..8ad59f1b86f0aa66cc2875649327ecf8e4231e24 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -13,8 +13,7 @@
 - cleanup tagstruct and modargs (add s32, pa_volume_t, pa_usec_t)
 - remove all gcc warnings
 - esd compatible startup script or personality
-- add total sample size to stat
-- implement streamed file playbacj
+- add total sample cache size to stat
 
 ** later ***
 - xmlrpc/http
index 6fb7a583e816e7ff6450d4761d92d443be6b1cf5..cd369657aaedf2af33004058227fcacb82027dd6 100644 (file)
@@ -133,7 +133,8 @@ polypaudio_SOURCES = idxset.c idxset.h \
                autoload.c autoload.h \
                xmalloc.c xmalloc.h \
                subscribe.h subscribe.c \
-               debug.h
+               debug.h \
+               sound-file-stream.c sound-file-stream.h
 
 polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 polypaudio_INCLUDES = $(INCLTDL)
index 5a8ff1770af549f98adea7e2cdc1bfe3d219e152..1d2788fa535e8dd8e48d8ba13414f67e878aca93 100644 (file)
@@ -46,6 +46,7 @@
 #include "play-memchunk.h"
 #include "autoload.h"
 #include "xmalloc.h"
+#include "sound-file-stream.h"
 
 struct command {
     const char *name;
@@ -516,10 +517,7 @@ static int pa_cli_command_scache_load(struct pa_core *c, struct pa_tokenizer *t,
 
 static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
     const char *fname, *sink_name;
-    struct pa_memchunk chunk;
-    struct pa_sample_spec ss;
     struct pa_sink *sink;
-    int ret;
     assert(c && t && buf && fail && verbose);
 
     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
@@ -532,14 +530,8 @@ static int pa_cli_command_play_file(struct pa_core *c, struct pa_tokenizer *t, s
         return -1;
     }
 
-    if (pa_sound_file_load(fname, &ss, &chunk, c->memblock_stat) < 0) {
-        pa_strbuf_puts(buf, "Failed to load sound file.\n");
-        return -1;
-    }
 
-    ret = pa_play_memchunk(sink, fname, &ss, &chunk, PA_VOLUME_NORM);
-    pa_memblock_unref(chunk.memblock);
-    return ret;
+    return pa_play_file(sink, fname, PA_VOLUME_NORM);
 }
 
 static int pa_cli_command_autoload_add(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
index 486f0cf650cab6253e4ecb5cc7f9f588c0dcded6..e3f0c006e5a8ad82661e2f9d5ce0405012f12bc7 100644 (file)
@@ -76,7 +76,7 @@ static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*ch
         pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
 }
 
-int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume) {
+int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume) {
     struct pa_sink_input *si;
     struct pa_memchunk *nchunk;
 
index edd327c554767406daa743d55c9a208b34a86712..0e6a1d8e4a5ef6ea046d59c0d051d00c9f73e6b4 100644 (file)
@@ -25,6 +25,6 @@
 #include "sink.h"
 #include "memchunk.h"
 
-int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, uint32_t volume);
+int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sample_spec *ss, const struct pa_memchunk *chunk, pa_volume_t volume);
 
 #endif
diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c
new file mode 100644 (file)
index 0000000..a77b581
--- /dev/null
@@ -0,0 +1,162 @@
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+  polypaudio 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.
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sndfile.h>
+
+#include "sound-file-stream.h"
+#include "sink-input.h"
+#include "xmalloc.h"
+
+#define BUF_SIZE (1024*10)
+
+struct userdata {
+    SNDFILE *sndfile;
+    struct pa_sink_input *sink_input;
+    struct pa_memchunk memchunk;
+};
+
+static void free_userdata(struct userdata *u) {
+    assert(u);
+    if (u->sink_input)
+        pa_sink_input_free(u->sink_input);
+    if (u->memchunk.memblock)
+        pa_memblock_unref(u->memchunk.memblock);
+    if (u->sndfile)
+        sf_close(u->sndfile);
+
+    pa_xfree(u);
+}
+
+static void sink_input_kill(struct pa_sink_input *i) {
+    assert(i && i->userdata);
+    free_userdata(i->userdata);
+}
+
+static void si_kill(struct pa_mainloop_api *m, void *i) {
+    sink_input_kill(i);
+}
+
+static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) {
+    struct userdata *u;
+    assert(i && chunk && i->userdata);
+    u = i->userdata;
+
+    if (!u->memchunk.memblock) {
+        uint32_t fs = pa_frame_size(&i->sample_spec);
+        sf_count_t samples = BUF_SIZE/fs;
+
+        u->memchunk.memblock = pa_memblock_new(BUF_SIZE, i->sink->core->memblock_stat);
+        u->memchunk.index = 0;
+        samples = sf_readf_float(u->sndfile, u->memchunk.memblock->data, samples);
+        u->memchunk.length = samples*fs;
+        
+        if (!u->memchunk.length) {
+            pa_memblock_unref(u->memchunk.memblock);
+            u->memchunk.memblock = NULL;
+            u->memchunk.index = u->memchunk.length = 0;
+            pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
+            return -1;
+        }
+    }
+
+    *chunk = u->memchunk;
+    pa_memblock_ref(chunk->memblock);
+    assert(chunk->length);
+    return 0;
+}
+
+static void sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk*chunk, size_t length) {
+    struct userdata *u;
+    assert(i && chunk && length && i->userdata);
+    u = i->userdata;
+
+    assert(!memcmp(chunk, &u->memchunk, sizeof(chunk)));
+    assert(length <= u->memchunk.length);
+
+    u->memchunk.index += length;
+    u->memchunk.length -= length;
+
+    if (u->memchunk.length <= 0) {
+        pa_memblock_unref(u->memchunk.memblock);
+        u->memchunk.memblock = NULL;
+        u->memchunk.index = u->memchunk.length = 0;
+    }
+}
+
+int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) {
+    struct userdata *u = NULL;
+    SF_INFO sfinfo;
+    struct pa_sample_spec ss;
+    assert(sink && fname);
+
+    if (volume <= 0)
+        goto fail;
+
+    u = pa_xmalloc(sizeof(struct userdata));
+    u->sink_input = NULL;
+    u->memchunk.memblock = NULL;
+    u->memchunk.index = u->memchunk.length = 0;
+    u->sndfile = NULL;
+
+    memset(&sfinfo, 0, sizeof(sfinfo));
+
+    if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) {
+        fprintf(stderr, __FILE__": Failed to open file %s\n", fname);
+        goto fail;
+    }
+
+    ss.format = PA_SAMPLE_FLOAT32;
+    ss.rate = sfinfo.samplerate;
+    ss.channels = sfinfo.channels;
+
+    if (!pa_sample_spec_valid(&ss)) {
+        fprintf(stderr, __FILE__": Unsupported sample format in file %s\n", fname);
+        goto fail;
+    }
+    
+    if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss)))
+        goto fail;
+
+    u->sink_input->volume = volume;
+    u->sink_input->peek = sink_input_peek;
+    u->sink_input->drop = sink_input_drop;
+    u->sink_input->kill = sink_input_kill;
+    u->sink_input->userdata = u;
+    
+    pa_sink_notify(sink);
+
+    return 0;
+
+fail:
+    if (u)
+        free_userdata(u);
+    
+    return -1;
+}
diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h
new file mode 100644 (file)
index 0000000..9cf88cc
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef foosoundfilestreamhfoo
+#define foosoundfilestreamhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+  polypaudio 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.
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include "sink.h"
+
+int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume);
+
+#endif