Esempio n. 1
0
pa_raop_packet_buffer *pa_raop_packet_buffer_new(pa_mempool *mempool, const size_t size) {
    pa_raop_packet_buffer *pb = pa_xnew0(pa_raop_packet_buffer, 1);

    pa_assert(mempool);
    pa_assert(size > 0);

    pb->count = 0;
    pb->size = size;
    pb->mempool = mempool;
    pb->packets = pa_xnew0(pa_memchunk, size);
    pb->seq = pb->pos = 0;

    return pb;
}
Esempio n. 2
0
pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_discovery *y, bool enable_hs_role) {
    pa_bluetooth_backend *backend;
    DBusError err;

    pa_log_debug("Bluetooth Headset Backend API support using the native backend");

    backend = pa_xnew0(pa_bluetooth_backend, 1);
    backend->core = c;

    dbus_error_init(&err);
    if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) {
        pa_log("Failed to get D-Bus connection: %s", err.message);
        dbus_error_free(&err);
        pa_xfree(backend);
        return NULL;
    }

    backend->discovery = y;
    backend->enable_hs_role = enable_hs_role;

    if (enable_hs_role)
       profile_init(backend, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY);
    profile_init(backend, PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT);

    return backend;
}
Esempio n. 3
0
pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) {
    char cname[256];
    pa_cli *c;
    pa_client_new_data data;
    pa_client *client;

    pa_assert(io);

    pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));

    pa_client_new_data_init(&data);
    data.driver = __FILE__;
    data.module = m;
    pa_proplist_sets(data.proplist, PA_PROP_APPLICATION_NAME, cname);
    client = pa_client_new(core, &data);
    pa_client_new_data_done(&data);

    if (!client)
        return NULL;

    c = pa_xnew0(pa_cli, 1);
    c->core = core;
    c->client = client;
    pa_assert_se(c->line = pa_ioline_new(io));

    c->client->kill = client_kill;
    c->client->userdata = c;

    pa_ioline_set_callback(c->line, line_callback, c);

    return c;
}
Esempio n. 4
0
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
    pa_context *c;

    pa_assert(mainloop);

    if (pa_detect_fork())
        return NULL;

    pa_init_i18n();

    c = pa_xnew0(pa_context, 1);
    PA_REFCNT_INIT(c);

    c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();

    if (name)
        pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);

#ifdef HAVE_DBUS
    c->system_bus = c->session_bus = NULL;
#endif
    c->mainloop = mainloop;
    c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->client_index = PA_INVALID_INDEX;
    c->use_rtclock = pa_mainloop_is_our_api(mainloop);

    PA_LLIST_HEAD_INIT(pa_stream, c->streams);
    PA_LLIST_HEAD_INIT(pa_operation, c->operations);

    c->error = PA_OK;
    c->state = PA_CONTEXT_UNCONNECTED;

    reset_callbacks(c);

#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
    pa_check_signal_is_blocked(SIGPIPE);
