revive howl support

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@566 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2006-02-22 20:11:56 +00:00
parent 361f16718f
commit 7f68c913f1
6 changed files with 126 additions and 106 deletions

View file

@ -29,7 +29,7 @@
#define HOWL_PROPERTY "howl" #define HOWL_PROPERTY "howl"
pa_howl_wrapper { struct pa_howl_wrapper {
pa_core *core; pa_core *core;
int ref; int ref;
@ -38,7 +38,7 @@ pa_howl_wrapper {
}; };
static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { static void howl_io_event(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
pa_howl_wrapper *w = userdata; pa_howl_wrapper *w = userdata;
assert(m && e && fd >= 0 && w && w->ref >= 1); assert(m && e && fd >= 0 && w && w->ref >= 1);

View file

@ -26,7 +26,7 @@
#include <polypcore/core.h> #include <polypcore/core.h>
pa_howl_wrapper; typedef struct pa_howl_wrapper pa_howl_wrapper;
pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c); pa_howl_wrapper* pa_howl_wrapper_get(pa_core *c);
pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h); pa_howl_wrapper* pa_howl_wrapper_ref(pa_howl_wrapper *h);

View file

@ -67,13 +67,13 @@ struct service {
struct { struct {
int valid; int valid;
pa_namereg_type type; pa_namereg_type_t type;
uint32_t index; uint32_t index;
} loaded; } loaded;
struct { struct {
int valid; int valid;
pa_namereg_type type; pa_namereg_type_t type;
uint32_t index; uint32_t index;
} autoload; } autoload;
}; };
@ -93,21 +93,19 @@ static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_stat
return SW_OKAY; return SW_OKAY;
} }
static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description) {
assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid); assert(u && s && s->loaded.valid && ret_ss && ret_description);
if (s->loaded.type == PA_NAMEREG_SINK) { if (s->loaded.type == PA_NAMEREG_SINK) {
pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index); pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index);
assert(sink); assert(sink);
*ret_ss = sink->sample_spec; *ret_ss = sink->sample_spec;
*ret_description = sink->description; *ret_description = sink->description;
*ret_typeid = sink->typeid;
} else if (s->loaded.type == PA_NAMEREG_SOURCE) { } else if (s->loaded.type == PA_NAMEREG_SOURCE) {
pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index); pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index);
assert(source); assert(source);
*ret_ss = source->sample_spec; *ret_ss = source->sample_spec;
*ret_description = source->description; *ret_description = source->description;
*ret_typeid = source->typeid;
} else } else
assert(0); assert(0);
} }
@ -154,10 +152,9 @@ static int publish_service(struct userdata *u, struct service *s) {
if (s->loaded.valid) { if (s->loaded.valid) {
char z[64], *description; char z[64], *description;
pa_typeid_t typeid;
pa_sample_spec ss; pa_sample_spec ss;
get_service_data(u, s, &ss, &description, &typeid); get_service_data(u, s, &ss, &description);
snprintf(z, sizeof(z), "%u", ss.rate); snprintf(z, sizeof(z), "%u", ss.rate);
sw_text_record_add_key_and_string_value(txt, "rate", z); sw_text_record_add_key_and_string_value(txt, "rate", z);
@ -167,10 +164,6 @@ static int publish_service(struct userdata *u, struct service *s) {
sw_text_record_add_key_and_string_value(txt, "description", description); sw_text_record_add_key_and_string_value(txt, "description", description);
snprintf(z, sizeof(z), "0x%8x", typeid);
sw_text_record_add_key_and_string_value(txt, "typeid", z);
if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t,
s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE,
NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt),
@ -210,7 +203,7 @@ finish:
return r; return r;
} }
struct service *get_service(struct userdata *u, const char *name) { static struct service *get_service(struct userdata *u, const char *name) {
struct service *s; struct service *s;
if ((s = pa_hashmap_get(u->services, name))) if ((s = pa_hashmap_get(u->services, name)))
@ -277,55 +270,55 @@ static int publish_autoload(struct userdata *u, pa_autoload_entry *s) {
return publish_service(u, svc); return publish_service(u, svc);
} }
static int remove_sink(struct userdata *u, uint32_t index) { static int remove_sink(struct userdata *u, uint32_t idx) {
struct service *svc; struct service *svc;
assert(u && index != PA_INVALID_INDEX); assert(u && idx != PA_INVALID_INDEX);
if (!(svc = pa_dynarray_get(u->sink_dynarray, index))) if (!(svc = pa_dynarray_get(u->sink_dynarray, idx)))
return 0; return 0;
if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK) if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK)
return 0; return 0;
svc->loaded.valid = 0; svc->loaded.valid = 0;
pa_dynarray_put(u->sink_dynarray, index, NULL); pa_dynarray_put(u->sink_dynarray, idx, NULL);
return publish_service(u, svc); return publish_service(u, svc);
} }
static int remove_source(struct userdata *u, uint32_t index) { static int remove_source(struct userdata *u, uint32_t idx) {
struct service *svc; struct service *svc;
assert(u && index != PA_INVALID_INDEX); assert(u && idx != PA_INVALID_INDEX);
if (!(svc = pa_dynarray_get(u->source_dynarray, index))) if (!(svc = pa_dynarray_get(u->source_dynarray, idx)))
return 0; return 0;
if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE) if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE)
return 0; return 0;
svc->loaded.valid = 0; svc->loaded.valid = 0;
pa_dynarray_put(u->source_dynarray, index, NULL); pa_dynarray_put(u->source_dynarray, idx, NULL);
return publish_service(u, svc); return publish_service(u, svc);
} }
static int remove_autoload(struct userdata *u, uint32_t index) { static int remove_autoload(struct userdata *u, uint32_t idx) {
struct service *svc; struct service *svc;
assert(u && index != PA_INVALID_INDEX); assert(u && idx != PA_INVALID_INDEX);
if (!(svc = pa_dynarray_get(u->autoload_dynarray, index))) if (!(svc = pa_dynarray_get(u->autoload_dynarray, idx)))
return 0; return 0;
if (!svc->autoload.valid) if (!svc->autoload.valid)
return 0; return 0;
svc->autoload.valid = 0; svc->autoload.valid = 0;
pa_dynarray_put(u->autoload_dynarray, index, NULL); pa_dynarray_put(u->autoload_dynarray, idx, NULL);
return publish_service(u, svc); return publish_service(u, svc);
} }
static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata) { static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
struct userdata *u = userdata; struct userdata *u = userdata;
assert(u && c); assert(u && c);
@ -334,12 +327,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
pa_sink *sink; pa_sink *sink;
if ((sink = pa_idxset_get_by_index(c->sinks, index))) { if ((sink = pa_idxset_get_by_index(c->sinks, idx))) {
if (publish_sink(u, sink) < 0) if (publish_sink(u, sink) < 0)
goto fail; goto fail;
} }
} else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
if (remove_sink(u, index) < 0) if (remove_sink(u, idx) < 0)
goto fail; goto fail;
} }
@ -350,12 +343,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
pa_source *source; pa_source *source;
if ((source = pa_idxset_get_by_index(c->sources, index))) { if ((source = pa_idxset_get_by_index(c->sources, idx))) {
if (publish_source(u, source) < 0) if (publish_source(u, source) < 0)
goto fail; goto fail;
} }
} else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
if (remove_source(u, index) < 0) if (remove_source(u, idx) < 0)
goto fail; goto fail;
} }
@ -365,12 +358,12 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type t, uint32_
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) { if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
pa_autoload_entry *autoload; pa_autoload_entry *autoload;
if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, index))) { if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, idx))) {
if (publish_autoload(u, autoload) < 0) if (publish_autoload(u, autoload) < 0)
goto fail; goto fail;
} }
} else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
if (remove_autoload(u, index) < 0) if (remove_autoload(u, idx) < 0)
goto fail; goto fail;
} }
@ -388,7 +381,7 @@ fail:
int pa__init(pa_core *c, pa_module*m) { int pa__init(pa_core *c, pa_module*m) {
struct userdata *u; struct userdata *u;
uint32_t index, port = PA_NATIVE_DEFAULT_PORT; uint32_t idx, port = PA_NATIVE_DEFAULT_PORT;
pa_sink *sink; pa_sink *sink;
pa_source *source; pa_source *source;
pa_autoload_entry *autoload; pa_autoload_entry *autoload;
@ -424,16 +417,16 @@ int pa__init(pa_core *c, pa_module*m) {
PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_SOURCE|
PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u); PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u);
for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx))
if (publish_sink(u, sink) < 0) if (publish_sink(u, sink) < 0)
goto fail; goto fail;
for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx))
if (publish_source(u, source) < 0) if (publish_source(u, source) < 0)
goto fail; goto fail;
if (c->autoload_idxset) if (c->autoload_idxset)
for (autoload = pa_idxset_first(c->autoload_idxset, &index); autoload; autoload = pa_idxset_next(c->autoload_idxset, &index)) for (autoload = pa_idxset_first(c->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(c->autoload_idxset, &idx))
if (publish_autoload(u, autoload) < 0) if (publish_autoload(u, autoload) < 0)
goto fail; goto fail;

View file

@ -32,19 +32,18 @@
#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp."
#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." #define SERVICE_NAME_SERVER "_polypaudio-server._tcp."
pa_browser { struct pa_browser {
int ref; int ref;
pa_mainloop_api *mainloop; pa_mainloop_api *mainloop;
void (*callback)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata); pa_browse_cb_t callback;
void *callback_userdata; void *userdata;
sw_discovery discovery; sw_discovery discovery;
pa_io_event *io_event; pa_io_event *io_event;
}; };
static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t events, void *userdata) {
static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags events, void *userdata) {
pa_browser *b = userdata; pa_browser *b = userdata;
assert(a && b && b->mainloop == a); assert(a && b && b->mainloop == a);
@ -56,26 +55,54 @@ static void io_callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_fl
} }
} }
static int type_equal(const char *a, const char *b) {
size_t la, lb;
if (strcasecmp(a, b) == 0)
return 1;
la = strlen(a);
lb = strlen(b);
if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0)
return 1;
if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0)
return 1;
return 0;
}
static int map_to_opcode(const char *type, int new) {
if (type_equal(type, SERVICE_NAME_SINK))
return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK;
else if (type_equal(type, SERVICE_NAME_SOURCE))
return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE;
else if (type_equal(type, SERVICE_NAME_SERVER))
return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER;
return -1;
}
static sw_result resolve_reply( static sw_result resolve_reply(
sw_discovery discovery, sw_discovery discovery,
sw_discovery_oid oid, sw_discovery_oid oid,
sw_uint32 interface_index, sw_uint32 interface_index,
sw_const_string name, sw_const_string name,
sw_const_string type, sw_const_string type,
sw_const_string domain, sw_const_string domain,
sw_ipv4_address address, sw_ipv4_address address,
sw_port port, sw_port port,
sw_octets text_record, sw_octets text_record,
sw_ulong text_record_len, sw_ulong text_record_len,
sw_opaque extra) { sw_opaque extra) {
pa_browser *b = extra; pa_browser *b = extra;
pa_browse_info i; pa_browse_info i;
char ip[256], a[256]; char ip[256], a[256];
pa_browse_opcode opcode; int opcode;
int device_found = 0; int device_found = 0;
uint32_t cookie; uint32_t cookie;
pa_typeid_t typeid;
pa_sample_spec ss; pa_sample_spec ss;
int ss_valid = 0; int ss_valid = 0;
sw_text_record_iterator iterator; sw_text_record_iterator iterator;
@ -91,17 +118,10 @@ static sw_result resolve_reply(
if (!b->callback) if (!b->callback)
goto fail; goto fail;
if (!strcmp(type, SERVICE_NAME_SINK))
opcode = PA_BROWSE_NEW_SINK;
else if (!strcmp(type, SERVICE_NAME_SOURCE))
opcode = PA_BROWSE_NEW_SOURCE;
else if (!strcmp(type, SERVICE_NAME_SERVER))
opcode = PA_BROWSE_NEW_SERVER;
else
goto fail;
opcode = map_to_opcode(type, 1);
assert(opcode >= 0);
snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port);
i.server = a; i.server = a;
@ -154,12 +174,6 @@ static sw_result resolve_reply(
pa_xfree((char*) i.description); pa_xfree((char*) i.description);
i.description = c; i.description = c;
c = NULL; c = NULL;
} else if (!strcmp(key, "typeid")) {
if (pa_atou(c, &typeid) < 0)
goto fail;
i.typeid = &typeid;
} else if (!strcmp(key, "channels")) { } else if (!strcmp(key, "channels")) {
uint32_t ch; uint32_t ch;
@ -195,7 +209,7 @@ static sw_result resolve_reply(
i.sample_spec = &ss; i.sample_spec = &ss;
b->callback(b, opcode, &i, b->callback_userdata); b->callback(b, opcode, &i, b->userdata);
fail: fail:
pa_xfree((void*) i.device); pa_xfree((void*) i.device);
@ -213,14 +227,14 @@ fail:
} }
static sw_result browse_reply( static sw_result browse_reply(
sw_discovery discovery, sw_discovery discovery,
sw_discovery_oid id, sw_discovery_oid id,
sw_discovery_browse_status status, sw_discovery_browse_status status,
sw_uint32 interface_index, sw_uint32 interface_index,
sw_const_string name, sw_const_string name,
sw_const_string type, sw_const_string type,
sw_const_string domain, sw_const_string domain,
sw_opaque extra) { sw_opaque extra) {
pa_browser *b = extra; pa_browser *b = extra;
assert(b); assert(b);
@ -238,9 +252,15 @@ static sw_result browse_reply(
case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: case SW_DISCOVERY_BROWSE_REMOVE_SERVICE:
if (b->callback) { if (b->callback) {
pa_browse_info i; pa_browse_info i;
int opcode;
memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof(i));
i.name = name; i.name = name;
b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata);
opcode = map_to_opcode(type, 0);
assert(opcode >= 0);
b->callback(b, opcode, &i, b->userdata);
} }
break; break;
@ -255,11 +275,11 @@ pa_browser *pa_browser_new(pa_mainloop_api *mainloop) {
pa_browser *b; pa_browser *b;
sw_discovery_oid oid; sw_discovery_oid oid;
b = pa_xmalloc(sizeof(pa_browser)); b = pa_xnew(pa_browser, 1);
b->mainloop = mainloop; b->mainloop = mainloop;
b->ref = 1; b->ref = 1;
b->callback = NULL; b->callback = NULL;
b->callback_userdata = NULL; b->userdata = NULL;
if (sw_discovery_init(&b->discovery) != SW_OKAY) { if (sw_discovery_init(&b->discovery) != SW_OKAY) {
pa_log("sw_discovery_init() failed.\n"); pa_log("sw_discovery_init() failed.\n");
@ -305,9 +325,9 @@ void pa_browser_unref(pa_browser *b) {
browser_free(b); browser_free(b);
} }
void pa_browser_set_callback(pa_browser *b, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void* userdata), void *userdata) { void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) {
assert(b); assert(b);
b->callback = cb; b->callback = cb;
b->callback_userdata = userdata; b->userdata = userdata;
} }

View file

@ -24,24 +24,27 @@
#include <polyp/mainloop-api.h> #include <polyp/mainloop-api.h>
#include <polyp/sample.h> #include <polyp/sample.h>
#include <polyp/channelmap.h>
#include <polyp/cdecl.h> #include <polyp/cdecl.h>
PA_C_DECL_BEGIN PA_C_DECL_BEGIN
pa_browser; typedef struct pa_browser pa_browser;
pa_browse_opcode { typedef enum pa_browse_opcode {
PA_BROWSE_NEW_SERVER, PA_BROWSE_NEW_SERVER = 0,
PA_BROWSE_NEW_SINK, PA_BROWSE_NEW_SINK,
PA_BROWSE_NEW_SOURCE, PA_BROWSE_NEW_SOURCE,
PA_BROWSE_REMOVE PA_BROWSE_REMOVE_SERVER,
}; PA_BROWSE_REMOVE_SINK,
PA_BROWSE_REMOVE_SOURCE
} pa_browse_opcode_t;
pa_browser *pa_browser_new(pa_mainloop_api *mainloop); pa_browser *pa_browser_new(pa_mainloop_api *mainloop);
pa_browser *pa_browser_ref(pa_browser *z); pa_browser *pa_browser_ref(pa_browser *z);
void pa_browser_unref(pa_browser *z); void pa_browser_unref(pa_browser *z);
pa_browse_info { typedef struct pa_browse_info {
/* Unique service name */ /* Unique service name */
const char *name; /* always available */ const char *name; /* always available */
@ -53,11 +56,12 @@ pa_browse_info {
/* Device info */ /* Device info */
const char *device; /* always available when this information is of a sink/source */ const char *device; /* always available when this information is of a sink/source */
const char *description; /* optional */ const char *description; /* optional */
const pa_typeid_t *typeid; /* optional */
const pa_sample_spec *sample_spec; /* optional */ const pa_sample_spec *sample_spec; /* optional */
}; } pa_browse_info;
void pa_browser_set_callback(pa_browser *z, void (*cb)(pa_browser *z, pa_browse_opcode c, const pa_browse_info *i, void *userdata), void *userdata); typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata);
void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata);
PA_C_DECL_END PA_C_DECL_END

View file

@ -55,26 +55,21 @@ static void dump_server(const pa_browse_info *i) {
} }
static void dump_device(const pa_browse_info *i) { static void dump_device(const pa_browse_info *i) {
char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
if (i->sample_spec) if (i->sample_spec)
pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec);
if (i->typeid)
pa_typeid_to_string(*i->typeid, t, sizeof(t));
printf("device: %s\n" printf("device: %s\n"
"description: %s\n" "description: %s\n"
"type: %s\n"
"sample spec: %s\n", "sample spec: %s\n",
i->device, i->device,
i->description ? i->description : "n/a", i->description ? i->description : "n/a",
i->typeid ? t : "n/a",
i->sample_spec ? ss : "n/a"); i->sample_spec ? ss : "n/a");
} }
static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_info *i, void *userdata) { static void browser_callback(pa_browser *b, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata) {
assert(b && i); assert(b && i);
switch (c) { switch (c) {
@ -96,10 +91,18 @@ static void browser_callback(pa_browser *b, pa_browse_opcode c, const pa_browse_
dump_device(i); dump_device(i);
break; break;
case PA_BROWSE_REMOVE: case PA_BROWSE_REMOVE_SERVER:
printf("\n=> removed service <%s>\n", i->name); printf("\n=> removed server <%s>\n", i->name);
break; break;
case PA_BROWSE_REMOVE_SINK:
printf("\n=> removed sink <%s>\n", i->name);
break;
case PA_BROWSE_REMOVE_SOURCE:
printf("\n=> removed source <%s>\n", i->name);
break;
default: default:
; ;
} }