pollfd.events = POLLIN;
pa_gettimeofday(u->timestamp);
-
+
for (;;) {
int code;
void *data, *object;
pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
}
-
+
} else if (object == u->sink) {
switch (code) {
pa_assert(running);
running = 0;
break;
-
+
case PA_SINK_MESSAGE_START:
pa_assert(!running);
running = 1;
-
+
pa_gettimeofday(u->timestamp);
break;
-
+
case PA_SINK_MESSAGE_GET_LATENCY:
-
+
if (pa_timeval_cmp(&u->timestamp, &now) > 0)
*((pa_usec_t*) data) = 0;
else
*((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
break;
-
+
/* ... */
default:
pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
}
}
-
+
pa_asyncmsgq_done(u->sink->asyncmsgq);
continue;
}
if (running) {
pa_gettimeofday(&now);
-
+
if (pa_timeval_cmp(u->timestamp, &now) <= 0) {
pa_memchunk chunk;
size_t l;
-
+
if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
l = chunk.length;
pa_memblock_unref(chunk.memblock);
} else
l = u->block_size;
-
+
pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink->sample_spec));
continue;
}
timeout = pa_timeval_diff(&u->timestamp, &now)/1000;
-
+
if (timeout < 1)
timeout = 1;
} else
timeout = -1;
/* Hmm, nothing to do. Let's sleep */
-
+
if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
continue;
pa_log("poll() failed: %s", pa_cstrerror(errno));
goto fail;
}
-
+
pa_assert(r == 0 || pollfd.revents == POLLIN);
}
pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
-
+
if (u->block_size <= 0)
u->block_size = pa_frame_size(&ss);
pa_log("Failed to create thread.");
goto fail;
}
-
+
pa_modargs_free(ma);
return 0;
void pa__done(pa_core *c, pa_module*m) {
struct userdata *u;
-
+
pa_assert(c);
pa_assert(m);
pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
pa_thread_free(u->thread);
}
-
+
pa_sink_unref(u->sink);
pa_xfree(u);
default:
pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
}
-
+
} else if (object == u->sink) {
-
+
case PA_SINK_MESSAGE_STOP:
pa_assert(running);
running = 0;
default:
pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
}
-
+
pa_asyncmsgq_done(u->sink->asyncmsgq);
continue;
}
if (!underrun) {
ssize_t l;
-
+
p = pa_memblock_acquire(u->memchunk.memblock);
l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length);
pa_memblock_release(p);
-
+
if (l < 0) {
if (errno != EINTR && errno != EAGAIN) {
pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
goto fail;
}
-
+
} else {
-
+
u->memchunk.index += l;
u->memchunk.length -= l;
pollfd[POLLFD_FIFO].events = running && !underrun ? POLLOUT : 0;
/* Hmm, nothing to do. Let's sleep */
-
+
if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
continue;
pa_log("FIFO shutdown.");
goto fail;
}
-
+
pa_assert(pollfd[POLLFD_ASYNCQ].revents & ~POLLIN == 0);
}
-
+
fail:
/* We have to continue processing messages until we receive the
* SHUTDOWN message */
u->memchunk.memblock = NULL;
u->memchunk.length = 0;
m->userdata = u;
-
+
mkfifo(u->filename, 0666);
-
+
if ((u->fd = open(u->filename, O_RDWR)) < 0) {
pa_log("open('%s'): %s", p, pa_cstrerror(errno));
goto fail;
pa_log("Failed to create sink.");
goto fail;
}
-
+
u->sink->userdata = u;
pa_sink_set_owner(u->sink, m);
pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p));
pa_log("Failed to create thread.");
goto fail;
}
-
+
pa_modargs_free(ma);
return 0;
pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
pa_thread_free(u->thread);
}
-
+
pa_sink_unref(u->sink);
if (u->memchunk.memblock)
pa_assert_se(a->asyncq = pa_asyncq_new(size));
pa_assert_se(a->mutex = pa_mutex_new(0));
a->current = NULL;
-
+
return a;
}
if (i->memchunk.memblock)
pa_memblock_unref(i->object);
-
+
if (i->userdata_free_cb)
i->userdata_free_cb(i->userdata);
-
+
if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
pa_xfree(i);
}
*object = a->current->object;
if (chunk)
*chunk = a->chunk;
-
+
return 0;
}
if (a->current->memchunk.memblock)
pa_memblock_unref(a->current->memchunk.memblock);
-
+
if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0)
pa_xfree(a->current);
}
int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
int c;
pa_assert(a);
-
+
do {
-
+
if (pa_asyncmsgq_get(a, NULL, &c, NULL, 1) < 0)
return -1;
pa_asyncmsgq_done(a);
-
+
} while (c != code);
return 0;
pa_xfree(l);
return NULL;
}
-
+
if (pipe(l->write_fds) < 0) {
pa_close(l->read_fds[0]);
pa_close(l->read_fds[1]);
if (free_cb) {
void *p;
-
+
while ((p = pa_asyncq_pop(l, 0)))
free_cb(p);
}
pa_close(l->read_fds[1]);
pa_close(l->write_fds[0]);
pa_close(l->write_fds[1]);
-
+
pa_xfree(l);
}
pa_assert(p);
cells = PA_ASYNCQ_CELLS(l);
-
+
_Y;
idx = reduce(l, l->write_idx);
if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
-
+
/* First try failed. Let's wait for changes. */
if (!wait)
for (;;) {
char x[20];
-
+
_Y;
if (pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p))
return -1;
}
}
-
+
_Y;
pa_atomic_dec(&l->write_waiting);
}
-
+
_Y;
l->write_idx++;
-
+
if (pa_atomic_load(&l->read_waiting)) {
char x = 'x';
_Y;
write(l->read_fds[1], &x, sizeof(x));
}
-
+
return 0;
}
if (!(ret = pa_atomic_ptr_load(&cells[idx]))) {
/* First try failed. Let's wait for changes. */
-
+
if (!wait)
return NULL;
_Y;
write(l->write_fds[1], &x, sizeof(x));
}
-
+
return ret;
}
return -1;
pa_atomic_inc(&l->read_waiting);
-
+
if (pa_atomic_ptr_load(&cells[idx])) {
pa_atomic_dec(&l->read_waiting);
return -1;
pa_core *c = PA_CORE(o);
pa_core_assert_ref(c);
-
+
switch (code) {
-
+
case PA_CORE_MESSAGE_UNLOAD_MODULE:
pa_module_unload(c, userdata);
return 0;
static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
pa_core *c = userdata;
-
+
pa_assert(pa_asyncmsgq_get_fd(c->asyncmsgq) == fd);
pa_assert(events == PA_IO_EVENT_INPUT);
pa_asyncmsgq_dispatch(object, code, data, &chunk);
pa_asyncmsgq_done(c->asyncmsgq, 0);
}
-
+
if (pa_asyncmsgq_before_poll(c->asyncmsgq) == 0)
break;
}
pa_mempool *pool;
pa_assert(m);
-
+
if (shared) {
if (!(pool = pa_mempool_new(shared))) {
pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
pa_assert_se(c->asyncmsgq = pa_asyncmsgq_new(0));
pa_assert_se(pa_asyncmsgq_before_poll(c->asyncmsgq) == 0);
pa_assert_se(c->asyncmsgq_event = c->mainloop->io_new(c->mainloop, pa_asyncmsgq_get_fd(c->asyncmsgq), PA_IO_EVENT_INPUT, asyncmsgq_cb, c));
-
+
return c;
}
struct pa_core {
pa_msgobject parent;
-
+
/* A random value which may be used to identify this instance of
* PulseAudio. Not cryptographically secure in any way. */
uint32_t cookie;
assert(p);
cells = PA_FLIST_CELLS(l);
-
+
n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN;
_Y;
idx = reduce(l, pa_atomic_load(&l->write_idx));
pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name) {
pa_msgobject *o;
-
+
pa_assert(size > sizeof(pa_msgobject));
pa_assert(type_name);
pa_object *pa_object_new_internal(size_t size, const char *type_name) {
pa_object *o;
-
+
pa_assert(size > sizeof(pa_object));
pa_assert(type_name);
pa_object_assert_ref(PA_OBJECT(o)); \
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
-
+
#endif
/* Not reentrant -- how could it be? */
void pa_once(pa_once_t *control, pa_once_func_t func) {
pa_mutex *m;
-
+
pa_assert(control);
pa_assert(func);
if (pa_atomic_load(&control->done))
return;
-
+
pa_atomic_inc(&control->ref);
-
+
for (;;) {
-
+
if ((m = pa_atomic_ptr_load(&control->mutex))) {
/* The mutex is stored in locked state, hence let's just
pa_assert_se(m = pa_mutex_new(0));
pa_mutex_lock(m);
-
+
if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) {
func();
pa_atomic_store(&control->done, 1);
}
pa_assert(pa_atomic_load(&control->done));
-
+
if (pa_atomic_dec(&control->ref) <= 1) {
pa_assert(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
pa_mutex_free(m);
};
enum {
- MESSAGE_REQUEST_DATA, /* data from source output to main loop */
+ MESSAGE_REQUEST_DATA, /* data from source output to main loop */
MESSAGE_POST_DATA /* data from source output to main loop */
};
-
+
#define PLAYBACK_BUFFER_SECONDS (.5)
#define PLAYBACK_BUFFER_FRAGMENTS (10)
#define RECORD_BUFFER_SECONDS (5)
pa_sink_input_disconnect(c->sink_input);
pa_sink_input_unref(c->sink_input);
}
-
+
if (c->source_output) {
pa_source_output_disconnect(c->source_output);
pa_source_output_unref(c->source_output);
}
-
+
if (c->playback.current_memblock)
pa_memblock_unref(c->playback.current_memblock);
-
+
if (c->client)
pa_client_free(c->client);
if (c->io)
pa_memblockq_free(c->input_memblockq);
if (c->output_memblockq)
pa_memblockq_free(c->output_memblockq);
-
+
pa_xfree(c);
}
void *p;
pa_assert(c);
-
+
if (!c->sink_input || !(l = pa_atomic_load(&c->playback.missing)))
return 0;
p = pa_memblock_acquire(c->playback.current_memblock);
r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l);
pa_memblock_release(c->playback.current_memblock);
-
+
if (r <= 0) {
if (errno == EINTR || errno == EAGAIN)
return 0;
-
+
pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
return -1;
}
p = pa_memblock_acquire(chunk.memblock);
r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
pa_memblock_release(chunk.memblock);
-
+
pa_memblock_unref(chunk.memblock);
if (r < 0) {
}
pa_memblockq_drop(c->output_memblockq, &chunk, r);
-
+
return 0;
}
/* Called from thread context */
static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, const pa_memchunk *chunk) {
struct connection*c;
-
+
pa_assert(i);
c = i->userdata;
pa_assert(c);
pa_memblockq_push_align(c->input_memblockq, chunk);
return 0;
}
-
+
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
pa_usec_t *r = userdata;
-
+
*r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
/* Fall through, the default handler will add in the extra
/* Called from thread context */
static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
struct connection*c;
-
+
pa_assert(i);
c = i->userdata;
pa_assert(c);
static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
struct connection*c = i->userdata;
size_t old, new;
-
+
pa_assert(i);
pa_assert(c);
pa_assert(length);
static void sink_input_kill_cb(pa_sink_input *i) {
pa_assert(i);
pa_assert(i->userdata);
-
+
connection_free((struct connection *) i->userdata);
}
static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
struct connection *c;
-
+
pa_assert(o);
c = o->userdata;
pa_assert(c);
pa_assert(o);
c = o->userdata;
pa_assert(c);
-
+
connection_free(c);
}
static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
struct connection*c;
-
+
pa_assert(o);
c = o->userdata;
pa_assert(c);
-
+
return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
}
static void client_kill_cb(pa_client *client) {
struct connection*c;
-
+
pa_assert(client);
c = client->userdata;
pa_assert(c);
pa_protocol_simple *p = userdata;
struct connection *c = NULL;
char cname[256];
-
+
pa_assert(s);
pa_assert(io);
pa_assert(p);
c->client->kill = client_kill_cb;
c->client->userdata = c;
-
+
if (p->mode & PLAYBACK) {
pa_sink_input_new_data data;
size_t l;
pa_iochannel_set_callback(c->io, io_callback, c);
pa_idxset_put(p->connections, c, NULL);
-
+
return;
fail:
static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
pa_protocol_simple *p = userdata;
int do_some_work = 0;
-
+
pa_assert(pa_asyncmsgq_get_fd(p->asyncmsgq) == fd);
pa_assert(events == PA_IO_EVENT_INPUT);
connection *c = object;
pa_assert(c);
-
+
switch (code) {
case MESSAGE_REQUEST_DATA:
pa_asyncmsgq_done(p->asyncmsgq);
}
-
+
if (pa_asyncmsgq_before_poll(p->asyncmsgq) == 0)
break;
}
pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
pa_protocol_simple* p = NULL;
int enable;
-
+
pa_assert(core);
pa_assert(server);
pa_assert(ma);
pa_assert_se(pa_asyncmsgq_before_poll(p->asyncmsgq) == 0);
pa_assert_se(p->asyncmsgq_event = core->mainloop->io_event_new(core->mainloop, pa_asyncmsgq_get_fd(p->asyncmsgq), PA_IO_EVENT_INPUT, p));
-
+
return p;
fail:
if (p)
pa_protocol_simple_free(p);
-
+
return NULL;
}
pa_asyncmsgq_after_poll(c->asyncmsgq);
pa_asyncmsgq_free(p->asyncmsgq);
}
-
+
pa_xfree(p);
}
void pa_semaphore_wait(pa_semaphore *s) {
int ret;
pa_assert(s);
-
+
do {
ret = sem_wait(&s->sem);
} while (ret < 0 && errno == EINTR);
memset(data, 0, sizeof(*data));
data->resample_method = PA_RESAMPLER_INVALID;
-
+
return data;
}
if (!data->channel_map_is_set) {
if (data->sink->channel_map.channels == data->sample_spec.channels)
data->channel_map = data->sink->channel_map;
- else
+ else
pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
}
if (!data->muted_is_set)
data->muted = 0;
-
+
if (data->resample_method == PA_RESAMPLER_INVALID)
data->resample_method = core->resample_method;
i->parent.parent.free = sink_input_free;
i->parent.process_msg = pa_sink_input_process_msg;
-
+
i->core = core;
pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
i->flags = flags;
i->module = data->module;
i->sink = data->sink;
i->client = data->client;
-
+
i->resample_method = data->resample_method;
i->sample_spec = data->sample_spec;
i->channel_map = data->channel_map;
i->volume = data->volume;
i->muted = data->muted;
-
+
i->process_msg = NULL;
i->peek = NULL;
i->drop = NULL;
pa_return_if_fail(pa_sink_input_get_state(i) != PA_SINK_INPUT_DISCONNECTED);
pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
-
+
pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
pa_assert(i);
pa_assert(pa_sink_input_refcnt(i) == 0);
-
+
pa_sink_input_disconnect(i);
pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
r = 0;
-
+
if (i->get_latency)
r += i->get_latency(i);
int do_volume_adj_here;
int volume_is_norm;
pa_sink_input_state_t state;
-
+
pa_sink_input_assert_ref(i);
pa_assert(chunk);
pa_assert(volume);
i->sample_spec.rate = rate;
pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
-
+
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return 0
}
pa_sink_assert_ref(dest);
return -1;
-
+
/* origin = i->sink; */
/* if (dest == origin) */
int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
pa_sink_input *i = PA_SINK_INPUT(o);
-
+
pa_sink_input_assert_ref(i);
switch (code) {
case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
s->thread_info.soft_volume = *((pa_cvolume*) userdata);
return 0;
-
+
case PA_SINK_INPUT_MESSAGE_SET_MUTE:
s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
return 0;
-
+
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
pa_usec_t *r = userdata;
-
+
if (i->thread_info.resampled_chunk.memblock)
*r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
/* if (i->move_silence) */
/* r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); */
-
+
return 0;
}
-
+
case PA_SINK_INPUT_MESSAGE_SET_RATE: {
-
+
i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userdata));
struct pa_sink_input {
pa_msgobject parent;
-
+
uint32_t index;
pa_core *core;
pa_atomic_t state;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
-
+
pa_cvolume volume;
int muted;
- int (*process_msg)(pa_sink_input *i, int code, void *userdata);
+ int (*process_msg)(pa_sink_input *i, int code, void *userdata);
int (*peek) (pa_sink_input *i, pa_memchunk *chunk);
void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length);
void (*kill) (pa_sink_input *i); /* may be NULL */
struct {
pa_sample_spec sample_spec;
-
+
pa_memchunk resampled_chunk;
pa_resampler *resampler; /* may be NULL */
-
+
/* Some silence to play before the actual data. This is used to
* compensate for latency differences when moving a sink input
* "hot" between sinks. */
pa_cvolume volume;
int muted;
} thread_info;
-
+
void *userdata;
};
s->parent.parent.free = sink_free;
s->parent.process_msg = pa_sink_process_msg;
-
+
s->core = core;
pa_atomic_store(&s->state, PA_SINK_IDLE);
s->name = pa_xstrdup(name);
s->userdata = NULL;
pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
-
+
r = pa_idxset_put(core->sinks, s, &s->index);
pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
s->thread_info.soft_volume = s->volume;
s->thread_info.soft_muted = s->muted;
-
+
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
return s;
static void sink_stop(pa_sink *s) {
pa_sink_state_t state;
int stop;
-
+
pa_assert(s);
state = pa_sink_get_state(s);
pa_return_if_fail(state == PA_SINK_RUNNING || state == PA_SINK_SUSPENDED);
static void sink_free(pa_object *o) {
pa_sink *s = PA_SINK(o);
-
+
pa_assert(s);
pa_assert(pa_sink_refcnt(s) == 0);
}
pa_idxset_free(s->inputs, NULL, NULL);
-
+
pa_hashmap_free(s->thread_info.inputs, (pa_free2_cb_t) pa_sink_input_unref, NULL);
pa_asyncmsgq_free(s->asyncmsgq);
-
+
pa_xfree(s->name);
pa_xfree(s->description);
pa_xfree(s->driver);
if (pa_sink_get_state(s) == PA_SINK_SUSPENDED)
return;
-
+
if (pa_sink_used_by(s) > 0)
sink_start(s);
else
s->stop(s);
else
pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
-
+
} else {
pa_atomic_store(&s->state, PA_SINK_RUNNING);
else {
void *src, *ptr;
pa_cvolume volume;
-
+
ptr = pa_memblock_acquire(target->memblock);
src = pa_memblock_acquire(info[0].chunk.memblock);
-
+
memcpy((uint8_t*) ptr + target->index,
(uint8_t*) src + info[0].chunk.index,
target->length);
-
+
pa_memblock_release(target->memblock);
pa_memblock_release(info[0].chunk.memblock);
-
+
pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
if (!pa_cvolume_is_norm(&volume))
pa_volume_memchunk(target, &s->sample_spec, &volume);
}
-
+
} else {
void *ptr;
ptr = pa_memblock_acquire(target->memblock);
-
+
target->length = pa_mix(info, n,
(uint8_t*) ptr + target->index,
target->length,
&s->sample_spec,
&s->thread_info.soft_volume,
s->thread_info.soft_muted);
-
+
pa_memblock_release(target->memblock);
}
-
+
inputs_drop(s, info, n, target->length);
if (s->monitor_source)
pa_usec_t pa_sink_get_latency(pa_sink *s) {
pa_usec_t usec = 0;
-
+
pa_sink_assert_ref(s);
if (s->get_latency)
return s->get_latency(s);
-
+
if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
return 0;
changed = !pa_cvolume_equal(volume, &s->volume);
s->volume = *volume;
-
+
if (s->set_volume && s->set_volume(s) < 0)
s->set_volume = NULL;
pa_sink_assert_ref(s);
old_volume = s->volume;
-
+
if (s->get_volume && s->get_volume(s) < 0)
s->get_volume = NULL;
if (!pa_cvolume_equal(&old_volume, &s->volume))
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
+
return &s->volume;
}
void pa_sink_set_mute(pa_sink *s, int mute) {
int changed;
-
+
pa_sink_assert_ref(s);
changed = s->muted != mute;
int pa_sink_get_mute(pa_sink *s) {
int old_muted;
-
+
pa_sink_assert_ref(s);
old_muted = s->muted;
-
+
if (s->get_mute && s->get_mute(s) < 0)
s->get_mute = NULL;
if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
+
return s->muted;
}
pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
return 0;
}
-
+
case PA_SINK_MESSAGE_REMOVE_INPUT: {
pa_sink_input *i = userdata;
pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
return 0;
}
-
+
case PA_SINK_MESSAGE_SET_VOLUME:
s->thread_info.soft_volume = *((pa_cvolume*) userdata);
return 0;
-
+
case PA_SINK_MESSAGE_SET_MUTE:
s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
return 0;
-
+
case PA_SINK_MESSAGE_GET_VOLUME:
*((pa_cvolume*) userdata) = s->thread_info.soft_volume;
return 0;
-
+
case PA_SINK_MESSAGE_GET_MUTE:
*((int*) userdata) = s->thread_info.soft_muted;
return 0;
-
+
default:
return -1;
}
if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
!pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
-
+
if (!(resampler = pa_resampler_new(
core->mempool,
&data->source->sample_spec, &data->source->channel_map,
}
o = pa_source_output_new(pa_source_output);
-
+
o->parent.parent.free = source_output_free;
o->parent.process_msg = pa_source_output_process_msg;
-
+
o->core = core;
pa_atomic_load(&o->state, PA_SOURCE_OUTPUT_RUNNING);
o->flags = flags;
pa_assert(o->source->core);
pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, NULL);
-
+
pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
pa_idxset_remove_by_data(o->source->outputs, o, NULL);
static void source_output_free(pa_msgobject* mo) {
pa_source_output *o = PA_SOURCE_OUTPUT(mo);
-
+
pa_assert(pa_source_output_refcnt(o) == 0);
pa_source_output_disconnect(o);
void pa_source_output_put(pa_source_output *o) {
pa_source_output_assert_ref(o);
-
+
pa_asyncmsgq_post(o->source->asyncmsgq, o->source, PA_SOURCE_MESSAGE_ADD_OUTPUT, o, NULL, pa_source_unref, pa_source_output_unref);
pa_source_update_status(o->source);
if (pa_asyncmsgq_send(o->source->asyncmsgq, i->source, PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
r = 0;
-
+
if (o->get_latency)
r += o->get_latency(o);
pa_assert(chunk->length);
state = pa_source_output_get_state(o);
-
+
if (!o->push || state == PA_SOURCE_OUTPUT_DISCONNECTED || state == PA_SOURCE_OUTPUT_CORKED)
return;
pa_assert(state = PA_SOURCE_OUTPUT_RUNNING);
-
+
if (!o->resampler) {
o->push(o, chunk);
return;
i->sample_spec.rate = rate;
pa_asyncmsgq_post(s->asyncmsgq, pa_source_output_ref(i), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_source_output_unref, NULL);
-
+
pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT!|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return 0;
}
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
pa_source_output_assert_ref(o);
- return o->resample_method;
+ return o->resample_method;
}
int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
pa_source_assert_ref(dest);
return -1;
-
+
/* origin = o->source; */
/* if (dest == origin) */
int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, pa_memchunk* chunk) {
pa_source_output *o = PA_SOURCE_OUTPUT(o);
-
+
pa_source_output_assert_ref(i);
switch (code) {
case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
-
+
i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
pa_resampler_set_output_rate(i->resampler, PA_PTR_TO_UINT(userdata));
struct pa_source_output {
pa_msgobject parent;
-
+
uint32_t index;
pa_core *core;
pa_atomic_t state;
struct {
pa_sample_spec sample_spec;
-
+
pa_resampler* resampler; /* may be NULL */
} thread_info;
-
+
void *userdata;
};
s->parent.parent.free = source_free;
s->parent.process_msg = pa_source_process_msg;
-
+
s->core = core;
pa_atomic_store(&s->state, PA_SOURCE_IDLE);
s->name = pa_xstrdup(name);
s->userdata = NULL;
pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
-
+
r = pa_idxset_put(core->sources, s, &s->index);
assert(s->index != PA_IDXSET_INVALID && r >= 0);
s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
s->thread_info.soft_volume = s->volume;
s->thread_info.soft_muted = s->muted;
-
+
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
return s;
static void source_stop(pa_source *s) {
pa_source_state_t state;
int stop;
-
+
pa_assert(s);
state = pa_source_get_state(s);
pa_return_if_fail(state == PA_SOURCE_RUNNING || state == PA_SOURCE_SUSPENDED);
pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECT);
source_stop(s);
-
+
pa_atomic_store(&s->state, PA_SOURCE_DISCONNECTED);
pa_namereg_unregister(s->core, s->name);
static void source_free(pa_msgobject *o) {
pa_source *s = PA_SOURCE(o);
-
+
pa_assert(s);
pa_assert(pa_source_refcnt(s) == 0);
pa_hashmap_free(s->thread_info.outputs, pa_sink_output_unref, NULL);
pa_asyncmsgq_free(s->asyncmsgq);
-
+
pa_xfree(s->name);
pa_xfree(s->description);
pa_xfree(s->driver);
if (pa_source_get_state(s) == PA_SOURCE_STATE_SUSPENDED)
return;
-
+
if (pa_source_used_by(s) > 0)
source_start(s);
else
s->stop(s);
else
pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
-
+
} else {
pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
pa_source_output *o;
void *state = NULL;
-
+
pa_source_assert_ref(s);
pa_assert(chunk);
pa_memblock_ref(vchunk.memblock);
pa_memchunk_make_writable(&vchunk, 0);
-
+
if (s->thread_info.muted || pa_cvolume_is_muted(s->thread_info.volume))
pa_silence_memchunk(&vchunk, &s->sample_spec);
else
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
pa_source_output_push(o, &vchunk);
-
+
pa_memblock_unref(vchunk.memblock);
} else {
-
+
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
pa_source_output_push(o, chunk);
changed = !pa_cvolume_equal(volume, s->volume);
s->volume = *volume;
-
+
if (s->set_volume && s->set_volume(s) < 0)
s->set_volume = NULL;
pa_source_assert_ref(s);
old_volume = s->volume;
-
+
if (s->get_volume && s->get_volume(s) < 0)
s->get_volume = NULL;
if (!pa_cvolume_equal(&old_volume, &s->volume))
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
+
return &s->volume;
}
void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
int changed;
-
+
pa_source_assert_ref(s);
changed = s->muted != mute;
int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
int old_muted;
-
+
pa_source_assert_ref(s);
old_muted = s->muted;
-
+
if (s->get_mute && s->get_mute(s) < 0)
s->get_mute = NULL;
if (old_muted != s->muted)
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-
+
return s->muted;
}
return;
s->module = m;
-
+
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
return 0;
}
-
+
case PA_SOURCE_MESSAGE_REMOVE_INPUT: {
pa_source_input *i = userdata;
pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
return 0;
}
-
+
case PA_SOURCE_MESSAGE_SET_VOLUME:
s->thread_info.soft_volume = *((pa_cvolume*) userdata);
return 0;
-
+
case PA_SOURCE_MESSAGE_SET_MUTE:
s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
return 0;
-
+
case PA_SOURCE_MESSAGE_GET_VOLUME:
*((pa_cvolume*) userdata) = s->thread_info.soft_volume;
return 0;
-
+
case PA_SOURCE_MESSAGE_GET_MUTE:
*((int*) userdata) = s->thread_info.soft_muted;
return 0;
-
+
default:
return -1;
}
struct pa_source {
pa_msgobject parent;
-
+
uint32_t index;
pa_core *core;
pa_atomic_t state;
pa_cvolume soft_volume;
int soft_muted;
} thread_info;
-
+
void *userdata;
};
do {
int code = 0;
-
+
pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, 1) == 0);
switch (code) {
-
+
case OPERATION_A:
printf("Operation A\n");
break;
case OPERATION_C:
printf("Operation C\n");
break;
-
+
case QUIT:
printf("quit\n");
quit = 1;
int main(int argc, char *argv[]) {
pa_asyncmsgq *q;
pa_thread *t;
-
+
pa_assert_se(q = pa_asyncmsgq_new(0));
pa_assert_se(t = pa_thread_new(the_thread, q));
static void producer(void *_q) {
pa_asyncq *q = _q;
int i;
-
+
for (i = 0; i < 1000; i++) {
pa_asyncq_push(q, (void*) (i+1), 1);
printf("pushed %i\n", i);
int i;
sleep(1);
-
+
for (i = 0;; i++) {
p = pa_asyncq_pop(q, 1);
break;
pa_assert(p == (void *) (i+1));
-
+
printf("popped %i\n", i);
}
int main(int argc, char *argv[]) {
pa_asyncq *q;
pa_thread *t1, *t2;
-
+
pa_assert_se(q = pa_asyncq_new(0));
pa_assert_se(t1 = pa_thread_new(producer, q));