#endif
#endif

    c->conf = pa_client_conf_new();
    pa_client_conf_load(c->conf, true, true);

    c->srb_template.readfd = -1;
    c->srb_template.writefd = -1;

    if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {

        if (!c->conf->disable_shm)
            c->mempool = pa_mempool_new(false, c->conf->shm_size);

        if (!c->mempool) {
            context_free(c);
            return NULL;
        }
    }

    return c;
}
Esempio n. 5
0
pa_inotify *pa_inotify_start(const char *filename, void *userdata, pa_inotify_cb cb, pa_core *core) {

    pa_inotify *i = pa_xnew0(pa_inotify, 1);
    pa_assert(i);

    i->core = core;
    pa_core_ref(core);

    i->filename = pa_xstrdup(filename);
    i->callback_data = userdata;
    i->callback = cb;
    i->fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);

    if (i->fd < 0) {
        pa_log("inotify_init1() failed: %s", pa_cstrerror(errno));
        pa_inotify_stop(i);
        return NULL;
    }

    if (inotify_add_watch(i->fd, filename, IN_DELETE_SELF|IN_MOVE_SELF) < 0) {
        pa_log("inotify_add_watch() failed: %s", pa_cstrerror(errno));
        pa_inotify_stop(i);
        return NULL;
    }

    pa_assert_se(i->io_event = core->mainloop->io_new(core->mainloop, i->fd, PA_IO_EVENT_INPUT, inotify_cb, i));

    return i;
}
Esempio n. 6
0
AEC* AEC_init(int RATE, int have_vector)
{
  AEC *a = pa_xnew0(AEC, 1);
  a->j = NLMS_EXT;
  AEC_setambient(a, NoiseFloor);
  a->dfast = a->dslow = M75dB_PCM;
  a->xfast = a->xslow = M80dB_PCM;
  a->gain = 1.0f;
  a->Fx = IIR1_init(2000.0f/RATE);
  a->Fe = IIR1_init(2000.0f/RATE);
  a->cutoff = FIR_HP_300Hz_init();
  a->acMic = IIR_HP_init();
  a->acSpk = IIR_HP_init();

  a->aes_y2 = M0dB;

  a->fdwdisplay = -1;

  if (have_vector) {
      /* Get a 16-byte aligned location */
      a->w = (REAL *) (((uintptr_t) a->w_arr) - (((uintptr_t) a->w_arr) % 16) + 16);
      a->dotp = dotp_sse;
  } else {
      /* We don't care about alignment, just use the array as-is */
      a->w = a->w_arr;
      a->dotp = dotp;
  }

  return a;
}
Esempio n. 7
0
pa_dynarray* pa_dynarray_new(pa_free_cb_t free_cb) {
    pa_dynarray *array;

    array = pa_xnew0(pa_dynarray, 1);
    array->free_cb = free_cb;

    return array;
}
Esempio n. 8
0
pa_simple_options* pa_simple_options_new(void) {
    pa_simple_options *o;

    o = pa_xnew0(pa_simple_options, 1);
    PA_REFCNT_INIT(o);

    o->record = FALSE;
    o->playback = TRUE;

    return o;
}
pa_simple_options* pa_simple_options_new(void) {
    pa_simple_options *o;

    o = pa_xnew0(pa_simple_options, 1);
    PA_REFCNT_INIT(o);

    o->record = false;
    o->playback = true;

    return o;
}
/* parse sidetone configuration file parameters */
sidetone_args* sidetone_args_new(const char *args) {

    pa_modargs* ma = NULL;
    sidetone_args* st_args = NULL;
    int count = 0 ;

    st_args = pa_xnew0(sidetone_args, 1);
    st_args->steps=pa_xnew0(struct mv_volume_steps, 1);
    ma = pa_modargs_new(args, valid_modargs);
    if(!ma) {
        pa_log_error("Failed to parse module arguments");
        goto fail;
    }

    st_args->modargs = ma;

    if(!(st_args->mixer = pa_modargs_get_value(ma, "mixer", NULL))) {
        pa_log_error("Failed to read mixer name");
        goto fail;
    }


    if(!(st_args->control_element = pa_modargs_get_value(ma, "control_element", NULL))) {
        pa_log_error("Failed to parse control element");
        goto fail;
    }


    if( !(st_args->master_sink = pa_modargs_get_value(ma, "master_sink", NULL))) {
        pa_log_error("Failed to parse master sink name");
        goto fail;
    }


    if(!(st_args->mainvolume = pa_modargs_get_value(ma, "mainvolume", NULL))) {
        pa_log_error("failed to search volume string");
    }

    count = parse_volume_steps(st_args->steps, st_args->mainvolume);
    if (count < 1) {
        pa_log_error("failed to parse call steps; %s", st_args->mainvolume);
        goto fail;
    }

    return st_args;

fail:

    sidetone_args_free(st_args);

    return NULL;
}
Esempio n. 11
0
pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
    pa_socket_server *s;

    pa_assert(m);
    pa_assert(fd >= 0);

    s = pa_xnew0(pa_socket_server, 1);
    PA_REFCNT_INIT(s);
    s->fd = fd;
    s->mainloop = m;

    pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));

    s->type = SOCKET_SERVER_GENERIC;

    return s;
}
Esempio n. 12
0
pa_memblockq* pa_memblockq_new(
        const char *name,
        int64_t idx,
        size_t maxlength,
        size_t tlength,
        const pa_sample_spec *sample_spec,
        size_t prebuf,
        size_t minreq,
        size_t maxrewind,
        pa_memchunk *silence) {

    pa_memblockq* bq;

    pa_assert(sample_spec);
    pa_assert(name);

    bq = pa_xnew0(pa_memblockq, 1);
    bq->name = pa_xstrdup(name);

    bq->sample_spec = *sample_spec;
    bq->base = pa_frame_size(sample_spec);
    bq->read_index = bq->write_index = idx;

    pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
                 (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) bq->base, (unsigned long) prebuf, (unsigned long) minreq, (unsigned long) maxrewind);

    bq->in_prebuf = true;

    pa_memblockq_set_maxlength(bq, maxlength);
    pa_memblockq_set_tlength(bq, tlength);
    pa_memblockq_set_minreq(bq, minreq);
    pa_memblockq_set_prebuf(bq, prebuf);
    pa_memblockq_set_maxrewind(bq, maxrewind);

    pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
                 (unsigned long) bq->maxlength, (unsigned long) bq->tlength, (unsigned long) bq->base, (unsigned long) bq->prebuf, (unsigned long) bq->minreq, (unsigned long) bq->maxrewind);

    if (silence) {
        bq->silence = *silence;
        pa_memblock_ref(bq->silence.memblock);
    }

    bq->mcalign = pa_mcalign_new(bq->base);

    return bq;
}
Esempio n. 13
0
/* Should be called locked */
static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) {
    pa_memimport_segment* seg;

    if (pa_hashmap_size(i->segments) >= PA_MEMIMPORT_SEGMENTS_MAX)
        return NULL;

    seg = pa_xnew0(pa_memimport_segment, 1);

    if (pa_shm_attach_ro(&seg->memory, shm_id) < 0) {
        pa_xfree(seg);
        return NULL;
    }

    seg->import = i;
    seg->trap = pa_memtrap_add(seg->memory.ptr, seg->memory.size);

    pa_hashmap_put(i->segments, PA_UINT32_TO_PTR(seg->memory.id), seg);
    return seg;
}
Esempio n. 14
0
pa_threaded_mainloop *pa_threaded_mainloop_new(void) {
    pa_threaded_mainloop *m;

    pa_init_i18n();

    m = pa_xnew0(pa_threaded_mainloop, 1);

    if (!(m->real_mainloop = pa_mainloop_new())) {
        pa_xfree(m);
        return NULL;
    }

    m->mutex = pa_mutex_new(true, true);
    m->cond = pa_cond_new();
    m->accept_cond = pa_cond_new();

    pa_mainloop_set_poll_func(m->real_mainloop, poll_func, m->mutex);

    return m;
}
Esempio n. 15
0
pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
    pa_iochannel *io;

    pa_assert(m);
    pa_assert(ifd >= 0 || ofd >= 0);

    io = pa_xnew0(pa_iochannel, 1);
    io->ifd = ifd;
    io->ofd = ofd;
    io->mainloop = m;

    if (io->ifd >= 0)
        pa_make_fd_nonblock(io->ifd);

    if (io->ofd >= 0 && io->ofd != io->ifd)
        pa_make_fd_nonblock(io->ofd);

    enable_events(io);
    return io;
}
Esempio n. 16
0
pa_rtsp_client* pa_rtsp_client_new(pa_mainloop_api *mainloop, const char* hostname, uint16_t port, const char* useragent) {
    pa_rtsp_client *c;

    pa_assert(mainloop);
    pa_assert(hostname);
    pa_assert(port > 0);

    c = pa_xnew0(pa_rtsp_client, 1);
    c->mainloop = mainloop;
    c->hostname = pa_xstrdup(hostname);
    c->port = port;
    c->headers = pa_headerlist_new();

    if (useragent)
        c->useragent = useragent;
    else
        c->useragent = "PulseAudio RTSP Client";

    return c;
}
Esempio n. 17
0
pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name) {
    pa_reserve_wrapper *r;
    int k;
    char *t;
#ifdef HAVE_DBUS
    DBusError error;

    dbus_error_init(&error);
#endif

    pa_assert(c);
    pa_assert(device_name);

    t = pa_sprintf_malloc("reserve-wrapper@%s", device_name);

    if ((r = pa_shared_get(c, t))) {
        pa_xfree(t);

        pa_assert(PA_REFCNT_VALUE(r) >= 1);
        PA_REFCNT_INC(r);

        return r;
    }

    r = pa_xnew0(pa_reserve_wrapper, 1);
    PA_REFCNT_INIT(r);
    r->core = c;
    pa_hook_init(&r->hook, r);
    r->shared_name = t;

    pa_assert_se(pa_shared_set(c, r->shared_name, r) >= 0);

#ifdef HAVE_DBUS
    if (!(r->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);

        /* We don't treat this as error here because we want allow PA
         * to run even when no session bus is available. */
        return r;
    }

    if ((k = rd_acquire(
                 &r->device,
                 pa_dbus_connection_get(r->connection),
                 device_name,
                 _("PulseAudio Sound Server"),
                 0,
                 request_cb,
                 NULL)) < 0) {

        if (k == -EBUSY) {
            pa_log_debug("Device '%s' already locked.", device_name);
            goto fail;
        } else {
            pa_log_debug("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));
            return r;
        }
    }

    pa_log_debug("Successfully acquired reservation lock on device '%s'", device_name);

    rd_set_userdata(r->device, r);

    return r;
fail:
    dbus_error_free(&error);

    reserve_wrapper_free(r);

    return NULL;
#else
    return r;
#endif
}
Esempio n. 18
0
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
    pa_context *c;
    pa_mem_type_t type;

    pa_assert(mainloop);

    if (pa_detect_fork())
        return NULL;

    pa_init_i18n();

    c = pa_xnew0(pa_context, 1);
    PA_REFCNT_INIT(c);

    c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();

    if (name)
        pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);

#ifdef HAVE_DBUS
    c->system_bus = c->session_bus = NULL;
#endif
    c->mainloop = mainloop;
    c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->client_index = PA_INVALID_INDEX;
    c->use_rtclock = pa_mainloop_is_our_api(mainloop);

    PA_LLIST_HEAD_INIT(pa_stream, c->streams);
    PA_LLIST_HEAD_INIT(pa_operation, c->operations);

    c->error = PA_OK;
    c->state = PA_CONTEXT_UNCONNECTED;

    reset_callbacks(c);

#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
    pa_check_signal_is_blocked(SIGPIPE);
#endif
#endif

    c->conf = pa_client_conf_new();
    pa_client_conf_load(c->conf, true, true);

    c->srb_template.readfd = -1;
    c->srb_template.writefd = -1;

    c->memfd_on_local = (!c->conf->disable_memfd && pa_memfd_is_locally_supported());

    type = (c->conf->disable_shm) ? PA_MEM_TYPE_PRIVATE :
           ((!c->memfd_on_local) ?
               PA_MEM_TYPE_SHARED_POSIX : PA_MEM_TYPE_SHARED_MEMFD);

    if (!(c->mempool = pa_mempool_new(type, c->conf->shm_size, true))) {

        if (!c->conf->disable_shm) {
            pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal private one.");
            c->mempool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, c->conf->shm_size, true);
        }

        if (!c->mempool) {
            context_free(c);
            return NULL;
        }
    }

    return c;
}
Esempio n. 19
0
static void ext_device_manager_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
    pa_operation *o = userdata;
    int eol = 1;

    pa_assert(pd);
    pa_assert(o);
    pa_assert(PA_REFCNT_VALUE(o) >= 1);

    if (!o->context)
        goto finish;

    if (command != PA_COMMAND_REPLY) {
        if (pa_context_handle_error(o->context, command, t, false) < 0)
            goto finish;

        eol = -1;
    } else {

        while (!pa_tagstruct_eof(t)) {
            pa_ext_device_manager_info i;

            memset(&i, 0, sizeof(i));

            if (pa_tagstruct_gets(t, &i.name) < 0 ||
                pa_tagstruct_gets(t, &i.description) < 0 ||
                pa_tagstruct_gets(t, &i.icon) < 0 ||
                pa_tagstruct_getu32(t, &i.index) < 0 ||
                pa_tagstruct_getu32(t, &i.n_role_priorities) < 0) {

                pa_context_fail(o->context, PA_ERR_PROTOCOL);
                goto finish;
            }

            if (i.n_role_priorities > 0) {
                uint32_t j;
                i.role_priorities = pa_xnew0(pa_ext_device_manager_role_priority_info, i.n_role_priorities+1);

                for (j = 0; j < i.n_role_priorities; j++) {

                    if (pa_tagstruct_gets(t, &i.role_priorities[j].role) < 0 ||
                        pa_tagstruct_getu32(t, &i.role_priorities[j].priority) < 0) {

                        pa_context_fail(o->context, PA_ERR_PROTOCOL);
                        pa_xfree(i.role_priorities);
                        goto finish;
                    }
                }

                /* Terminate with an extra NULL entry, just to make sure */
                i.role_priorities[j].role = NULL;
                i.role_priorities[j].priority = 0;
            }

            if (o->callback) {
                pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
                cb(o->context, &i, 0, o->userdata);
            }

            pa_xfree(i.role_priorities);
        }
    }

    if (o->callback) {
        pa_ext_device_manager_read_cb_t cb = (pa_ext_device_manager_read_cb_t) o->callback;
        cb(o->context, NULL, eol, o->userdata);
    }

finish:
    pa_operation_done(o);
    pa_operation_unref(o);
}
Esempio n. 20
0
pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const char *device_name) {
    pa_reserve_monitor_wrapper *w;
    int k;
    char *t;
#ifdef HAVE_DBUS
    DBusError error;

    dbus_error_init(&error);
#endif

    pa_assert(c);
    pa_assert(device_name);

    t = pa_sprintf_malloc("reserve-monitor-wrapper@%s", device_name);

    if ((w = pa_shared_get(c, t))) {
        pa_xfree(t);

        pa_assert(PA_REFCNT_VALUE(w) >= 1);
        PA_REFCNT_INC(w);

        return w;
    }

    w = pa_xnew0(pa_reserve_monitor_wrapper, 1);
    PA_REFCNT_INIT(w);
    w->core = c;
    pa_hook_init(&w->hook, w);
    w->shared_name = t;

    pa_assert_se(pa_shared_set(c, w->shared_name, w) >= 0);

#ifdef HAVE_DBUS
    if (!(w->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);

        /* We don't treat this as error here because we want allow PA
         * to run even when no session bus is available. */
        return w;
    }

    if ((k = rm_watch(
                 &w->monitor,
                 pa_dbus_connection_get(w->connection),
                 device_name,
                 change_cb,
                 NULL)) < 0) {

        pa_log_debug("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k));
        goto fail;
    }

    pa_log_debug("Successfully create reservation lock monitor for device '%s'", device_name);

    rm_set_userdata(w->monitor, w);
    return w;

fail:
    dbus_error_free(&error);

    reserve_monitor_wrapper_free(w);

    return NULL;
#else
    return w;
#endif
}
Esempio n. 21
0
pa_simple* pa_simple_new(
        const char *server,
        const char *name,
        pa_stream_direction_t dir,
        const char *dev,
        const char *stream_name,
        const pa_sample_spec *ss,
        const pa_channel_map *map,
        const pa_buffer_attr *attr,
        int *rerror) {

    pa_simple *p;
    int error = PA_ERR_INTERNAL, r;

    CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL);
    CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL);
    CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL);
    CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL);
    CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL)

    p = pa_xnew0(pa_simple, 1);
    p->direction = dir;

    if (!(p->mainloop = pa_threaded_mainloop_new()))
        goto fail;

    if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
        goto fail;

    pa_context_set_state_callback(p->context, context_state_cb, p);

    if (pa_context_connect(p->context, server, 0, NULL) < 0) {
        error = pa_context_errno(p->context);
        goto fail;
    }

    pa_threaded_mainloop_lock(p->mainloop);

    if (pa_threaded_mainloop_start(p->mainloop) < 0)
        goto unlock_and_fail;

    for (;;) {
        pa_context_state_t state;

        state = pa_context_get_state(p->context);

        if (state == PA_CONTEXT_READY)
            break;

        if (!PA_CONTEXT_IS_GOOD(state)) {
            error = pa_context_errno(p->context);
            goto unlock_and_fail;
        }

        /* Wait until the context is ready */
        pa_threaded_mainloop_wait(p->mainloop);
    }

    if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) {
        error = pa_context_errno(p->context);
        goto unlock_and_fail;
    }

    pa_stream_set_state_callback(p->stream, stream_state_cb, p);
    pa_stream_set_read_callback(p->stream, stream_request_cb, p);
    pa_stream_set_write_callback(p->stream, stream_request_cb, p);
    pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);

    if (dir == PA_STREAM_PLAYBACK)
        r = pa_stream_connect_playback(p->stream, dev, attr,
                                       PA_STREAM_INTERPOLATE_TIMING
                                       |PA_STREAM_ADJUST_LATENCY
                                       |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
    else
        r = pa_stream_connect_record(p->stream, dev, attr,
                                     PA_STREAM_INTERPOLATE_TIMING
                                     |PA_STREAM_ADJUST_LATENCY
                                     |PA_STREAM_AUTO_TIMING_UPDATE);

    if (r < 0) {
        error = pa_context_errno(p->context);
        goto unlock_and_fail;
    }

    for (;;) {
        pa_stream_state_t state;

        state = pa_stream_get_state(p->stream);

        if (state == PA_STREAM_READY)
            break;

        if (!PA_STREAM_IS_GOOD(state)) {
            error = pa_context_errno(p->context);
            goto unlock_and_fail;
        }

        /* Wait until the stream is ready */
        pa_threaded_mainloop_wait(p->mainloop);
    }

    pa_threaded_mainloop_unlock(p->mainloop);

    return p;

unlock_and_fail:
    pa_threaded_mainloop_unlock(p->mainloop);

fail:
    if (rerror)
        *rerror = error;
    pa_simple_free(p);
    return NULL;
}