static int sink_process_msg(pa_msgobject * o, int code, void *data, int64_t offset, pa_memchunk * chunk) { int r; struct userdata *u = PA_SINK(o)->userdata; int state; switch (code) { case PA_SINK_MESSAGE_SET_STATE: state = PA_PTR_TO_UINT(data); r = pa_sink_process_msg(o, code, data, offset, chunk); if (r >= 0) { pa_log("sink cork req state =%d, now state=%d\n", state, (int) (u->sink->state)); } return r; case PA_SINK_MESSAGE_GET_LATENCY: { size_t n = 0; n += u->memchunk_sink.length; *((pa_usec_t *) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg( pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: if (pa_sink_get_state(u->sink) == PA_SINK_SUSPENDED || pa_sink_get_state(u->sink) == PA_SINK_INIT) { if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING || PA_PTR_TO_UINT(data) == PA_SINK_IDLE) u->timestamp = pa_rtclock_now(); } break; case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t now; now = pa_rtclock_now(); *((int64_t*) data) = (int64_t)u->timestamp - (int64_t)now; return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t w, r; r = pa_smoother_get(u->smoother, pa_rtclock_now()); w = pa_bytes_to_usec((uint64_t) u->offset + u->memchunk.length, &u->sink->sample_spec); *((int64_t*) data) = (int64_t)w - r; return 0; } case SINK_MESSAGE_PASS_SOCKET: { struct pollfd *pollfd; pa_assert(!u->rtpoll_item); u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->fd = u->fd; pollfd->events = pollfd->revents = 0; return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg( pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: pa_log("mesg set state"); if (PA_PTR_TO_INT(data) == PA_SINK_RUNNING) u->timestamp = pa_rtclock_now(); break; case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t now; pa_log("mesg get latency"); now = pa_rtclock_now(); *((pa_usec_t*)data) = u->timestamp > now ? u->timestamp - now : 0; return 0; } } pa_log("sink message: %u", code); return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from I/O thread context */ static int raw_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; if (!u->master_sink) return -1; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t usec = 0; if (PA_MSGOBJECT(u->master_sink)->process_msg(PA_MSGOBJECT(u->master_sink), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0) usec = 0; *((pa_usec_t*) data) = usec; return 0; } case PA_SINK_MESSAGE_ADD_INPUT: { pa_sink_input *i = PA_SINK_INPUT(data); if (i == u->hw_sink_input) { pa_log_error("Denied loop connection"); // TODO: This does not work... we should do something more deny connection.. return -1; } break; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from I/O thread context */ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: /* The sink is _put() before the sink input is, so let's * make sure we don't access it in that time. Also, the * sink input is first shut down, the sink second. */ if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) { *((pa_usec_t*) data) = 0; return 0; } *((pa_usec_t*) data) = /* Get the latency of the master sink */ pa_sink_get_latency_within_thread(u->sink_input->sink) + /* Add the latency internal to our sink input on top */ pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); return 0; } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) pa_rtclock_get(&u->timestamp); break; case PA_SINK_MESSAGE_GET_LATENCY: { struct timeval now; pa_rtclock_get(&now); 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; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { case PA_SINK_SUSPENDED: pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); pa_smoother_pause(u->smoother, pa_rtclock_now()); break; case PA_SINK_IDLE: case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) pa_smoother_resume(u->smoother, pa_rtclock_now(), TRUE); break; case PA_SINK_UNLINKED: case PA_SINK_INIT: case PA_SINK_INVALID_STATE: ; } break; case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t w, r; r = pa_smoother_get(u->smoother, pa_rtclock_now()); w = pa_bytes_to_usec((uint64_t) u->offset + u->memchunk.length, &u->sink->sample_spec); *((pa_usec_t*) data) = w > r ? w - r : 0; return 0; } case SINK_MESSAGE_PASS_SOCKET: { struct pollfd *pollfd; pa_assert(!u->rtpoll_item); u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->fd = u->fd; pollfd->events = pollfd->revents = 0; return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { int negative; pa_usec_t remote_latency; if (!PA_SINK_IS_LINKED(u->sink->thread_info.state)) { *((pa_usec_t*) data) = 0; return 0; } if (!u->stream) { *((pa_usec_t*) data) = 0; return 0; } if (pa_stream_get_state(u->stream) != PA_STREAM_READY) { *((pa_usec_t*) data) = 0; return 0; } if (pa_stream_get_latency(u->stream, &remote_latency, &negative) < 0) { *((pa_usec_t*) data) = 0; return 0; } *((pa_usec_t*) data) = remote_latency; return 0; } case PA_SINK_MESSAGE_SET_STATE: if (!u->stream || pa_stream_get_state(u->stream) != PA_STREAM_READY) break; switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { case PA_SINK_SUSPENDED: { cork_stream(u, true); break; } case PA_SINK_IDLE: case PA_SINK_RUNNING: { cork_stream(u, false); break; } case PA_SINK_INVALID_STATE: case PA_SINK_INIT: case PA_SINK_UNLINKED: break; } break; } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int process_message( pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: /* if sink has additional internal latency, it may report it here */ *((pa_usec_t*)data) = 0; return 0; } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec); return 0; case PA_SINK_MESSAGE_SET_STATE: switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { case PA_SINK_SUSPENDED: pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); pa_smoother_pause(u->smoother, pa_rtclock_now()); if (!u->source || u->source_suspended) { if (suspend(u) < 0) return -1; } u->sink_suspended = true; break; case PA_SINK_IDLE: case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { pa_smoother_resume(u->smoother, pa_rtclock_now(), true); if (!u->source || u->source_suspended) { if (unsuspend(u) < 0) return -1; u->sink->get_volume(u->sink); u->sink->get_mute(u->sink); } u->sink_suspended = false; } break; case PA_SINK_INVALID_STATE: case PA_SINK_UNLINKED: case PA_SINK_INIT: ; } break; } return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from I/O thread context */ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: /* there's no real latency here */ *((pa_usec_t*) data) = 0; return 0; } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { size_t n = 0; n += u->memchunk.length; *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct context *context = PA_SINK(o)->userdata; pa_usec_t now; long latency; pa_log_debug("sink_process_msg: code %d", code); switch (code) { case PA_SINK_MESSAGE_SET_VOLUME: /* 3 */ break; case PA_SINK_MESSAGE_SET_MUTE: /* 6 */ break; case PA_SINK_MESSAGE_GET_LATENCY: /* 7 */ now = pa_rtclock_now(); latency = context->timestamp > now ? context->timestamp - now : 0ULL; pa_log_debug("sink_process_msg: latency %ld", latency); *((pa_usec_t*) data) = latency; return 0; case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: /* 8 */ break; case PA_SINK_MESSAGE_SET_STATE: /* 9 */ if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) /* 0 */ { pa_log("sink_process_msg: running"); context->timestamp = pa_rtclock_now(); } else { pa_log("sink_process_msg: not running"); close_send(context); } break; } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u; if (pa_sink_isinstance(o)) { u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->hwo) r = sink_get_latency(u); *((pa_usec_t*) data) = r; return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); } if (pa_source_isinstance(o)) { u = PA_SOURCE(o)->userdata; switch (code) { case PA_SOURCE_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->hwi) r = source_get_latency(u); *((pa_usec_t*) data) = r; return 0; } } return pa_source_process_msg(o, code, data, offset, chunk); } return -1; }
/* Called from I/O thread context */ static int voip_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case VOICE_SINK_GET_SIDE_INFO_QUEUE_PTR: { /* TODO: Make sure there is only one client (or multiple queues) */ if (!u->dl_sideinfo_queue) { pa_log_warn("Side info queue not set"); } *((pa_queue **) data) = u->dl_sideinfo_queue; pa_log_debug("Side info queue (%p) passed to client", (void *) u->dl_sideinfo_queue); return 0; } case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t usec = 0; if (PA_MSGOBJECT(u->raw_sink)->process_msg(PA_MSGOBJECT(u->raw_sink), PA_SINK_MESSAGE_GET_LATENCY, &usec, (int64_t)0, NULL) < 0) usec = 0; *((pa_usec_t*) data) = usec; return 0; } case PA_SINK_MESSAGE_ADD_INPUT: { pa_sink_input *i = PA_SINK_INPUT(data); if (i == u->hw_sink_input) { pa_log_error("Denied loop connection"); // TODO: How to deny connection... return -1; } // Pass trough to pa_sink_process_msg break; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from I/O thread context */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: /* The sink is _put() before the sink input is, so let's * make sure we don't access it yet */ if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) { *((int64_t*) data) = 0; return 0; } *((int64_t*) data) = /* Get the latency of the master sink */ pa_sink_get_latency_within_thread(u->sink_input->sink, true) + /* Add the latency internal to our sink input on top */ pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); return 0; case PA_SINK_MESSAGE_SET_STATE: { pa_sink_state_t new_state = (pa_sink_state_t) PA_PTR_TO_UINT(data); /* When set to running or idle for the first time, request a rewind * of the master sink to make sure we are heard immediately */ if ((new_state == PA_SINK_IDLE || new_state == PA_SINK_RUNNING) && u->sink->thread_info.state == PA_SINK_INIT) { pa_log_debug("Requesting rewind due to state change."); pa_sink_input_request_rewind(u->sink_input, 0, false, true, true); } break; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { size_t n = 0; int l; #ifdef FIONREAD if (ioctl(u->fd, FIONREAD, &l) >= 0 && l > 0) n = (size_t) l; #endif n += u->memchunk.length; *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from IO context */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd >= 0) { if (u->use_mmap) r = mmap_sink_get_latency(u); else r = io_sink_get_latency(u); } *((int64_t*) data) = (int64_t)r; return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *memchunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case SINK_MESSAGE_RENDER: /* Handle the request from the JACK thread */ if (u->sink->thread_info.state == PA_SINK_RUNNING) { pa_memchunk chunk; size_t nbytes; void *p; pa_assert(offset > 0); nbytes = (size_t) offset * pa_frame_size(&u->sink->sample_spec); pa_sink_render_full(u->sink, nbytes, &chunk); p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index; pa_deinterleave(p, u->buffer, u->channels, sizeof(float), (unsigned) offset); pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); } else { unsigned c; pa_sample_spec ss; /* Humm, we're not RUNNING, hence let's write some silence */ ss = u->sink->sample_spec; ss.channels = 1; for (c = 0; c < u->channels; c++) pa_silence_memory(u->buffer[c], (size_t) offset * pa_sample_size(&ss), &ss); } u->frames_in_buffer = (jack_nframes_t) offset; u->saved_frame_time = * (jack_nframes_t*) data; u->saved_frame_time_valid = TRUE; return 0; case SINK_MESSAGE_BUFFER_SIZE: pa_sink_set_max_request_within_thread(u->sink, (size_t) offset * pa_frame_size(&u->sink->sample_spec)); return 0; case SINK_MESSAGE_ON_SHUTDOWN: pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); return 0; case PA_SINK_MESSAGE_GET_LATENCY: { jack_nframes_t l, ft, d; size_t n; /* This is the "worst-case" latency */ l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer; if (u->saved_frame_time_valid) { /* Adjust the worst case latency by the time that * passed since we last handed data to JACK */ ft = jack_frame_time(u->client); d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0; l = l > d ? l - d : 0; } /* Convert it to usec */ n = l * pa_frame_size(&u->sink->sample_spec); *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec); return 0; } } return pa_sink_process_msg(o, code, data, offset, memchunk); }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { case PA_SINK_SUSPENDED: pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); pa_smoother_pause(u->smoother, pa_rtclock_now()); /* Issue a FLUSH if we are connected */ if (u->fd >= 0) { pa_raop_flush(u->raop); } break; case PA_SINK_IDLE: case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { pa_smoother_resume(u->smoother, pa_rtclock_now(), true); /* The connection can be closed when idle, so check to see if we need to reestablish it */ if (u->fd < 0) pa_raop_connect(u->raop); else pa_raop_flush(u->raop); } break; case PA_SINK_UNLINKED: case PA_SINK_INIT: case PA_SINK_INVALID_STATE: ; } break; case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t w, r; r = pa_smoother_get(u->smoother, pa_rtclock_now()); w = pa_bytes_to_usec((u->offset - u->encoding_overhead + (u->encoded_memchunk.length / u->encoding_ratio)), &u->sink->sample_spec); *((pa_usec_t*) data) = w > r ? w - r : 0; return 0; } case SINK_MESSAGE_PASS_SOCKET: { struct pollfd *pollfd; pa_assert(!u->rtpoll_item); u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->fd = u->fd; pollfd->events = POLLOUT; /*pollfd->events = */pollfd->revents = 0; if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { /* Our stream has been suspended so we just flush it.... */ pa_raop_flush(u->raop); } return 0; } case SINK_MESSAGE_RIP_SOCKET: { if (u->fd >= 0) { pa_close(u->fd); u->fd = -1; } else /* FIXME */ pa_log("We should not get to this state. Cannot rip socket if not connected."); if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { pa_log_debug("RTSP control connection closed, but we're suspended so let's not worry about it... we'll open it again later"); if (u->rtpoll_item) pa_rtpoll_item_free(u->rtpoll_item); u->rtpoll_item = NULL; } else { /* Question: is this valid here: or should we do some sort of: return pa_sink_process_msg(PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL); ?? */ pa_module_unload_request(u->module, true); } return 0; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
/* Called from IO context */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; int ret; pa_bool_t do_trigger = FALSE, quick = TRUE; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd >= 0) { if (u->use_mmap) r = mmap_sink_get_latency(u); else r = io_sink_get_latency(u); } *((pa_usec_t*) data) = r; return 0; } case PA_SINK_MESSAGE_SET_STATE: switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { case PA_SINK_SUSPENDED: pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); if (!u->source || u->source_suspended) { if (suspend(u) < 0) return -1; } do_trigger = TRUE; u->sink_suspended = TRUE; break; case PA_SINK_IDLE: case PA_SINK_RUNNING: if (u->sink->thread_info.state == PA_SINK_INIT) { do_trigger = TRUE; quick = u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state); } if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { if (!u->source || u->source_suspended) { if (unsuspend(u) < 0) return -1; quick = FALSE; } do_trigger = TRUE; u->out_mmap_current = 0; u->out_mmap_saved_nfrags = 0; u->sink_suspended = FALSE; } break; case PA_SINK_INVALID_STATE: case PA_SINK_UNLINKED: case PA_SINK_INIT: ; } break; } ret = pa_sink_process_msg(o, code, data, offset, chunk); if (ret >= 0 && do_trigger) { if (trigger(u, quick) < 0) return -1; } return ret; }
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; int err; audio_info_t info; switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec); r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec); if (u->memchunk.memblock) r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec); } *((pa_usec_t*) data) = r; return 0; } case PA_SINK_MESSAGE_SET_VOLUME: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.play.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) pa_log("AUDIO_SETINFO: Unsupported volume."); else pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } else { return 0; } } break; case PA_SINK_MESSAGE_GET_VOLUME: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); assert(err >= 0); pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); return 0; } break; case PA_SINK_MESSAGE_SET_MUTE: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.output_muted = !!PA_PTR_TO_UINT(data); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); else return 0; } break; case PA_SINK_MESSAGE_GET_MUTE: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); *(int*)data = !!info.output_muted; return 0; } break; } return pa_sink_process_msg(o, code, data, offset, chunk); }