APULSE_EXPORT int pa_mainloop_dispatch(pa_mainloop *m) { trace_info("F %s m=%p\n", __func__, m); int cnt = 0; GList *keys = g_hash_table_get_keys(m->events_ht); GList *it; it = keys; while (it) { struct pa_io_event *ioe = it->data; if (ioe->pollfd && ioe->pollfd->revents) { int idx = ioe->pollfd - m->fds; unsigned short revents = 0; if (0 < idx && idx <= m->alsa_special_cnt) { snd_pcm_poll_descriptors_revents(ioe->pcm, ioe->pollfd, 1, &revents); } else { revents = ioe->pollfd->revents; } if (revents & (~(POLLOUT|POLLIN))) { recover_pcm(ioe->pcm); } else { pa_io_event_flags_t eflags = to_pa_io_event_flags(revents); if (ioe->cb) ioe->cb(&m->api, ioe, ioe->fd, eflags, ioe->cb_userdata); ioe->pollfd->revents = 0; cnt ++; } } it = g_list_next(it); } g_list_free(keys); if (m->fds && m->fds[0].revents) { // drain wakeup pipe char buf[200]; while (read(m->wakeup_pipe[0], buf, sizeof(buf)) > 0) { // cycle } m->fds[0].revents = 0; } pa_defer_event *de = g_queue_pop_head(m->queue); while (de) { if (de->cb) de->cb(&m->api, de, de->userdata); de = g_queue_pop_head(m->queue); } return cnt; }
static void * audio_thread(void *param) { struct pollfd *fds = NULL; nfds_t nfds = 0; static char buf[16 * 1024]; ppb_message_loop_mark_thread_unsuitable(); nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; while (1) { if (g_atomic_int_get(&terminate_thread)) goto quit; int res = poll(fds, nfds, 10 * 1000); if (res == -1) { if (errno == EINTR) continue; trace_error("%s, poll, errno=%d\n", __func__, errno); continue; } if (res == 0 || fds == NULL) continue; if (fds[0].revents) drain_wakeup_pipe(fds[0].fd); if (g_atomic_int_get(&rebuild_fds)) { nfds = do_rebuild_fds(&fds); pthread_barrier_wait(&stream_list_update_barrier); if (nfds == 0) goto quit; } for (uintptr_t k = 1; k < nfds; k ++) { unsigned short revents = 0; audio_stream *as = g_hash_table_lookup(stream_by_fd_ht, GINT_TO_POINTER(fds[k].fd)); // check if stream was deleted if (!as) continue; snd_pcm_poll_descriptors_revents(as->pcm, &fds[k], 1, &revents); if (revents & (~(POLLIN | POLLOUT))) { trace_warning("%s, revents have unexpected flags set (%u)\n", __func__, (unsigned int)revents); recover_pcm(as->pcm); } if (revents & (POLLIN | POLLOUT)) { int paused = g_atomic_int_get(&as->paused); snd_pcm_sframes_t frame_count = snd_pcm_avail(as->pcm); if (revents & POLLIN) { // POLLIN const size_t frame_size = 1 * sizeof(int16_t); // mono 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_read; const size_t segment_length = MIN(to_process, max_segment_length); frames_read = snd_pcm_readi(as->pcm, buf, segment_length / frame_size); if (frames_read < 0) { trace_warning("%s, snd_pcm_readi error %d\n", __func__, (int)frames_read); recover_pcm(as->pcm); continue; } if (!paused && as->capture_cb) as->capture_cb(buf, frames_read * frame_size, 0, as->cb_user_data); to_process -= frames_read * frame_size; } } else { // POLLOUT const size_t frame_size = 2 * sizeof(int16_t); // stereo 16-bit const size_t max_segment_length = MIN(as->sample_frame_count * frame_size, sizeof(buf)); size_t to_process = frame_count * frame_size; while (to_process > 0) { snd_pcm_sframes_t frames_written; const size_t segment_length = MIN(to_process, max_segment_length); if (paused || !as->playback_cb) memset(buf, 0, segment_length); else as->playback_cb(buf, segment_length, 0, as->cb_user_data); frames_written = snd_pcm_writei(as->pcm, buf, segment_length / frame_size); if (frames_written < 0) { trace_warning("%s, snd_pcm_writei error %d\n", __func__, (int)frames_written); recover_pcm(as->pcm); continue; } to_process -= frames_written * frame_size; } } } } } quit: free(fds); return NULL; }