mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	sample cache work
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@98 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
		
							parent
							
								
									527faf01d0
								
							
						
					
					
						commit
						bb0b105b83
					
				
					 17 changed files with 539 additions and 24 deletions
				
			
		
							
								
								
									
										14
									
								
								bootstrap.sh
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								bootstrap.sh
									
										
									
									
									
								
							| 
						 | 
					@ -17,9 +17,17 @@
 | 
				
			||||||
# along with polypaudio; if not, write to the Free Software Foundation,
 | 
					# along with polypaudio; if not, write to the Free Software Foundation,
 | 
				
			||||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 | 
					# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					run_versioned() {
 | 
				
			||||||
 | 
					    local P
 | 
				
			||||||
 | 
					    type -p "$1-$2" &> /dev/null && P="$1-$2" || local P="$1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shift 2
 | 
				
			||||||
 | 
					    "$P" "$@"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ "x$1" = "xam" ] ; then
 | 
					if [ "x$1" = "xam" ] ; then
 | 
				
			||||||
    set -ex
 | 
					    set -ex
 | 
				
			||||||
    automake -a -c --foreign
 | 
					    run_versioned automake 1.7 -a -c --foreign
 | 
				
			||||||
    ./config.status
 | 
					    ./config.status
 | 
				
			||||||
else 
 | 
					else 
 | 
				
			||||||
    set -ex
 | 
					    set -ex
 | 
				
			||||||
| 
						 | 
					@ -27,10 +35,10 @@ else
 | 
				
			||||||
    rm -rf autom4te.cache
 | 
					    rm -rf autom4te.cache
 | 
				
			||||||
    rm -f config.cache
 | 
					    rm -f config.cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    aclocal
 | 
					    run_versioned aclocal 1.7
 | 
				
			||||||
    libtoolize -c --force
 | 
					    libtoolize -c --force
 | 
				
			||||||
    autoheader
 | 
					    autoheader
 | 
				
			||||||
    automake -a -c
 | 
					    run_versioned automake 1.7 -a -c --foreign
 | 
				
			||||||
    autoconf -Wall
 | 
					    autoconf -Wall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@"
 | 
					    CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								doc/todo
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								doc/todo
									
										
									
									
									
								
							| 
						 | 
					@ -1,11 +1,18 @@
 | 
				
			||||||
*** $Id$ ***
 | 
					*** $Id$ ***
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*** 0.2 ***
 | 
					*** 0.2 ***
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- scache memory leak
 | 
				
			||||||
 | 
					- scache remove()
 | 
				
			||||||
 | 
					- scache in native protocol
 | 
				
			||||||
 | 
					- scache/debug.h copyright
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- future cancellation
 | 
					- future cancellation
 | 
				
			||||||
- clip cache
 | 
					 | 
				
			||||||
- autoloading/autounloading
 | 
					- autoloading/autounloading
 | 
				
			||||||
- doxygen
 | 
					- doxygen
 | 
				
			||||||
- make mcalign merge chunks
 | 
					- make mcalign merge chunks
 | 
				
			||||||
 | 
					- autoscan
 | 
				
			||||||
 | 
					- rename clitext.[ch] to cli-text.[ch]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*** 0.3 ***
 | 
					*** 0.3 ***
 | 
				
			||||||
- client-ui
 | 
					- client-ui
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,8 @@ polypaudio_SOURCES = idxset.c idxset.h \
 | 
				
			||||||
		cli-command.c cli-command.h \
 | 
							cli-command.c cli-command.h \
 | 
				
			||||||
		clitext.c clitext.h \
 | 
							clitext.c clitext.h \
 | 
				
			||||||
		tokenizer.c tokenizer.h \
 | 
							tokenizer.c tokenizer.h \
 | 
				
			||||||
		dynarray.c dynarray.h
 | 
							dynarray.c dynarray.h \
 | 
				
			||||||
 | 
							scache.c scache.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS)
 | 
					polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS)
 | 
				
			||||||
polypaudio_INCLUDES = $(INCLTDL)
 | 
					polypaudio_INCLUDES = $(INCLTDL)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,8 @@
 | 
				
			||||||
#include "strbuf.h"
 | 
					#include "strbuf.h"
 | 
				
			||||||
#include "namereg.h"
 | 
					#include "namereg.h"
 | 
				
			||||||
