Пример #1
0
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;
}
Пример #2
0
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;
}