Ejemplo n.º 1
0
static int do_read(connection *c) {
    pa_memchunk chunk;
    ssize_t r;
    size_t l;
    void *p;
    size_t space = 0;

    connection_assert_ref(c);

    if (!c->sink_input || (l = (size_t) pa_atomic_load(&c->playback.missing)) <= 0)
        return 0;

    if (c->playback.current_memblock) {

        space = pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index;

        if (space <= 0) {
            pa_memblock_unref(c->playback.current_memblock);
            c->playback.current_memblock = NULL;
        }
    }

    if (!c->playback.current_memblock) {
        pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1));
        c->playback.memblock_index = 0;

        space = pa_memblock_get_length(c->playback.current_memblock);
    }

    if (l > space)
        l = space;

    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 (r < 0 && (errno == EINTR || errno == EAGAIN))
            return 0;

        pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
        return -1;
    }

    chunk.memblock = c->playback.current_memblock;
    chunk.index = c->playback.memblock_index;
    chunk.length = (size_t) r;

    c->playback.memblock_index += (size_t) r;

    pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
    pa_atomic_sub(&c->playback.missing, (int) r);

    return 0;
}
Ejemplo n.º 2
0
pa_memchunk* pa_memchunk_memcpy(pa_memchunk *dst, pa_memchunk *src) {
    void *p, *q;

    pa_assert(dst);
    pa_assert(src);
    pa_assert(dst->length == src->length);

    p = pa_memblock_acquire(dst->memblock);
    q = pa_memblock_acquire(src->memblock);

    memmove((uint8_t*) p + dst->index,
            (uint8_t*) q + src->index,
            dst->length);

    pa_memblock_release(dst->memblock);
    pa_memblock_release(src->memblock);

    return dst;
}
Ejemplo n.º 3
0
static void do_read(struct userdata *u) {
    uint32_t free_frags;
    pa_memchunk memchunk;
    WAVEHDR *hdr;
    MMRESULT res;
    void *p;

    if (!u->source)
        return;

    if (!PA_SOURCE_IS_LINKED(u->source->state))
        return;

    EnterCriticalSection(&u->crit);
    free_frags = u->free_ifrags;
    u->free_ifrags = 0;
    LeaveCriticalSection(&u->crit);

    if (free_frags == u->fragments)
        pa_log_debug("WaveIn overflow!");

    while (free_frags) {
        hdr = &u->ihdrs[u->cur_ihdr];
        if (hdr->dwFlags & WHDR_PREPARED)
            waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR));

        if (hdr->dwBytesRecorded) {
            memchunk.memblock = pa_memblock_new(u->core->mempool, hdr->dwBytesRecorded);
            pa_assert(memchunk.memblock);

            p = pa_memblock_acquire(memchunk.memblock);
            memcpy((char*) p, hdr->lpData, hdr->dwBytesRecorded);
            pa_memblock_release(memchunk.memblock);

            memchunk.length = hdr->dwBytesRecorded;
            memchunk.index = 0;

            pa_source_post(u->source, &memchunk);
            pa_memblock_unref(memchunk.memblock);
        }

        res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
            pa_log_error("Unable to prepare waveIn block: %d", res);

        res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
            pa_log_error("Unable to add waveIn block: %d", res);

        free_frags--;
        u->cur_ihdr++;
        u->cur_ihdr %= u->fragments;
    }
}
Ejemplo n.º 4
0
static void dump_chunk(const pa_memchunk *chunk) {
    size_t n;
    void *q;
    char *e;

    pa_assert(chunk);

    q = pa_memblock_acquire(chunk->memblock);
    for (e = (char*) q + chunk->index, n = 0; n < chunk->length; n++, e++)
        fprintf(stderr, "%c", *e);
    pa_memblock_release(chunk->memblock);
}
Ejemplo n.º 5
0
/* No lock necessary. */
pa_memblock *pa_memblock_will_need(pa_memblock *b) {
    void *p;

    pa_assert(b);
    pa_assert(PA_REFCNT_VALUE(b) > 0);

    p = pa_memblock_acquire(b);
    pa_will_need(p, b->length);
    pa_memblock_release(b);

    return b;
}
Ejemplo n.º 6
0
pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
    void *data;

    pa_assert(b);
    pa_assert(spec);

    data = pa_memblock_acquire(b);
    pa_silence_memory(data, pa_memblock_get_length(b), spec);
    pa_memblock_release(b);

    return b;
}
Ejemplo n.º 7
0
pa_memchunk* pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
    void *data;

    pa_assert(c);
    pa_assert(c->memblock);
    pa_assert(spec);

    data = pa_memblock_acquire(c->memblock);
    pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
    pa_memblock_release(c->memblock);

    return c;
}
Ejemplo n.º 8
0
pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c) {
    void *p;

    pa_assert(c);
    pa_assert(c->memblock);

    /* A version of pa_memblock_will_need() that works on memchunks
     * instead of memblocks */

    p = pa_memblock_acquire_chunk(c);
    pa_will_need(p, c->length);
    pa_memblock_release(c->memblock);

    return (pa_memchunk*) c;
}
Ejemplo n.º 9
0
static int process_render(struct userdata *u) {
    pa_assert(u);


    if (u->memchunk.length <= 0)
        pa_sink_render(u->sink, ioring->usable_buffer_space, &u->memchunk);


    pa_assert(u->memchunk.length > 0);

    xc_evtchn_notify(xce, xen_evtchn_port);
    for (;;) {
        ssize_t l;
        void *p;

        p = pa_memblock_acquire(u->memchunk.memblock);
	    /* xen: write data to ring buffer & notify backend */
        l = ring_write(ioring, (uint8_t*)p + u->memchunk.index, u->memchunk.length);

        pa_memblock_release(u->memchunk.memblock);

        pa_assert(l != 0);

        if (l < 0) {
            if (errno == EINTR)
                continue;
            else if (errno == EAGAIN)
                return 0;
            else {
                pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
                return -1;
            }

        } else {

            u->memchunk.index += (size_t) l;
            u->memchunk.length -= (size_t) l;

            if (u->memchunk.length <= 0) {
                pa_memblock_unref(u->memchunk.memblock);
                pa_memchunk_reset(&u->memchunk);
            }
        }

        return 0;
    }
}
Ejemplo n.º 10
0
static int process_sink_render(struct userdata *u)
{
    pa_assert(u);

    if (u->memchunk_sink.length <= 0)
        pa_sink_render(u->sink, libvchan_buffer_space(u->play_ctrl), &u->memchunk_sink);

    pa_assert(u->memchunk_sink.length > 0);

    for (;;) {
        ssize_t l;
        void *p;

        p = pa_memblock_acquire(u->memchunk_sink.memblock);
        l = write_to_vchan(u->play_ctrl, (char *) p +
                           u->memchunk_sink.index, u->memchunk_sink.length);
        pa_memblock_release(u->memchunk_sink.memblock);

        pa_assert(l != 0);

        if (l < 0) {

            if (errno == EINTR)
                continue;
            else if (errno == EAGAIN)
                return 0;
            else {
                pa_log
                ("Failed to write data to VCHAN: %s",
                 pa_cstrerror(errno));
                return -1;
            }

        } else {

            u->memchunk_sink.index += (size_t) l;
            u->memchunk_sink.length -= (size_t) l;

            if (u->memchunk_sink.length <= 0) {
                pa_memblock_unref(u->memchunk_sink.memblock);
                pa_memchunk_reset(&u->memchunk_sink);
            }
        }

        return 0;
    }
}
/* Called from thread context */
static void cmtspeech_source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
    struct userdata *u;
    uint8_t *buf;

    pa_assert(o);
    pa_assert_se(u = o->userdata);

    if (chunk->length != u->ul_frame_size) {
        pa_log_warn("Pushed UL audio frame has wrong size %zu", chunk->length);
        return;
    }

    buf = ((uint8_t *) pa_memblock_acquire(chunk->memblock)) + chunk->index;

    (void)cmtspeech_send_ul_frame(u, buf, chunk->length);

    pa_memblock_release(chunk->memblock);
}
Ejemplo n.º 12
0
static int process_render(struct userdata *u) {
    pa_assert(u);

    if (u->memchunk.length <= 0)
        pa_sink_render(u->sink, u->buffer_size, &u->memchunk);

    pa_assert(u->memchunk.length > 0);

    for (;;) {
        ssize_t l;
        void *p;

        p = pa_memblock_acquire(u->memchunk.memblock);
        l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &u->write_type);
        pa_memblock_release(u->memchunk.memblock);

        pa_assert(l != 0);

        if (l < 0) {

            if (errno == EINTR)
                continue;
            else if (errno == EAGAIN)
                return 0;
            else {
                pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
                return -1;
            }

        } else {

            u->memchunk.index += (size_t) l;
            u->memchunk.length -= (size_t) l;

            if (u->memchunk.length <= 0) {
                pa_memblock_unref(u->memchunk.memblock);
                pa_memchunk_reset(&u->memchunk);
            }
        }

        return 0;
    }
}
Ejemplo n.º 13
0
static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) {
    pa_memblock *b;
    size_t length;
    void *data;

    pa_assert(pool);

    length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX);

    b = pa_memblock_new(pool, length);

    data = pa_memblock_acquire(b);
    memset(data, c, length);
    pa_memblock_release(b);

    pa_memblock_set_is_silence(b, true);

    return b;
}
Ejemplo n.º 14
0
static void dump(pa_memblockq *bq) {
    printf(">");

    for (;;) {
        pa_memchunk out;
        char *e;
        size_t n;
        void *q;

        if (pa_memblockq_peek(bq, &out) < 0)
            break;

        q = pa_memblock_acquire(out.memblock);
        for (e = (char*) q + out.index, n = 0; n < out.length; n++)
            printf("%c", *e);
        pa_memblock_release(out.memblock);

        pa_memblock_unref(out.memblock);
        pa_memblockq_drop(bq, out.length);
    }

    printf("<\n");
}
Ejemplo n.º 15
0
void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) {
    size_t l;
    unsigned gcd, n;
    void *p;

    pa_memchunk_reset(c);

    gcd = pa_gcd(rate, freq);
    n = rate / gcd;

    l = pa_mempool_block_size_max(pool) / sizeof(float);

    l /= n;
    if (l <= 0) l = 1;
    l *= n;

    c->length = l * sizeof(float);
    c->memblock = pa_memblock_new(pool, c->length);

    p = pa_memblock_acquire(c->memblock);
    calc_sine(p, c->length, freq * l / rate);
    pa_memblock_release(c->memblock);
}
Ejemplo n.º 16
0
static int do_write(connection *c) {
    pa_memchunk chunk;
    ssize_t r;
    void *p;

    connection_assert_ref(c);

    if (!c->source_output)
        return 0;

    if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) {
/*         pa_log("peek failed"); */
        return 0;
    }

    pa_assert(chunk.memblock);
    pa_assert(chunk.length);

    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) {

        if (errno == EINTR || errno == EAGAIN)
            return 0;

        pa_log("write(): %s", pa_cstrerror(errno));
        return -1;
    }

    pa_memblockq_drop(c->output_memblockq, (size_t) r);

    return 0;
}
Ejemplo n.º 17
0
void pa_srbchannel_free(pa_srbchannel *sr)
{
#ifdef DEBUG_SRBCHANNEL
    pa_log("Freeing srbchannel");
#endif
    pa_assert(sr);

    if (sr->defer_event)
        sr->mainloop->defer_free(sr->defer_event);
    if (sr->read_event)
        sr->mainloop->io_free(sr->read_event);

    if (sr->sem_read)
        pa_fdsem_free(sr->sem_read);
    if (sr->sem_write)
        pa_fdsem_free(sr->sem_write);

    if (sr->memblock) {
        pa_memblock_release(sr->memblock);
        pa_memblock_unref(sr->memblock);
    }

    pa_xfree(sr);
}
Ejemplo n.º 18
0
static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) {
    pa_memblock *r;
    void *d;
    unsigned i;

    pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10));
    d = pa_memblock_acquire(r);

    switch (ss->format) {

        case PA_SAMPLE_U8:
        case PA_SAMPLE_ULAW:
        case PA_SAMPLE_ALAW: {
            uint8_t *u = d;

            u[0] = 0x00;
            u[1] = 0xFF;
            u[2] = 0x7F;
            u[3] = 0x80;
            u[4] = 0x9f;
            u[5] = 0x3f;
            u[6] = 0x1;
            u[7] = 0xF0;
            u[8] = 0x20;
            u[9] = 0x21;
            break;
        }

        case PA_SAMPLE_S16NE:
        case PA_SAMPLE_S16RE: {
            uint16_t *u = d;

            u[0] = 0x0000;
            u[1] = 0xFFFF;
            u[2] = 0x7FFF;
            u[3] = 0x8000;
            u[4] = 0x9fff;
            u[5] = 0x3fff;
            u[6] = 0x1;
            u[7] = 0xF000;
            u[8] = 0x20;
            u[9] = 0x21;
            break;
        }

        case PA_SAMPLE_S32NE:
        case PA_SAMPLE_S32RE: {
            uint32_t *u = d;

            u[0] = 0x00000001;
            u[1] = 0xFFFF0002;
            u[2] = 0x7FFF0003;
            u[3] = 0x80000004;
            u[4] = 0x9fff0005;
            u[5] = 0x3fff0006;
            u[6] =    0x10007;
            u[7] = 0xF0000008;
            u[8] =   0x200009;
            u[9] =   0x21000A;
            break;
        }

        case PA_SAMPLE_S24_32NE:
        case PA_SAMPLE_S24_32RE: {
            uint32_t *u = d;

            u[0] = 0x000001;
            u[1] = 0xFF0002;
            u[2] = 0x7F0003;
            u[3] = 0x800004;
            u[4] = 0x9f0005;
            u[5] = 0x3f0006;
            u[6] =    0x107;
            u[7] = 0xF00008;
            u[8] =   0x2009;
            u[9] =   0x210A;
            break;
        }

        case PA_SAMPLE_FLOAT32NE:
        case PA_SAMPLE_FLOAT32RE: {
            float *u = d;

            u[0] = 0.0f;
            u[1] = -1.0f;
            u[2] = 1.0f;
            u[3] = 4711.0f;
            u[4] = 0.222f;
            u[5] = 0.33f;
            u[6] = -.3f;
            u[7] = 99.0f;
            u[8] = -0.555f;
            u[9] = -.123f;

            if (ss->format == PA_SAMPLE_FLOAT32RE)
                for (i = 0; i < 10; i++)
                    u[i] = PA_FLOAT32_SWAP(u[i]);

            break;
        }

        case PA_SAMPLE_S24NE:
        case PA_SAMPLE_S24RE: {
            uint8_t *u = d;

            PA_WRITE24NE(u,    0x000001);
            PA_WRITE24NE(u+3,  0xFF0002);
            PA_WRITE24NE(u+6,  0x7F0003);
            PA_WRITE24NE(u+9,  0x800004);
            PA_WRITE24NE(u+12, 0x9f0005);
            PA_WRITE24NE(u+15, 0x3f0006);
            PA_WRITE24NE(u+18,    0x107);
            PA_WRITE24NE(u+21, 0xF00008);
            PA_WRITE24NE(u+24,   0x2009);
            PA_WRITE24NE(u+27,   0x210A);
            break;
        }

        default:
            pa_assert_not_reached();
    }

    pa_memblock_release(r);

    return r;
}
Ejemplo n.º 19
0
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);
}
Ejemplo n.º 20
0
int pa_sound_file_load(
        pa_mempool *pool,
        const char *fname,
        pa_sample_spec *ss,
        pa_channel_map *map,
        pa_memchunk *chunk,
        pa_proplist *p) {

    SNDFILE *sf = NULL;
    SF_INFO sfi;
    int ret = -1;
    size_t l;
    sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
    void *ptr = NULL;
    int fd;

    pa_assert(fname);
    pa_assert(ss);
    pa_assert(chunk);

    pa_memchunk_reset(chunk);

    if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) {
        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
        goto finish;
    }

#ifdef HAVE_POSIX_FADVISE
    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
        goto finish;
    } else
        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
#endif

    pa_zero(sfi);
    if (!(sf = sf_open_fd(fd, SFM_READ, &sfi, 1))) {
        pa_log("Failed to open file %s", fname);
        goto finish;
    }

    fd = -1;

    if (pa_sndfile_read_sample_spec(sf, ss) < 0) {
        pa_log("Failed to determine file sample format.");
        goto finish;
    }

    if ((map && pa_sndfile_read_channel_map(sf, map) < 0)) {
        if (ss->channels > 2)
            pa_log("Failed to determine file channel map, synthesizing one.");
        pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT);
    }

    if (p)
        pa_sndfile_init_proplist(sf, p);

    if ((l = pa_frame_size(ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
        pa_log("File too large");
        goto finish;
    }

    chunk->memblock = pa_memblock_new(pool, l);
    chunk->index = 0;
    chunk->length = l;

    readf_function = pa_sndfile_readf_function(ss);

    ptr = pa_memblock_acquire(chunk->memblock);

    if ((readf_function && readf_function(sf, ptr, sfi.frames) != sfi.frames) ||
        (!readf_function && sf_read_raw(sf, ptr, (sf_count_t) l) != (sf_count_t) l)) {
        pa_log("Premature file end");
        goto finish;
    }

    ret = 0;

finish:

    if (sf)
        sf_close(sf);

    if (ptr)
        pa_memblock_release(chunk->memblock);

    if (ret != 0 && chunk->memblock)
        pa_memblock_unref(chunk->memblock);

    if (fd >= 0)
        pa_close(fd);

    return ret;
}
static void thread_func(void *userdata) {
    struct userdata *u = userdata;
    pa_proplist *proplist;
    pa_assert(u);

    pa_log_debug("Thread starting up");
    pa_thread_mq_install(u->thread_mq);

    proplist = tunnel_new_proplist(u);
    u->context = pa_context_new_with_proplist(u->thread_mainloop_api,
                                              "PulseAudio",
                                              proplist);
    pa_proplist_free(proplist);

    if (!u->context) {
        pa_log("Failed to create libpulse context");
        goto fail;
    }

    if (u->cookie_file && pa_context_load_cookie_from_file(u->context, u->cookie_file) != 0) {
        pa_log_error("Can not load cookie file!");
        goto fail;
    }

    pa_context_set_state_callback(u->context, context_state_cb, u);
    if (pa_context_connect(u->context,
                           u->remote_server,
                           PA_CONTEXT_NOAUTOSPAWN,
                           NULL) < 0) {
        pa_log("Failed to connect libpulse context");
        goto fail;
    }

    for (;;) {
        int ret;

        if (pa_mainloop_iterate(u->thread_mainloop, 1, &ret) < 0) {
            if (ret == 0)
                goto finish;
            else
                goto fail;
        }

        if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
            pa_sink_process_rewind(u->sink, 0);

        if (u->connected &&
                pa_stream_get_state(u->stream) == PA_STREAM_READY &&
                PA_SINK_IS_LINKED(u->sink->thread_info.state)) {
            size_t writable;

            writable = pa_stream_writable_size(u->stream);
            if (writable > 0) {
            
                if(u->transcode.encoding != -1) {
                         pa_memchunk memchunk;
                         const void *p;
                         size_t nbBytes;
                         unsigned char *cbits;
                         
                         pa_sink_render_full(u->sink, u->transcode.frame_size*u->transcode.channels*u->transcode.sample_size, &memchunk);
                           
                         pa_assert(memchunk.length > 0);
                         pa_assert(memchunk.length >=  u->transcode.frame_size*u->transcode.channels);
                         
                         
                         pa_log_debug("received memchunk length: %zu bytes", memchunk.length );
                         /* we have new data to write */
                         p = pa_memblock_acquire(memchunk.memblock);
   
                         nbBytes = pa_transcode_encode(&u->transcode, (uint8_t*) p + memchunk.index, &cbits);
                         pa_log_debug("encoded length: %zu bytes", nbBytes);
                                                        
                         /* TODO: Use pa_stream_begin_write() to reduce copying. */
                         ret = pa_stream_write_compressed(u->stream,
                                               (uint8_t*) cbits,
                                               nbBytes,
                                               NULL,     /**< A cleanup routine for the data or NULL to request an internal copy */
                                               0,        /** offset */
                                              PA_SEEK_RELATIVE, u->transcode.frame_size*u->transcode.channels*u->transcode.sample_size);
                         pa_memblock_release(memchunk.memblock);
                         pa_memblock_unref(memchunk.memblock);
                         if(nbBytes > 0) free(cbits);
                         
                         if (ret != 0) {
                             pa_log_error("Could not write data into the stream ... ret = %i", ret);
                             u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
                         }
                }
                else { 
                         pa_memchunk memchunk;
                         const void *p;

                         pa_sink_render_full(u->sink, writable, &memchunk);

                         pa_assert(memchunk.length > 0);

                         /* we have new data to write */
                         p = pa_memblock_acquire(memchunk.memblock);
                         /* TODO: Use pa_stream_begin_write() to reduce copying. */
                         ret = pa_stream_write(u->stream,
                                               (uint8_t*) p + memchunk.index,
                                               memchunk.length,
                                               NULL,     /**< A cleanup routine for the data or NULL to request an internal copy */
                                               0,        /** offset */
                                               PA_SEEK_RELATIVE);
                         pa_memblock_release(memchunk.memblock);
                         pa_memblock_unref(memchunk.memblock);

                         if (ret != 0) {
                             pa_log_error("Could not write data into the stream ... ret = %i", ret);
                             u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
                         }
                
                }

            }
        }
    }
fail:
    pa_asyncmsgq_post(u->thread_mq->outq, PA_MSGOBJECT(u->module->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq->inq, PA_MESSAGE_SHUTDOWN);

finish:
    if (u->stream) {
        pa_stream_disconnect(u->stream);
        pa_stream_unref(u->stream);
        u->stream = NULL;
    }

    if (u->context) {
        pa_context_disconnect(u->context);
        pa_context_unref(u->context);
        u->context = NULL;
    }

    pa_log_debug("Thread shutting down");
}
Ejemplo n.º 22
0
static void thread_func(void *userdata) {
    struct userdata *u = userdata;
    int write_type = 0, read_type = 0;
    short revents = 0;

    pa_assert(u);

    pa_log_debug("Thread starting up");

    if (u->core->realtime_scheduling)
        pa_make_realtime(u->core->realtime_priority);

    pa_thread_mq_install(&u->thread_mq);

    for (;;) {
        int ret;

/*        pa_log("loop");    */

        if (PA_UNLIKELY(u->sink && u->sink->thread_info.rewind_requested))
            pa_sink_process_rewind(u->sink, 0);

        /* Render some data and write it to the dsp */

        if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {

            if (u->use_mmap) {

                if ((ret = mmap_write(u)) < 0)
                    goto fail;

                revents &= ~POLLOUT;

                if (ret > 0)
                    continue;

            } else {
                ssize_t l;
                pa_bool_t loop = FALSE, work_done = FALSE;

                l = (ssize_t) u->out_fragment_size;

                if (u->use_getospace) {
                    audio_buf_info info;

                    if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
                        pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
                        u->use_getospace = FALSE;
                    } else {
                        l = info.bytes;

                        /* We loop only if GETOSPACE worked and we
                         * actually *know* that we can write more than
                         * one fragment at a time */
                        loop = TRUE;
                    }
                }

                /* Round down to multiples of the fragment size,
                 * because OSS needs that (at least some versions
                 * do) */
                l = (l/(ssize_t) u->out_fragment_size) * (ssize_t) u->out_fragment_size;

                /* Hmm, so poll() signalled us that we can read
                 * something, but GETOSPACE told us there was nothing?
                 * Hmm, make the best of it, try to read some data, to
                 * avoid spinning forever. */
                if (l <= 0 && (revents & POLLOUT)) {
                    l = (ssize_t) u->out_fragment_size;
                    loop = FALSE;
                }

                while (l > 0) {
                    void *p;
                    ssize_t t;

                    if (u->memchunk.length <= 0)
                        pa_sink_render(u->sink, (size_t) l, &u->memchunk);

                    pa_assert(u->memchunk.length > 0);

                    p = pa_memblock_acquire(u->memchunk.memblock);
                    t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
                    pa_memblock_release(u->memchunk.memblock);

/*                     pa_log("wrote %i bytes of %u", t, l); */

                    pa_assert(t != 0);

                    if (t < 0) {

                        if (errno == EINTR)
                            continue;

                        else if (errno == EAGAIN) {
                            pa_log_debug("EAGAIN");

                            revents &= ~POLLOUT;
                            break;

                        } else {
                            pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
                            goto fail;
                        }

                    } else {

                        u->memchunk.index += (size_t) t;
                        u->memchunk.length -= (size_t) t;

                        if (u->memchunk.length <= 0) {
                            pa_memblock_unref(u->memchunk.memblock);
                            pa_memchunk_reset(&u->memchunk);
                        }

                        l -= t;

                        revents &= ~POLLOUT;
                        work_done = TRUE;
                    }

                    if (!loop)
                        break;
                }

                if (work_done)
                    continue;
            }
        }

        /* Try to read some data and pass it on to the source driver. */

        if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {

            if (u->use_mmap) {

                if ((ret = mmap_read(u)) < 0)
                    goto fail;

                revents &= ~POLLIN;

                if (ret > 0)
                    continue;

            } else {

                void *p;
                ssize_t l;
                pa_memchunk memchunk;
                pa_bool_t loop = FALSE, work_done = FALSE;

                l = (ssize_t) u->in_fragment_size;

                if (u->use_getispace) {
                    audio_buf_info info;

                    if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
                        pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
                        u->use_getispace = FALSE;
                    } else {
                        l = info.bytes;
                        loop = TRUE;
                    }
                }

                l = (l/(ssize_t) u->in_fragment_size) * (ssize_t) u->in_fragment_size;

                if (l <= 0 && (revents & POLLIN)) {
                    l = (ssize_t) u->in_fragment_size;
                    loop = FALSE;
                }

                while (l > 0) {
                    ssize_t t;
                    size_t k;

                    pa_assert(l > 0);

                    memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);

                    k = pa_memblock_get_length(memchunk.memblock);

                    if (k > (size_t) l)
                        k = (size_t) l;

                    k = (k/u->frame_size)*u->frame_size;

                    p = pa_memblock_acquire(memchunk.memblock);
                    t = pa_read(u->fd, p, k, &read_type);
                    pa_memblock_release(memchunk.memblock);

                    pa_assert(t != 0); /* EOF cannot happen */

/*                     pa_log("read %i bytes of %u", t, l); */

                    if (t < 0) {
                        pa_memblock_unref(memchunk.memblock);

                        if (errno == EINTR)
                            continue;

                        else if (errno == EAGAIN) {
                            pa_log_debug("EAGAIN");

                            revents &= ~POLLIN;
                            break;

                        } else {
                            pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
                            goto fail;
                        }

                    } else {
                        memchunk.index = 0;
                        memchunk.length = (size_t) t;

                        pa_source_post(u->source, &memchunk);
                        pa_memblock_unref(memchunk.memblock);

                        l -= t;

                        revents &= ~POLLIN;
                        work_done = TRUE;
                    }

                    if (!loop)
                        break;
                }

                if (work_done)
                    continue;
            }
        }

/*         pa_log("loop2 revents=%i", revents); */

        if (u->rtpoll_item) {
            struct pollfd *pollfd;

            pa_assert(u->fd >= 0);

            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
            pollfd->events = (short)
                (((u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
                 ((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0));
        }

        /* Hmm, nothing to do. Let's sleep */
        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
            goto fail;

        if (ret == 0)
            goto finish;

        if (u->rtpoll_item) {
            struct pollfd *pollfd;

            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);

            if (pollfd->revents & ~(POLLOUT|POLLIN)) {
                pa_log("DSP shutdown.");
                goto fail;
            }

            revents = pollfd->revents;
        } else
            revents = 0;
    }

fail:
    /* If this was no regular exit from the loop we have to continue
     * processing messages until we received PA_MESSAGE_SHUTDOWN */
    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);

finish:
    pa_log_debug("Thread shutting down");
}
Ejemplo n.º 23
0
static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) {
    pa_memblock *r;
    void *d;
    unsigned i;

    pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10));
    d = pa_memblock_acquire(r);

    switch (ss->format) {

    case PA_SAMPLE_U8:
    case PA_SAMPLE_ULAW:
    case PA_SAMPLE_ALAW: {
        static const uint8_t u8_samples[] = {
            0x00, 0xFF, 0x7F, 0x80, 0x9f,
            0x3f, 0x01, 0xF0, 0x20, 0x21
        };

        memcpy(d, u8_samples, sizeof(u8_samples));
        break;
    }

    case PA_SAMPLE_S16NE:
    case PA_SAMPLE_S16RE: {
        static const uint16_t u16_samples[] = {
            0x0000, 0xFFFF, 0x7FFF, 0x8000, 0x9fff,
            0x3fff, 0x0001, 0xF000, 0x0020, 0x0021
        };

        memcpy(d, u16_samples, sizeof(u16_samples));
        break;
    }

    case PA_SAMPLE_S24_32NE:
    case PA_SAMPLE_S24_32RE:
    case PA_SAMPLE_S32NE:
    case PA_SAMPLE_S32RE: {
        static const uint32_t u32_samples[] = {
            0x00000001, 0xFFFF0002, 0x7FFF0003, 0x80000004, 0x9fff0005,
            0x3fff0006, 0x00010007, 0xF0000008, 0x00200009, 0x0021000A
        };

        memcpy(d, u32_samples, sizeof(u32_samples));
        break;
    }

    case PA_SAMPLE_S24NE:
    case PA_SAMPLE_S24RE: {
        /* Need to be on a byte array because they are not aligned */
        static const uint8_t u24_samples[] = {
            0x00, 0x00, 0x01,
            0xFF, 0xFF, 0x02,
            0x7F, 0xFF, 0x03,
            0x80, 0x00, 0x04,
            0x9f, 0xff, 0x05,
            0x3f, 0xff, 0x06,
            0x01, 0x00, 0x07,
            0xF0, 0x00, 0x08,
            0x20, 0x00, 0x09,
            0x21, 0x00, 0x0A
        };

        memcpy(d, u24_samples, sizeof(u24_samples));
        break;
    }

    case PA_SAMPLE_FLOAT32NE:
    case PA_SAMPLE_FLOAT32RE: {
        float *u = d;
        static const float float_samples[] = {
            0.0f, -1.0f, 1.0f, 4711.0f, 0.222f,
            0.33f, -.3f, 99.0f, -0.555f, -.123f
        };

        if (ss->format == PA_SAMPLE_FLOAT32RE) {
            for (i = 0; i < 10; i++)
                u[i] = PA_FLOAT32_SWAP(float_samples[i]);
        } else
            memcpy(d, float_samples, sizeof(float_samples));

        break;
    }

    default:
        pa_assert_not_reached();
    }

    pa_memblock_release(r);

    return r;
}
Ejemplo n.º 24
0
/* Called from I/O thread context */
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
    struct userdata *u;
    float *src, *dst;
    size_t fs;
    unsigned n, c;
    pa_memchunk tchunk;
    pa_usec_t current_latency PA_GCC_UNUSED;

    pa_sink_input_assert_ref(i);
    pa_assert(chunk);
    pa_assert_se(u = i->userdata);

    /* Hmm, process any rewind request that might be queued up */
    pa_sink_process_rewind(u->sink, 0);

    /* (1) IF YOU NEED A FIXED BLOCK SIZE USE
     * pa_memblockq_peek_fixed_size() HERE INSTEAD. NOTE THAT FILTERS
     * WHICH CAN DEAL WITH DYNAMIC BLOCK SIZES ARE HIGHLY
     * PREFERRED. */
    while (pa_memblockq_peek(u->memblockq, &tchunk) < 0) {
        pa_memchunk nchunk;

        pa_sink_render(u->sink, nbytes, &nchunk);
        pa_memblockq_push(u->memblockq, &nchunk);
        pa_memblock_unref(nchunk.memblock);
    }

    /* (2) IF YOU NEED A FIXED BLOCK SIZE, THIS NEXT LINE IS NOT
     * NECESSARY */
    tchunk.length = PA_MIN(nbytes, tchunk.length);
    pa_assert(tchunk.length > 0);

    fs = pa_frame_size(&i->sample_spec);
    n = (unsigned) (tchunk.length / fs);

    pa_assert(n > 0);

    chunk->index = 0;
    chunk->length = n*fs;
    chunk->memblock = pa_memblock_new(i->sink->core->mempool, chunk->length);

    pa_memblockq_drop(u->memblockq, chunk->length);

    src = pa_memblock_acquire_chunk(&tchunk);
    dst = pa_memblock_acquire(chunk->memblock);

    /* (3) PUT YOUR CODE HERE TO DO SOMETHING WITH THE DATA */

    /* As an example, copy input to output */
    for (c = 0; c < u->channels; c++) {
        pa_sample_clamp(PA_SAMPLE_FLOAT32NE,
                        dst+c, u->channels * sizeof(float),
                        src+c, u->channels * sizeof(float),
                        n);
    }

    pa_memblock_release(tchunk.memblock);
    pa_memblock_release(chunk->memblock);

    pa_memblock_unref(tchunk.memblock);

    /* (4) IF YOU NEED THE LATENCY FOR SOMETHING ACQUIRE IT LIKE THIS: */
    current_latency =
        /* Get the latency of the master sink */
        pa_sink_get_latency_within_thread(i->sink) +

        /* Add the latency internal to our sink input on top */
        pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);

    return 0;
}
Ejemplo n.º 25
0
static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) {
    void *d;
    unsigned i;

    d = pa_memblock_acquire(chunk->memblock);

    switch (ss->format) {

        case PA_SAMPLE_U8:
        case PA_SAMPLE_ULAW:
        case PA_SAMPLE_ALAW: {
            uint8_t *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
                printf("      0x%02x ", *(u++));

            break;
        }

        case PA_SAMPLE_S16NE:
        case PA_SAMPLE_S16RE: {
            uint16_t *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
                printf("    0x%04x ", *(u++));

            break;
        }

        case PA_SAMPLE_S32NE:
        case PA_SAMPLE_S32RE: {
            uint32_t *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
                printf("0x%08x ", *(u++));

            break;
        }

        case PA_SAMPLE_S24_32NE:
        case PA_SAMPLE_S24_32RE: {
            uint32_t *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++)
                printf("0x%08x ", *(u++));

            break;
        }

        case PA_SAMPLE_FLOAT32NE:
        case PA_SAMPLE_FLOAT32RE: {
            float *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
                printf("%4.3g ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u));
                u++;
            }

            break;
        }

        case PA_SAMPLE_S24LE:
        case PA_SAMPLE_S24BE: {
            uint8_t *u = d;

            for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
                printf("  0x%06x ", PA_READ24NE(u));
                u += pa_frame_size(ss);
            }

            break;
        }

        default:
            pa_assert_not_reached();
    }

    printf("\n");

    pa_memblock_release(chunk->memblock);
}
Ejemplo n.º 26
0
/* Called from input thread context */
static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
    struct userdata *u;

    pa_source_output_assert_ref(o);
    pa_source_output_assert_io_context(o);
    pa_assert_se(u = o->userdata);

    if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
        pa_log("push when no link?");
        return;
    }

    /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */

    /* if uplink sink exists, pull data from there; simplify by using
       same length as chunk provided by source */
    if(u->sink && (pa_sink_get_state(u->sink) == PA_SINK_RUNNING)) {
        pa_memchunk tchunk;
        size_t nbytes = chunk->length;
        pa_mix_info streams[2];
        pa_memchunk target_chunk;
        void *target;
        int ch;

        /* Hmm, process any rewind request that might be queued up */
        pa_sink_process_rewind(u->sink, 0);

        /* get data from the sink */
        while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) {
            pa_memchunk nchunk;

            /* make sure we get nbytes from the sink with render_full,
               otherwise we cannot mix with the uplink */
            pa_sink_render_full(u->sink, nbytes, &nchunk);
            pa_memblockq_push(u->sink_memblockq, &nchunk);
            pa_memblock_unref(nchunk.memblock);
        }
        pa_assert(tchunk.length == chunk->length);

        /* move the read pointer for sink memblockq */
        pa_memblockq_drop(u->sink_memblockq, tchunk.length);

        /* allocate target chunk */
        /* this could probably be done in-place, but having chunk as both
           the input and output creates issues with reference counts */
        target_chunk.index = 0;
        target_chunk.length = chunk->length;
        pa_assert(target_chunk.length == chunk->length);

        target_chunk.memblock = pa_memblock_new(o->source->core->mempool,
                                                target_chunk.length);
        pa_assert( target_chunk.memblock );

        /* get target pointer */
        target = (void*)((uint8_t*)pa_memblock_acquire(target_chunk.memblock)
                         + target_chunk.index);

        /* set-up mixing structure
           volume was taken care of in sink and source already */
        streams[0].chunk = *chunk;
        for(ch=0;ch<o->sample_spec.channels;ch++)
            streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
        streams[0].volume.channels = o->sample_spec.channels;

        streams[1].chunk = tchunk;
        for(ch=0;ch<o->sample_spec.channels;ch++)
            streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */
        streams[1].volume.channels = o->sample_spec.channels;

        /* do mixing */
        pa_mix(streams,                /* 2 streams to be mixed */
               2,
               target,                 /* put result in target chunk */
               chunk->length,          /* same length as input */
               (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */
               NULL,                   /* no volume information */
               FALSE);                 /* no mute */

        pa_memblock_release(target_chunk.memblock);
        pa_memblock_unref(tchunk.memblock); /* clean-up */

        /* forward the data to the virtual source */
        pa_source_post(u->source, &target_chunk);

        pa_memblock_unref(target_chunk.memblock); /* clean-up */

    } else {
        /* forward the data to the virtual source */
        pa_source_post(u->source, chunk);
    }


}
Ejemplo n.º 27
0
int main(int argc, char *argv[]) {
    pa_mempool *pool_a, *pool_b, *pool_c;
    unsigned id_a, id_b, id_c;
    pa_memexport *export_a, *export_b;
    pa_memimport *import_b, *import_c;
    pa_memblock *mb_a, *mb_b, *mb_c;
    int r, i;
    pa_memblock* blocks[5];
    uint32_t id, shm_id;
    size_t offset, size;
    char *x;

    const char txt[] = "This is a test!";

    pool_a = pa_mempool_new(1);
    pool_b = pa_mempool_new(1);
    pool_c = pa_mempool_new(1);

    pa_mempool_get_shm_id(pool_a, &id_a);
    pa_mempool_get_shm_id(pool_b, &id_b);
    pa_mempool_get_shm_id(pool_c, &id_c);

    pa_assert(pool_a && pool_b && pool_c);

    blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1);

    blocks[1] = pa_memblock_new(pool_a, sizeof(txt));
    x = pa_memblock_acquire(blocks[1]);
    snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt);
    pa_memblock_release(blocks[1]);

    blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt));
    x = pa_memblock_acquire(blocks[2]);
    snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt);
    pa_memblock_release(blocks[2]);

    blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt));
    blocks[4] = NULL;

    for (i = 0; blocks[i]; i++) {
        printf("Memory block %u\n", i);

        mb_a = blocks[i];
        pa_assert(mb_a);

        export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A");
        export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B");

        pa_assert(export_a && export_b);

        import_b = pa_memimport_new(pool_b, release_cb, (void*) "B");
        import_c = pa_memimport_new(pool_c, release_cb, (void*) "C");

        pa_assert(import_b && import_c);

        r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size);
        pa_assert(r >= 0);
        pa_assert(shm_id == id_a);

        printf("A: Memory block exported as %u\n", id);

        mb_b = pa_memimport_get(import_b, id, shm_id, offset, size);
        pa_assert(mb_b);
        r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size);
        pa_assert(r >= 0);
        pa_assert(shm_id == id_a || shm_id == id_b);
        pa_memblock_unref(mb_b);

        printf("B: Memory block exported as %u\n", id);

        mb_c = pa_memimport_get(import_c, id, shm_id, offset, size);
        pa_assert(mb_c);
        x = pa_memblock_acquire(mb_c);
        printf("1 data=%s\n", x);
        pa_memblock_release(mb_c);

        print_stats(pool_a, "A");
        print_stats(pool_b, "B");
        print_stats(pool_c, "C");

        pa_memexport_free(export_b);
        x = pa_memblock_acquire(mb_c);
        printf("2 data=%s\n", x);
        pa_memblock_release(mb_c);
        pa_memblock_unref(mb_c);

        pa_memimport_free(import_b);

        pa_memblock_unref(mb_a);

        pa_memimport_free(import_c);
        pa_memexport_free(export_a);
    }

    printf("vaccuuming...\n");

    pa_mempool_vacuum(pool_a);
    pa_mempool_vacuum(pool_b);
    pa_mempool_vacuum(pool_c);

    printf("vaccuuming done...\n");

    pa_mempool_free(pool_a);
    pa_mempool_free(pool_b);
    pa_mempool_free(pool_c);

    return 0;
}
Ejemplo n.º 28
0
static void thread_func(void *userdata) {
    struct userdata *u = userdata;
    int write_type = 0;
    pa_memchunk silence;
    uint32_t silence_overhead = 0;
    double silence_ratio = 0;

    pa_assert(u);

    pa_log_debug("Thread starting up");

    pa_thread_mq_install(&u->thread_mq);

    pa_smoother_set_time_offset(u->smoother, pa_rtclock_now());

    /* Create a chunk of memory that is our encoded silence sample. */
    pa_memchunk_reset(&silence);

    for (;;) {
        int ret;

        if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
            pa_sink_process_rewind(u->sink, 0);

        if (u->rtpoll_item) {
            struct pollfd *pollfd;
            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);

            /* Render some data and write it to the fifo */
            if (/*PA_SINK_IS_OPENED(u->sink->thread_info.state) && */pollfd->revents) {
                pa_usec_t usec;
                int64_t n;
                void *p;

                if (!silence.memblock) {
                    pa_memchunk silence_tmp;

                    pa_memchunk_reset(&silence_tmp);
                    silence_tmp.memblock = pa_memblock_new(u->core->mempool, 4096);
                    silence_tmp.length = 4096;
                    p = pa_memblock_acquire(silence_tmp.memblock);
                    memset(p, 0, 4096);
                    pa_memblock_release(silence_tmp.memblock);
                    pa_raop_client_encode_sample(u->raop, &silence_tmp, &silence);
                    pa_assert(0 == silence_tmp.length);
                    silence_overhead = silence_tmp.length - 4096;
                    silence_ratio = silence_tmp.length / 4096;
                    pa_memblock_unref(silence_tmp.memblock);
                }

                for (;;) {
                    ssize_t l;

                    if (u->encoded_memchunk.length <= 0) {
                        if (u->encoded_memchunk.memblock)
                            pa_memblock_unref(u->encoded_memchunk.memblock);
                        if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
                            size_t rl;

                            /* We render real data */
                            if (u->raw_memchunk.length <= 0) {
                                if (u->raw_memchunk.memblock)
                                    pa_memblock_unref(u->raw_memchunk.memblock);
                                pa_memchunk_reset(&u->raw_memchunk);

                                /* Grab unencoded data */
                                pa_sink_render(u->sink, u->block_size, &u->raw_memchunk);
                            }
                            pa_assert(u->raw_memchunk.length > 0);

                            /* Encode it */
                            rl = u->raw_memchunk.length;
                            u->encoding_overhead += u->next_encoding_overhead;
                            pa_raop_client_encode_sample(u->raop, &u->raw_memchunk, &u->encoded_memchunk);
                            u->next_encoding_overhead = (u->encoded_memchunk.length - (rl - u->raw_memchunk.length));
                            u->encoding_ratio = u->encoded_memchunk.length / (rl - u->raw_memchunk.length);
                        } else {
                            /* We render some silence into our memchunk */
                            memcpy(&u->encoded_memchunk, &silence, sizeof(pa_memchunk));
                            pa_memblock_ref(silence.memblock);

                            /* Calculate/store some values to be used with the smoother */
                            u->next_encoding_overhead = silence_overhead;
                            u->encoding_ratio = silence_ratio;
                        }
                    }
                    pa_assert(u->encoded_memchunk.length > 0);

                    p = pa_memblock_acquire(u->encoded_memchunk.memblock);
                    l = pa_write(u->fd, (uint8_t*) p + u->encoded_memchunk.index, u->encoded_memchunk.length, &write_type);
                    pa_memblock_release(u->encoded_memchunk.memblock);

                    pa_assert(l != 0);

                    if (l < 0) {

                        if (errno == EINTR)
                            continue;
                        else if (errno == EAGAIN) {

                            /* OK, we filled all socket buffers up
                             * now. */
                            goto filled_up;

                        } else {
                            pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
                            goto fail;
                        }

                    } else {
                        u->offset += l;

                        u->encoded_memchunk.index += l;
                        u->encoded_memchunk.length -= l;

                        pollfd->revents = 0;

                        if (u->encoded_memchunk.length > 0) {
                            /* we've completely written the encoded data, so update our overhead */
                            u->encoding_overhead += u->next_encoding_overhead;

                            /* OK, we wrote less that we asked for,
                             * hence we can assume that the socket
                             * buffers are full now */
                            goto filled_up;
                        }
                    }
                }

filled_up:

                /* At this spot we know that the socket buffers are
                 * fully filled up. This is the best time to estimate
                 * the playback position of the server */

                n = u->offset - u->encoding_overhead;

#ifdef SIOCOUTQ
                {
                    int l;
                    if (ioctl(u->fd, SIOCOUTQ, &l) >= 0 && l > 0)
                        n -= (l / u->encoding_ratio);
                }
#endif

                usec = pa_bytes_to_usec(n, &u->sink->sample_spec);

                if (usec > u->latency)
                    usec -= u->latency;
                else
                    usec = 0;

                pa_smoother_put(u->smoother, pa_rtclock_now(), usec);
            }

            /* Hmm, nothing to do. Let's sleep */
            pollfd->events = POLLOUT; /*PA_SINK_IS_OPENED(u->sink->thread_info.state)  ? POLLOUT : 0;*/
        }

        if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
            goto fail;

        if (ret == 0)
            goto finish;

        if (u->rtpoll_item) {
            struct pollfd* pollfd;

            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);

            if (pollfd->revents & ~POLLOUT) {
                if (u->sink->thread_info.state != PA_SINK_SUSPENDED) {
                    pa_log("FIFO shutdown.");
                    goto fail;
                }

                /* We expect this to happen on occasion if we are not sending data.
                   It's perfectly natural and normal and natural */
                if (u->rtpoll_item)
                    pa_rtpoll_item_free(u->rtpoll_item);
                u->rtpoll_item = NULL;
            }
        }
    }

fail:
    /* If this was no regular exit from the loop we have to continue
     * processing messages until we received PA_MESSAGE_SHUTDOWN */
    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);

finish:
    if (silence.memblock)
        pa_memblock_unref(silence.memblock);
    pa_log_debug("Thread shutting down");
}
Ejemplo n.º 29
0
static void thread_func(void *userdata) {
    struct userdata *u = userdata;
    int read_type = 0;

    pa_assert(u);

    pa_log_debug("Thread starting up");

    pa_thread_mq_install(&u->thread_mq);

    for (;;) {
        int ret;
        struct pollfd *pollfd;

        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);

        /* Try to read some data and pass it on to the source driver */
        if (u->source->thread_info.state == PA_SOURCE_RUNNING && pollfd->revents) {
            ssize_t l;
            void *p;

            if (!u->memchunk.memblock) {
                u->memchunk.memblock = pa_memblock_new(u->core->mempool, pa_pipe_buf(u->fd));
                u->memchunk.index = u->memchunk.length = 0;
            }

            pa_assert(pa_memblock_get_length(u->memchunk.memblock) > u->memchunk.index);

            p = pa_memblock_acquire(u->memchunk.memblock);
            l = pa_read(u->fd, (uint8_t*) p + u->memchunk.index, pa_memblock_get_length(u->memchunk.memblock) - u->memchunk.index, &read_type);
            pa_memblock_release(u->memchunk.memblock);

            pa_assert(l != 0); /* EOF cannot happen, since we opened the fifo for both reading and writing */

            if (l < 0) {

                if (errno == EINTR)
                    continue;
                else if (errno != EAGAIN) {
                    pa_log("Failed to read data from FIFO: %s", pa_cstrerror(errno));
                    goto fail;
                }

            } else {

                u->memchunk.length = (size_t) l;
                pa_source_post(u->source, &u->memchunk);
                u->memchunk.index += (size_t) l;

                if (u->memchunk.index >= pa_memblock_get_length(u->memchunk.memblock)) {
                    pa_memblock_unref(u->memchunk.memblock);
                    pa_memchunk_reset(&u->memchunk);
                }

                pollfd->revents = 0;
            }
        }

        /* Hmm, nothing to do. Let's sleep */
        pollfd->events = (short) (u->source->thread_info.state == PA_SOURCE_RUNNING ? POLLIN : 0);

        if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
            goto fail;

        if (ret == 0)
            goto finish;

        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);

        if (pollfd->revents & ~POLLIN) {
            pa_log("FIFO shutdown.");
            goto fail;
        }
    }

fail:
    /* If this was no regular exit from the loop we have to continue
     * processing messages until we received PA_MESSAGE_SHUTDOWN */
    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);

finish:
    pa_log_debug("Thread shutting down");
}
Ejemplo n.º 30
0
static void compare_block(const pa_sample_spec *ss, const pa_memchunk *chunk, int iter) {
    void *d;
    unsigned i;

    d = pa_memblock_acquire(chunk->memblock);

    switch (ss->format) {
    case PA_SAMPLE_U8: {
        const uint8_t *v = u8_result[iter];
        uint8_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_ALAW: {
        const uint8_t *v = alaw_result[iter];
        uint8_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_ULAW: {
        const uint8_t *v = ulaw_result[iter];
        uint8_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S16LE: {
        const uint16_t *v = s16le_result[iter];
        uint16_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S16BE: {
        const uint16_t *v = s16be_result[iter];
        uint16_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_FLOAT32LE: {
        const float *v = float32le_result[iter];
        float *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            float uu = ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u);
            fail_unless(fabs(uu - *v) <= 1e-6, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_FLOAT32BE: {
        const float *v = float32be_result[iter];
        float *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            float uu = ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u);
            fail_unless(fabs(uu - *v) <= 1e-6, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S32LE: {
        const uint32_t *v = s32le_result[iter];
        uint32_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S32BE: {
        const uint32_t *v = s32be_result[iter];
        uint32_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S24_32LE: {
        const uint32_t *v = s24_32le_result[iter];
        uint32_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S24_32BE: {
        const uint32_t *v = s24_32be_result[iter];
        uint32_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            ++u;
            ++v;
        }
        break;
    }

    case PA_SAMPLE_S24LE: {
        const uint8_t *v = s24le_result[iter];
        uint8_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            fail_unless(*(u+1) == *(v+1), NULL);
            fail_unless(*(u+2) == *(v+2), NULL);

            u += 3;
            v += 3;
        }
        break;
    }

    case PA_SAMPLE_S24BE: {
        const uint8_t *v = s24be_result[iter];
        uint8_t *u = d;

        for (i = 0; i < chunk->length / pa_frame_size(ss); i++) {
            fail_unless(*u == *v, NULL);
            fail_unless(*(u+1) == *(v+1), NULL);
            fail_unless(*(u+2) == *(v+2), NULL);

            u += 3;
            v += 3;
        }
        break;
    }

    default:
        pa_assert_not_reached();
    }

    pa_memblock_release(chunk->memblock);
}