#include "clitext.h"
 | 
					#include "clitext.h"
 | 
				
			||||||
 | 
					#include "scache.h"
 | 
				
			||||||
 | 
					#include "sample-util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct command {
 | 
					struct command {
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
| 
						 | 
					@ -67,6 +69,9 @@ static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer
 | 
				
			||||||
static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
					static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
					static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
					static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct command commands[] = {
 | 
					static const struct command commands[] = {
 | 
				
			||||||
    { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
 | 
					    { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
 | 
				
			||||||
| 
						 | 
					@ -90,6 +95,9 @@ static const struct command commands[] = {
 | 
				
			||||||
    { "kill_client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
 | 
					    { "kill_client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
 | 
				
			||||||
    { "kill_sink_input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
 | 
					    { "kill_sink_input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
 | 
				
			||||||
    { "kill_source_output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
 | 
					    { "kill_source_output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
 | 
				
			||||||
 | 
					    { "scache_list",             pa_cli_command_scache_list,        "List all entries in the sample cache", 2},
 | 
				
			||||||
 | 
					    { "scache_play",             pa_cli_command_scache_play,        "Play a sample from the sample cache (args: name, sink|index)", 3},
 | 
				
			||||||
 | 
					    { "scache_remove",           pa_cli_command_scache_remove,      "Remove a sample from the sample cache (args: name)", 2},
 | 
				
			||||||
    { NULL, NULL, NULL, 0 }
 | 
					    { NULL, NULL, NULL, 0 }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,6 +207,7 @@ static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct
 | 
				
			||||||
    pa_cli_command_clients(c, t, buf, fail, verbose);
 | 
					    pa_cli_command_clients(c, t, buf, fail, verbose);
 | 
				
			||||||
    pa_cli_command_sink_inputs(c, t, buf, fail, verbose);
 | 
					    pa_cli_command_sink_inputs(c, t, buf, fail, verbose);
 | 
				
			||||||
    pa_cli_command_source_outputs(c, t, buf, fail, verbose);
 | 
					    pa_cli_command_source_outputs(c, t, buf, fail, verbose);
 | 
				
			||||||
 | 
					    pa_cli_command_scache_list(c, t, buf, fail, verbose);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -429,6 +438,56 @@ static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokeni
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_list(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
 | 
				
			||||||
 | 
					    char *s;
 | 
				
			||||||
 | 
					    assert(c && t);
 | 
				
			||||||
 | 
					    s = pa_scache_list_to_string(c);
 | 
				
			||||||
 | 
					    assert(s);
 | 
				
			||||||
 | 
					    pa_strbuf_puts(buf, s);
 | 
				
			||||||
 | 
					    free(s);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_play(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
 | 
				
			||||||
 | 
					    const char *n, *sink_name;
 | 
				
			||||||
 | 
					    struct pa_sink *sink;
 | 
				
			||||||
 | 
					    assert(c && t && buf && fail && verbose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
 | 
				
			||||||
 | 
					        pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
 | 
				
			||||||
 | 
					        pa_strbuf_puts(buf, "No sink by that name.\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) {
 | 
				
			||||||
 | 
					        pa_strbuf_puts(buf, "Failed to play sample.\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int pa_cli_command_scache_remove(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
 | 
				
			||||||
 | 
					    const char *n;
 | 
				
			||||||
 | 
					    assert(c && t && buf && fail && verbose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(n = pa_tokenizer_get(t, 1))) {
 | 
				
			||||||
 | 
					        pa_strbuf_puts(buf, "You need to specify a sample name.\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pa_scache_remove_item(c, n) < 0) {
 | 
				
			||||||
 | 
					        pa_strbuf_puts(buf, "Failed to remove sample.\n");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) {
 | 
					int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) {
 | 
				
			||||||
    const char *cs;
 | 
					    const char *cs;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "clitext.h"
 | 
					#include "clitext.h"
 | 
				
			||||||
#include "module.h"
 | 
					#include "module.h"
 | 
				
			||||||
| 
						 | 
					@ -34,6 +35,7 @@
 | 
				
			||||||
#include "source-output.h"
 | 
					#include "source-output.h"
 | 
				
			||||||
#include "strbuf.h"
 | 
					#include "strbuf.h"
 | 
				
			||||||
#include "sample-util.h"
 | 
					#include "sample-util.h"
 | 
				
			||||||
 | 
					#include "scache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *pa_module_list_to_string(struct pa_core *c) {
 | 
					char *pa_module_list_to_string(struct pa_core *c) {
 | 
				
			||||||
    struct pa_strbuf *s;
 | 
					    struct pa_strbuf *s;
 | 
				
			||||||
| 
						 | 
					@ -201,3 +203,36 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return pa_strbuf_tostring_free(s);
 | 
					    return pa_strbuf_tostring_free(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *pa_scache_list_to_string(struct pa_core *c) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    void *state = NULL;
 | 
				
			||||||
 | 
					    struct pa_strbuf *s;
 | 
				
			||||||
 | 
					    assert(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s = pa_strbuf_new();
 | 
				
			||||||
 | 
					    assert(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_strbuf_printf(s, "%u cache entries available.\n", c->scache_hashmap ? pa_hashmap_ncontents(c->scache_hashmap) : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->scache_hashmap) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while ((e = pa_hashmap_iterate(c->scache_hashmap, &state))) {
 | 
				
			||||||
 | 
					            double l;
 | 
				
			||||||
 | 
					            char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH];
 | 
				
			||||||
 | 
					            pa_sample_snprint(ss, sizeof(ss), &e->sample_spec);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            pa_strbuf_printf(
 | 
				
			||||||
 | 
					                s, "    name: <%s>\n\tindex: <%i>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n",
 | 
				
			||||||
 | 
					                e->name,
 | 
				
			||||||
 | 
					                e->index,
 | 
				
			||||||
 | 
					                ss,
 | 
				
			||||||
 | 
					                e->memchunk.length,
 | 
				
			||||||
 | 
					                l);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pa_strbuf_tostring_free(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ char *pa_sink_list_to_string(struct pa_core *core);
 | 
				
			||||||
char *pa_source_list_to_string(struct pa_core *c);
 | 
					char *pa_source_list_to_string(struct pa_core *c);
 | 
				
			||||||
char *pa_client_list_to_string(struct pa_core *c);
 | 
					char *pa_client_list_to_string(struct pa_core *c);
 | 
				
			||||||
char *pa_module_list_to_string(struct pa_core *c);
 | 
					char *pa_module_list_to_string(struct pa_core *c);
 | 
				
			||||||
 | 
					char *pa_scache_list_to_string(struct pa_core *c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@
 | 
				
			||||||
#include "source.h"
 | 
					#include "source.h"
 | 
				
			||||||
#include "namereg.h"
 | 
					#include "namereg.h"
 | 
				
			||||||
#include "util.h"
 | 
					#include "util.h"
 | 
				
			||||||
 | 
					#include "scache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
 | 
					struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
 | 
				
			||||||
    struct pa_core* c;
 | 
					    struct pa_core* c;
 | 
				
			||||||
| 
						 | 
					@ -50,6 +51,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    c->modules = NULL;
 | 
					    c->modules = NULL;
 | 
				
			||||||
    c->namereg = NULL;
 | 
					    c->namereg = NULL;
 | 
				
			||||||
 | 
					    c->scache_idxset = NULL;
 | 
				
			||||||
 | 
					    c->scache_hashmap = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    c->default_sample_spec.format = PA_SAMPLE_S16NE;
 | 
					    c->default_sample_spec.format = PA_SAMPLE_S16NE;
 | 
				
			||||||
    c->default_sample_spec.rate = 44100;
 | 
					    c->default_sample_spec.rate = 44100;
 | 
				
			||||||
| 
						 | 
					@ -82,6 +85,7 @@ void pa_core_free(struct pa_core *c) {
 | 
				
			||||||
    pa_idxset_free(c->sink_inputs, NULL, NULL);
 | 
					    pa_idxset_free(c->sink_inputs, NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_namereg_free(c);
 | 
					    pa_namereg_free(c);
 | 
				
			||||||
 | 
					    pa_scache_free(c);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    free(c);    
 | 
					    free(c);    
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,9 +30,9 @@
 | 
				
			||||||
struct pa_core {
 | 
					struct pa_core {
 | 
				
			||||||
    struct pa_mainloop_api *mainloop;
 | 
					    struct pa_mainloop_api *mainloop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules;
 | 
					    struct pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache_idxset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct pa_hashmap *namereg;
 | 
					    struct pa_hashmap *namereg, *scache_hashmap;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    uint32_t default_source_index, default_sink_index;
 | 
					    uint32_t default_source_index, default_sink_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								polyp/debug.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								polyp/debug.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					#ifndef foodebughfoo
 | 
				
			||||||
 | 
					#define foodebughfoo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A nice trick for debuggers, working on x86 only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG_TRAP __asm__("int $3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -168,3 +168,17 @@ int pa_hashmap_remove(struct pa_hashmap *h, const void *key) {
 | 
				
			||||||
unsigned pa_hashmap_ncontents(struct pa_hashmap *h) {
 | 
					unsigned pa_hashmap_ncontents(struct pa_hashmap *h) {
 | 
				
			||||||
    return h->n_entries;
 | 
					    return h->n_entries;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *pa_hashmap_iterate(struct pa_hashmap *h, void **state) {
 | 
				
			||||||
 | 
					    assert(h && state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!*state) {
 | 
				
			||||||
 | 
					        *state = h->first_entry;
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					        *state = ((struct hashmap_entry*) *state)->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!*state)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return ((struct hashmap_entry*) *state)->value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,4 +34,9 @@ int pa_hashmap_remove(struct pa_hashmap *h, const void *key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned pa_hashmap_ncontents(struct pa_hashmap *h);
 | 
					unsigned pa_hashmap_ncontents(struct pa_hashmap *h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Maybe used to iterate through the hashmap. Initial state should
 | 
				
			||||||
 | 
					   point to a NULL pointer. The hashmap may not be modified during
 | 
				
			||||||
 | 
					   iteration */
 | 
				
			||||||
 | 
					void *pa_hashmap_iterate(struct pa_hashmap *h, void **state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,7 +126,7 @@ int main(int argc, char *argv[]) {
 | 
				
			||||||
    r = lt_dlinit();
 | 
					    r = lt_dlinit();
 | 
				
			||||||
    assert(r == 0);
 | 
					    assert(r == 0);
 | 
				
			||||||
#ifdef DLSEARCHDIR
 | 
					#ifdef DLSEARCHDIR
 | 
				
			||||||
    lt_dladdsearchdir(DLSEARCHDIR);
 | 
					/*    lt_dladdsearchdir(DLSEARCHDIR);*/
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mainloop = pa_mainloop_new();
 | 
					    mainloop = pa_mainloop_new();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,8 @@
 | 
				
			||||||
#include "sink.h"
 | 
					#include "sink.h"
 | 
				
			||||||
#include "source.h"
 | 
					#include "source.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pa_modargs;
 | 
					struct pa_modargs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct entry {
 | 
					struct entry {
 | 
				
			||||||
| 
						 | 
					@ -213,6 +215,8 @@ int pa_modargs_get_sample_spec(struct pa_modargs *ma, struct pa_sample_spec *rss
 | 
				
			||||||
    struct pa_sample_spec ss;
 | 
					    struct pa_sample_spec ss;
 | 
				
			||||||
    assert(ma && rss);
 | 
					    assert(ma && rss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*    DEBUG_TRAP;*/
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    ss = *rss;
 | 
					    ss = *rss;
 | 
				
			||||||
    if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
 | 
					    if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,8 +39,10 @@
 | 
				
			||||||
#include "source-output.h"
 | 
					#include "source-output.h"
 | 
				
			||||||
#include "source.h"
 | 
					#include "source.h"
 | 
				
			||||||
#include "sample.h"
 | 
					#include "sample.h"
 | 
				
			||||||
 | 
					#include "scache.h"
 | 
				
			||||||
 | 
					#include "sample-util.h"
 | 
				
			||||||
#include "authkey.h"
 | 
					#include "authkey.h"
 | 
				
			||||||
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEFAULT_COOKIE_FILE ".esd_auth"
 | 
					#define DEFAULT_COOKIE_FILE ".esd_auth"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +51,10 @@
 | 
				
			||||||
#define RECORD_BUFFER_SECONDS (5)
 | 
					#define RECORD_BUFFER_SECONDS (5)
 | 
				
			||||||
#define RECORD_BUFFER_FRAGMENTS (100)
 | 
					#define RECORD_BUFFER_FRAGMENTS (100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_CACHE_SAMPLE_SIZE (1024000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SCACHE_PREFIX "esound~"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is heavily based on esound's code */
 | 
					/* This is heavily based on esound's code */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct connection {
 | 
					struct connection {
 | 
				
			||||||
| 
						 | 
					@ -71,6 +77,11 @@ struct connection {
 | 
				
			||||||
        struct pa_memblock *current_memblock;
 | 
					        struct pa_memblock *current_memblock;
 | 
				
			||||||
        size_t memblock_index, fragment_size;
 | 
					        size_t memblock_index, fragment_size;
 | 
				
			||||||
    } playback;
 | 
					    } playback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    struct pa_memchunk scache_memchunk;
 | 
				
			||||||
 | 
					    char *scache_name;
 | 
				
			||||||
 | 
					    struct pa_sample_spec scache_sample_spec;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pa_protocol_esound {
 | 
					struct pa_protocol_esound {
 | 
				
			||||||
| 
						 | 
					@ -105,6 +116,9 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons
 | 
				
			||||||
static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
					static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
					static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
					static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
 | 
					static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
 | 
					static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
 | 
					static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* the big map of protocol handler info */
 | 
					/* the big map of protocol handler info */
 | 
				
			||||||
static struct proto_handler proto_map[ESD_PROTO_MAX] = {
 | 
					static struct proto_handler proto_map[ESD_PROTO_MAX] = {
 | 
				
			||||||
| 
						 | 
					@ -116,9 +130,9 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = {
 | 
				
			||||||
    { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" },
 | 
					    { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" },
 | 
				
			||||||
    { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" },
 | 
					    { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    { ESD_NAME_MAX + 3 * sizeof(int), NULL, "sample cache" },
 | 
					    { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" },
 | 
				
			||||||
    { sizeof(int),                    NULL, "sample free" },
 | 
					    { sizeof(int),                    esd_proto_sample_free_or_play, "sample free" },
 | 
				
			||||||
    { sizeof(int),                    NULL, "sample play" },
 | 
					    { sizeof(int),                    esd_proto_sample_free_or_play, "sample play" },
 | 
				
			||||||
    { sizeof(int),                    NULL, "sample loop" },
 | 
					    { sizeof(int),                    NULL, "sample loop" },
 | 
				
			||||||
    { sizeof(int),                    NULL, "sample stop" },
 | 
					    { sizeof(int),                    NULL, "sample stop" },
 | 
				
			||||||
    { -1,                             NULL, "TODO: sample kill" },
 | 
					    { -1,                             NULL, "TODO: sample kill" },
 | 
				
			||||||
| 
						 | 
					@ -126,7 +140,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = {
 | 
				
			||||||
    { ESD_KEY_LEN + sizeof(int),      NULL, "standby" },
 | 
					    { ESD_KEY_LEN + sizeof(int),      NULL, "standby" },
 | 
				
			||||||
    { ESD_KEY_LEN + sizeof(int),      NULL, "resume" },
 | 
					    { ESD_KEY_LEN + sizeof(int),      NULL, "resume" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    { ESD_NAME_MAX,                   NULL, "sample getid" },
 | 
					    { ESD_NAME_MAX,                   esd_proto_sample_get_id, "sample getid" },
 | 
				
			||||||
    { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
 | 
					    { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    { sizeof(int),                    esd_proto_server_info, "server info" },
 | 
					    { sizeof(int),                    esd_proto_server_info, "server info" },
 | 
				
			||||||
| 
						 | 
					@ -171,6 +185,10 @@ static void connection_free(struct connection *c) {
 | 
				
			||||||
    if (c->fixed_source)
 | 
					    if (c->fixed_source)
 | 
				
			||||||
        c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source);
 | 
					        c->protocol->core->mainloop->cancel_fixed(c->protocol->core->mainloop, c->fixed_source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->scache_memchunk.memblock)
 | 
				
			||||||
 | 
					        pa_memblock_unref(c->scache_memchunk.memblock);
 | 
				
			||||||
 | 
					    free(c->scache_name);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    free(c);
 | 
					    free(c);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,6 +234,22 @@ static void* connection_write(struct connection *c, size_t length) {
 | 
				
			||||||
    return c->write_data+i;
 | 
					    return c->write_data+i;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void format_esd2native(int format, struct pa_sample_spec *ss) {
 | 
				
			||||||
 | 
					    assert(ss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
 | 
				
			||||||
 | 
					    ss->format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int format_native2esd(struct pa_sample_spec *ss) {
 | 
				
			||||||
 | 
					    int format = 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16;
 | 
				
			||||||
 | 
					    format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return format;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*** esound commands ***/
 | 
					/*** esound commands ***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) {
 | 
					static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length) {
 | 
				
			||||||
| 
						 | 
					@ -260,8 +294,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons
 | 
				
			||||||
    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 | 
					    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss.rate = rate;
 | 
					    ss.rate = rate;
 | 
				
			||||||
    ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
 | 
					    format_esd2native(format, &ss);
 | 
				
			||||||
    ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!pa_sample_spec_valid(&ss))
 | 
					    if (!pa_sample_spec_valid(&ss))
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
| 
						 | 
					@ -313,8 +346,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co
 | 
				
			||||||
    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 | 
					    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss.rate = rate;
 | 
					    ss.rate = rate;
 | 
				
			||||||
    ss.channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
 | 
					    format_esd2native(format, &ss);
 | 
				
			||||||
    ss.format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!pa_sample_spec_valid(&ss))
 | 
					    if (!pa_sample_spec_valid(&ss))
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
| 
						 | 
					@ -390,8 +422,7 @@ static int esd_proto_server_info(struct connection *c, esd_proto_t request, cons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((sink = get_output_sink(c->protocol))) {
 | 
					    if ((sink = get_output_sink(c->protocol))) {
 | 
				
			||||||
        rate = sink->sample_spec.rate;
 | 
					        rate = sink->sample_spec.rate;
 | 
				
			||||||
        format = (sink->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16;
 | 
					        format = format_native2esd(&sink->sample_spec);
 | 
				
			||||||
        format |= (sink->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    response = connection_write(c, sizeof(int)*3);
 | 
					    response = connection_write(c, sizeof(int)*3);
 | 
				
			||||||
| 
						 | 
					@ -428,8 +459,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
 | 
				
			||||||
        if (conn->sink_input) {
 | 
					        if (conn->sink_input) {
 | 
				
			||||||
            rate = conn->sink_input->sample_spec.rate;
 | 
					            rate = conn->sink_input->sample_spec.rate;
 | 
				
			||||||
            volume = (conn->sink_input->volume*0xFF)/0x100;
 | 
					            volume = (conn->sink_input->volume*0xFF)/0x100;
 | 
				
			||||||
            format = (conn->sink_input->sample_spec.format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16;
 | 
					            format = format_native2esd(&conn->sink_input->sample_spec);
 | 
				
			||||||
            format |= (conn->sink_input->sample_spec.channels >= 2) ? ESD_STEREO : ESD_MONO;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        /* id */
 | 
					        /* id */
 | 
				
			||||||
| 
						 | 
					@ -488,6 +518,103 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length) {
 | 
				
			||||||
 | 
					    struct pa_sample_spec ss;
 | 
				
			||||||
 | 
					    int format, rate;
 | 
				
			||||||
 | 
					    size_t sc_length;
 | 
				
			||||||
 | 
					    uint32_t index;
 | 
				
			||||||
 | 
					    int *ok;
 | 
				
			||||||
 | 
					    char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
 | 
				
			||||||
 | 
					    assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    format = maybe_swap_endian_32(c->swap_byte_order, *(int*)data);
 | 
				
			||||||
 | 
					    rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    ss.rate = rate;
 | 
				
			||||||
 | 
					    format_esd2native(format, &ss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sc_length >= MAX_CACHE_SAMPLE_SIZE)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(name, SCACHE_PREFIX);
 | 
				
			||||||
 | 
					    strncpy(name+sizeof(SCACHE_PREFIX)-1, data+3*sizeof(int), ESD_NAME_MAX);
 | 
				
			||||||
 | 
					    name[sizeof(name)-1] = 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    assert(!c->scache_memchunk.memblock);
 | 
				
			||||||
 | 
					    c->scache_memchunk.memblock = pa_memblock_new(sc_length);
 | 
				
			||||||
 | 
					    c->scache_memchunk.index = 0;
 | 
				
			||||||
 | 
					    c->scache_memchunk.length = sc_length;
 | 
				
			||||||
 | 
					    c->scache_sample_spec = ss;
 | 
				
			||||||
 | 
					    assert(!c->scache_name);
 | 
				
			||||||
 | 
					    c->scache_name = strdup(name);
 | 
				
			||||||
 | 
					    assert(c->scache_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c->state = ESD_CACHING_SAMPLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ok = connection_write(c, sizeof(int));
 | 
				
			||||||
 | 
					    assert(ok);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    *ok = index+1;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length) {
 | 
				
			||||||
 | 
					    int *ok;
 | 
				
			||||||
 | 
					    uint32_t index;
 | 
				
			||||||
 | 
					    char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
 | 
				
			||||||
 | 
					    assert(c && data && length == ESD_NAME_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ok = connection_write(c, sizeof(int));
 | 
				
			||||||
 | 
					    assert(ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *ok = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(name, SCACHE_PREFIX);
 | 
				
			||||||
 | 
					    strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX);
 | 
				
			||||||
 | 
					    name[sizeof(name)-1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((index = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID)
 | 
				
			||||||
 | 
					        *ok = (int) index +1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) {
 | 
				
			||||||
 | 
					    int *ok;
 | 
				
			||||||
 | 
					    const char *name;
 | 
				
			||||||
 | 
					    uint32_t index;
 | 
				
			||||||
 | 
					    assert(c && data && length == sizeof(int));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    index = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(int*)data)-1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ok = connection_write(c, sizeof(int));
 | 
				
			||||||
 | 
					    assert(ok);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *ok = 0;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if ((name = pa_scache_get_name_by_id(c->protocol->core, index))) {
 | 
				
			||||||
 | 
					        if (request == ESD_PROTO_SAMPLE_PLAY) {
 | 
				
			||||||
 | 
					            struct pa_sink *sink;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            if ((sink = get_output_sink(c->protocol)))
 | 
				
			||||||
 | 
					                if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0)
 | 
				
			||||||
 | 
					                    *ok = (int) index+1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            assert(request == ESD_PROTO_SAMPLE_FREE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (pa_scache_remove_item(c->protocol->core, name) >= 0)
 | 
				
			||||||
 | 
					                *ok = (int) index+1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*** client callbacks ***/
 | 
					/*** client callbacks ***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_kill_cb(struct pa_client *c) {
 | 
					static void client_kill_cb(struct pa_client *c) {
 | 
				
			||||||
| 
						 | 
					@ -566,6 +693,40 @@ static int do_read(struct connection *c) {
 | 
				
			||||||
            if (handler->proc(c, c->request, c->read_data, l) < 0)
 | 
					            if (handler->proc(c, c->request, c->read_data, l) < 0)
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (c->state == ESD_CACHING_SAMPLE) {
 | 
				
			||||||
 | 
					        ssize_t r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if ((r = pa_iochannel_read(c->io, c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) {
 | 
				
			||||||
 | 
					            fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno));
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        c->scache_memchunk.index += r;
 | 
				
			||||||
 | 
					        assert(c->scache_memchunk.index <= c->scache_memchunk.length);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (c->scache_memchunk.index == c->scache_memchunk.length) {
 | 
				
			||||||
 | 
					            uint32_t index;
 | 
				
			||||||
 | 
					            int *ok;
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            c->scache_memchunk.index = 0;
 | 
				
			||||||
 | 
					            pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_memblock_unref(c->scache_memchunk.memblock);
 | 
				
			||||||
 | 
					            c->scache_memchunk.memblock = NULL;
 | 
				
			||||||
 | 
					            c->scache_memchunk.index = c->scache_memchunk.length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            free(c->scache_name);
 | 
				
			||||||
 | 
					            c->scache_name = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            c->state = ESD_NEXT_REQUEST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ok = connection_write(c, sizeof(int));
 | 
				
			||||||
 | 
					            assert(ok);
 | 
				
			||||||
 | 
					            *ok = index+1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    } else if (c->state == ESD_STREAMING_DATA && c->sink_input) {
 | 
					    } else if (c->state == ESD_STREAMING_DATA && c->sink_input) {
 | 
				
			||||||
        struct pa_memchunk chunk;
 | 
					        struct pa_memchunk chunk;
 | 
				
			||||||
        ssize_t r;
 | 
					        ssize_t r;
 | 
				
			||||||
| 
						 | 
					@ -608,7 +769,6 @@ static int do_read(struct connection *c) {
 | 
				
			||||||
        pa_memblockq_push_align(c->input_memblockq, &chunk, 0);
 | 
					        pa_memblockq_push_align(c->input_memblockq, &chunk, 0);
 | 
				
			||||||
        assert(c->sink_input);
 | 
					        assert(c->sink_input);
 | 
				
			||||||
        pa_sink_notify(c->sink_input->sink);
 | 
					        pa_sink_notify(c->sink_input->sink);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
| 
						 | 
					@ -789,6 +949,10 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
 | 
				
			||||||
    c->playback.memblock_index = 0;
 | 
					    c->playback.memblock_index = 0;
 | 
				
			||||||
    c->playback.fragment_size = 0;
 | 
					    c->playback.fragment_size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c->scache_memchunk.length = c->scache_memchunk.index = 0;
 | 
				
			||||||
 | 
					    c->scache_memchunk.memblock = NULL;
 | 
				
			||||||
 | 
					    c->scache_name = NULL;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c);
 | 
					    c->fixed_source = c->protocol->core->mainloop->source_fixed(c->protocol->core->mainloop, fixed_callback, c);
 | 
				
			||||||
    assert(c->fixed_source);
 | 
					    assert(c->fixed_source);
 | 
				
			||||||
    c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0);
 | 
					    c->protocol->core->mainloop->enable_fixed(c->protocol->core->mainloop, c->fixed_source, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										181
									
								
								polyp/scache.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								polyp/scache.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,181 @@
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "scache.h"
 | 
				
			||||||
 | 
					#include "sink-input.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void free_entry(struct pa_scache_entry *e) {
 | 
				
			||||||
 | 
					    assert(e);
 | 
				
			||||||
 | 
					    free(e->name);
 | 
				
			||||||
 | 
					    if (e->memchunk.memblock)
 | 
				
			||||||
 | 
					        pa_memblock_unref(e->memchunk.memblock);
 | 
				
			||||||
 | 
					    free(e);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    int put;
 | 
				
			||||||
 | 
					    assert(c && name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->scache_hashmap && (e = pa_hashmap_get(c->scache_hashmap, name))) {
 | 
				
			||||||
 | 
					        put = 0;
 | 
				
			||||||
 | 
					        if (e->memchunk.memblock)
 | 
				
			||||||
 | 
					            pa_memblock_unref(e->memchunk.memblock);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        put = 1;
 | 
				
			||||||
 | 
					        e = malloc(sizeof(struct pa_scache_entry));
 | 
				
			||||||
 | 
					        assert(e);
 | 
				
			||||||
 | 
					        e->name = strdup(name);
 | 
				
			||||||
 | 
					        assert(e->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ss)
 | 
				
			||||||
 | 
					        e->sample_spec = *ss;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        memset(&e->sample_spec, 0, sizeof(struct pa_sample_spec));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (chunk) {
 | 
				
			||||||
 | 
					        e->memchunk = *chunk;
 | 
				
			||||||
 | 
					        pa_memblock_ref(e->memchunk.memblock);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        e->memchunk.memblock = NULL;
 | 
				
			||||||
 | 
					        e->memchunk.index = e->memchunk.length = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (put) {
 | 
				
			||||||
 | 
					        if (!c->scache_hashmap) {
 | 
				
			||||||
 | 
					            c->scache_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 | 
				
			||||||
 | 
					            assert(c->scache_hashmap);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (!c->scache_idxset) {
 | 
				
			||||||
 | 
					            c->scache_idxset = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 | 
				
			||||||
 | 
					            assert(c->scache_idxset);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        pa_idxset_put(c->scache_idxset, e, &e->index);
 | 
				
			||||||
 | 
					        pa_hashmap_put(c->scache_hashmap, e->name, e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    if (index)
 | 
				
			||||||
 | 
					        *index = e->index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_scache_remove_item(struct pa_core *c, const char *name) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    assert(c && name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_hashmap_remove(c->scache_hashmap, name);
 | 
				
			||||||
 | 
					    pa_idxset_remove_by_index(c->scache_idxset, e->index);
 | 
				
			||||||
 | 
					    free_entry(e);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void free_cb(void *p, void *userdata) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e = p;
 | 
				
			||||||
 | 
					    assert(e);
 | 
				
			||||||
 | 
					    free_entry(e);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa_scache_free(struct pa_core *c) {
 | 
				
			||||||
 | 
					    assert(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->scache_hashmap) {
 | 
				
			||||||
 | 
					        pa_hashmap_free(c->scache_hashmap, free_cb, NULL);
 | 
				
			||||||
 | 
					        c->scache_hashmap = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->scache_idxset) {
 | 
				
			||||||
 | 
					        pa_idxset_free(c->scache_idxset, NULL, NULL);
 | 
				
			||||||
 | 
					        c->scache_idxset = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sink_input_kill(struct pa_sink_input *i) {
 | 
				
			||||||
 | 
					    struct pa_memchunk *c;
 | 
				
			||||||
 | 
					    assert(i && i->userdata);
 | 
				
			||||||
 | 
					    c = i->userdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_memblock_unref(c->memblock);
 | 
				
			||||||
 | 
					    free(c);
 | 
				
			||||||
 | 
					    pa_sink_input_free(i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) {
 | 
				
			||||||
 | 
					    struct pa_memchunk *c;
 | 
				
			||||||
 | 
					    assert(i && chunk && i->userdata);
 | 
				
			||||||
 | 
					    c = i->userdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(c->length && c->memblock && c->memblock->length);
 | 
				
			||||||
 | 
					    *chunk = *c;
 | 
				
			||||||
 | 
					    pa_memblock_ref(c->memblock);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sink_input_drop(struct pa_sink_input *i, size_t length) {
 | 
				
			||||||
 | 
					    struct pa_memchunk *c;
 | 
				
			||||||
 | 
					    assert(i && length && i->userdata);
 | 
				
			||||||
 | 
					    c = i->userdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(length <= c->length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    c->length -= length;
 | 
				
			||||||
 | 
					    c->index += length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c->length <= 0)
 | 
				
			||||||
 | 
					        sink_input_kill(i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) {
 | 
				
			||||||
 | 
					    struct pa_sink_input *si;
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    struct pa_memchunk *chunk;
 | 
				
			||||||
 | 
					    assert(c && name && sink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!e->memchunk.memblock)
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (!(si = pa_sink_input_new(sink, name, &e->sample_spec)))
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    si->volume = volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    si->peek = sink_input_peek;
 | 
				
			||||||
 | 
					    si->drop = sink_input_drop;
 | 
				
			||||||
 | 
					    si->kill = sink_input_kill;
 | 
				
			||||||
 | 
					    si->userdata = chunk = malloc(sizeof(struct pa_memchunk));
 | 
				
			||||||
 | 
					    assert(chunk);
 | 
				
			||||||
 | 
					    *chunk = e->memchunk;
 | 
				
			||||||
 | 
					    pa_memblock_ref(chunk->memblock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char * pa_scache_get_name_by_id(struct pa_core *c, uint32_t id) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    assert(c && id != PA_IDXSET_INVALID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!c->scache_idxset || !(e = pa_idxset_get_by_index(c->scache_idxset, id)))
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return e->name;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name) {
 | 
				
			||||||
 | 
					    struct pa_scache_entry *e;
 | 
				
			||||||
 | 
					    assert(c && name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!c->scache_hashmap || !(e = pa_hashmap_get(c->scache_hashmap, name)))
 | 
				
			||||||
 | 
					        return PA_IDXSET_INVALID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return e->index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								polyp/scache.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								polyp/scache.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#ifndef fooscachehfoo
 | 
				
			||||||
 | 
					#define fooscachehfoo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "core.h"
 | 
				
			||||||
 | 
					#include "memchunk.h"
 | 
				
			||||||
 | 
					#include "sink.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pa_scache_entry {
 | 
				
			||||||
 | 
					    uint32_t index;
 | 
				
			||||||
 | 
					    char *name;
 | 
				
			||||||
 | 
					    struct pa_sample_spec sample_spec;
 | 
				
			||||||
 | 
					    struct pa_memchunk memchunk;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_spec *ss, struct pa_memchunk *chunk, uint32_t *index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa_scache_remove_item(struct pa_core *c, const char *name);
 | 
				
			||||||
 | 
					int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume);
 | 
				
			||||||
 | 
					void pa_scache_free(struct pa_core *c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *pa_scache_get_name_by_id(struct pa_core *c, uint32_t id);
 | 
				
			||||||
 | 
					uint32_t pa_scache_get_id_by_name(struct pa_core *c, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue