Ejemplo n.º 1
0
pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) {
    pa_client *c;

    pa_core_assert_ref(core);
    pa_assert(data);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
        return NULL;

    c = pa_xnew(pa_client, 1);
    c->core = core;
    c->proplist = pa_proplist_copy(data->proplist);
    c->driver = pa_xstrdup(pa_path_get_filename(data->driver));
    c->module = data->module;

    c->sink_inputs = pa_idxset_new(NULL, NULL);
    c->source_outputs = pa_idxset_new(NULL, NULL);

    c->userdata = NULL;
    c->kill = NULL;
    c->send_event = NULL;

    pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);

    pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_PUT], c);

    pa_core_check_idle(core);

    return c;
}
Ejemplo n.º 2
0
/* Called from main context */
void pa_source_output_unlink(pa_source_output*o) {
    pa_bool_t linked;
    pa_assert(o);
    pa_assert_ctl_context();

    /* See pa_sink_unlink() for a couple of comments how this function
     * works */

    pa_source_output_ref(o);

    linked = PA_SOURCE_OUTPUT_IS_LINKED(o->state);

    if (linked)
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);

    if (o->direct_on_input)
        pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);

    pa_idxset_remove_by_data(o->core->source_outputs, o, NULL);

    if (o->source)
        if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
            pa_source_output_unref(o);

    if (o->client)
        pa_idxset_remove_by_data(o->client->source_outputs, o, NULL);

    update_n_corked(o, PA_SOURCE_OUTPUT_UNLINKED);
    o->state = PA_SOURCE_OUTPUT_UNLINKED;

    if (linked && o->source)
        if (o->source->asyncmsgq)
            pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);

    reset_callbacks(o);

    if (linked) {
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
    }

    if (o->source) {
        pa_source_update_status(o->source);
        o->source = NULL;
    }

    pa_core_maybe_vacuum(o->core);

    pa_source_output_unref(o);
}
Ejemplo n.º 3
0
/* Called from main context */
void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) {
    pa_proplist *pl = NULL;
    pa_source_output_send_event_hook_data hook_data;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert(event);

    if (!o->send_event)
        return;

    if (!data)
        data = pl = pa_proplist_new();

    hook_data.source_output = o;
    hook_data.data = data;
    hook_data.event = event;

    if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT], &hook_data) < 0)
        goto finish;

    o->send_event(o, event, data);

finish:
    if (pl)
        pa_proplist_free(pl);
}
Ejemplo n.º 4
0
/* Called from main context */
int pa_source_output_start_move(pa_source_output *o) {
    pa_source *origin;
    int r;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
    pa_assert(o->source);

    if (!pa_source_output_may_move(o))
        return -PA_ERR_NOTSUPPORTED;

    if ((r = pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], o)) < 0)
        return r;

    origin = o->source;

    pa_idxset_remove_by_data(o->source->outputs, o, NULL);

    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
        pa_assert_se(origin->n_corked-- >= 1);

    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL) == 0);

    pa_source_update_status(o->source);
    o->source = NULL;

    pa_source_output_unref(o);

    return 0;
}
Ejemplo n.º 5
0
void pa_client_send_event(pa_client *c, const char *event, pa_proplist *data) {
    pa_proplist *pl = NULL;
    pa_client_send_event_hook_data hook_data;

    pa_assert(c);
    pa_assert(event);

    if (!c->send_event)
        return;

    if (!data)
        data = pl = pa_proplist_new();

    hook_data.client = c;
    hook_data.data = data;
    hook_data.event = event;

    if (pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_SEND_EVENT], &hook_data) < 0)
        goto finish;

    c->send_event(c, event, data);

finish:

    if (pl)
        pa_proplist_free(pl);
}
Ejemplo n.º 6
0
void pa_client_free(pa_client *c) {
    pa_core *core;

    pa_assert(c);
    pa_assert(c->core);

    core = c->core;

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK], c);

    pa_idxset_remove_by_data(c->core->clients, c, NULL);

    pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);

    pa_assert(pa_idxset_isempty(c->sink_inputs));
    pa_idxset_free(c->sink_inputs, NULL);
    pa_assert(pa_idxset_isempty(c->source_outputs));
    pa_idxset_free(c->source_outputs, NULL);

    pa_proplist_free(c->proplist);
    pa_xfree(c->driver);
    pa_xfree(c);

    pa_core_check_idle(core);
}
Ejemplo n.º 7
0
static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
    pa_bluetooth_transport *t = userdata;

    pa_assert(io);
    pa_assert(t);

    if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
        pa_log_info("Lost RFCOMM connection.");
        goto fail;
    }

    if (events & PA_IO_EVENT_INPUT) {
        char buf[512];
        ssize_t len;
        int gain;

        len = read(fd, buf, 511);
        buf[len] = 0;
        pa_log_debug("RFCOMM << %s", buf);

        if (sscanf(buf, "AT+VGS=%d", &gain) == 1) {
          t->speaker_gain = gain;
          pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);

        } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1) {
          t->microphone_gain = gain;
          pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);
        }

        pa_log_debug("RFCOMM >> OK");

        len = write(fd, "\r\nOK\r\n", 6);

        /* we ignore any errors, it's not critical and real errors should
         * be caught with the HANGUP and ERROR events handled above */
        if (len < 0)
            pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
    }

    return;

fail:
    pa_bluetooth_transport_unlink(t);
    pa_bluetooth_transport_free(t);
    return;
}
Ejemplo n.º 8
0
void pa_client_update_proplist(pa_client *c, pa_update_mode_t mode, pa_proplist *p) {
    pa_assert(c);

    if (p)
        pa_proplist_update(c->proplist, mode, p);

    pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], c);
    pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
}
Ejemplo n.º 9
0
/* Called from main thread */
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();

    if (p)
        pa_proplist_update(o->proplist, mode, p);

    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
    }
}
Ejemplo n.º 10
0
/* Called from main context */
void pa_source_output_fail_move(pa_source_output *o) {

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
    pa_assert(!o->source);

    /* Check if someone wants this source output? */
    if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP)
        return;

    if (o->moving)
        o->moving(o, NULL);

    pa_source_output_kill(o);
}
Ejemplo n.º 11
0
static int request_cb(rd_device *d, int forced) {
    pa_reserve_wrapper *r;
    int k;

    pa_assert(d);
    pa_assert_se(r = rd_get_userdata(d));
    pa_assert(PA_REFCNT_VALUE(r) >= 1);

    PA_REFCNT_INC(r);

    k = pa_hook_fire(&r->hook, PA_INT_TO_PTR(forced));
    pa_log_debug("Device unlock of %s has been requested and %s.", r->shared_name, k < 0 ? "failed" : "succeeded");

    pa_reserve_wrapper_unref(r);

    return k < 0 ? -1 : 1;
}
Ejemplo n.º 12
0
static void change_cb(rm_monitor *m) {
    pa_reserve_monitor_wrapper *w;
    int k;

    pa_assert(m);
    pa_assert_se(w = rm_get_userdata(m));
    pa_assert(PA_REFCNT_VALUE(w) >= 1);

    PA_REFCNT_INC(w);

    if ((k = rm_busy(w->monitor)) < 0)
        return;

    pa_hook_fire(&w->hook, PA_INT_TO_PTR(!!k));
    pa_log_debug("Device lock status of %s changed: %s", w->shared_name, k ? "busy" : "not busy");

    pa_reserve_monitor_wrapper_unref(w);
}
static void fire_object_property_changed_hook(struct pa_policy_object *object)
{
    pa_core                 *core;
    pa_core_hook_t           hook;
    struct pa_sink          *sink;
    struct pa_source        *src;
    struct pa_sink_input    *sinp;
    struct pa_source_output *sout;

   switch (object->type) {

    case pa_policy_object_sink:
        sink = object->ptr;
        core = sink->core;
        hook = PA_CORE_HOOK_SINK_PROPLIST_CHANGED;
        break;
        
    case pa_policy_object_source:
        src  = object->ptr;
        core = src->core;
        hook = PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED;
        break;
        
    case pa_policy_object_sink_input:
        sinp = object->ptr;
        core = sinp->core;
        hook = PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED;
        break;
        
    case pa_policy_object_source_output:
        sout = object->ptr;
        core = sout->core;
        hook = PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED;
        break;
        
    default:
        return;
    }

   pa_hook_fire(&core->hooks[hook], object->ptr);
}
Ejemplo n.º 14
0
/* Called from main context */
static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
    pa_assert(o);
    pa_assert_ctl_context();

    if (o->state == state)
        return;

    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);

    update_n_corked(o, state);
    o->state = state;

    if (state != PA_SOURCE_OUTPUT_UNLINKED) {
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);

        if (PA_SOURCE_OUTPUT_IS_LINKED(state))
            pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
    }

    pa_source_update_status(o->source);
}
Ejemplo n.º 15
0
void pa_device_port_set_available(pa_device_port *p, pa_available_t status)
{
    pa_core *core;

    pa_assert(p);

    if (p->available == status)
        return;

/*    pa_assert(status != PA_AVAILABLE_UNKNOWN); */

    p->available = status;
    pa_log_debug("Setting port %s to status %s", p->name, status == PA_AVAILABLE_YES ? "yes" :
       status == PA_AVAILABLE_NO ? "no" : "unknown");

    /* Post subscriptions to the card which owns us */
    pa_assert_se(core = p->core);
    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, p->card->index);

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
}
Ejemplo n.º 16
0
void pa_device_port_set_available(pa_device_port *p, pa_port_available_t status)
{
    uint32_t state;
    pa_card *card;
/*    pa_source *source;
    pa_sink *sink; */
    pa_core *core;

    pa_assert(p);

    if (p->available == status)
        return;

/*    pa_assert(status != PA_PORT_AVAILABLE_UNKNOWN); */

    p->available = status;
    pa_log_debug("Setting port %s to status %s", p->name, status == PA_PORT_AVAILABLE_YES ? "yes" :
       status == PA_PORT_AVAILABLE_NO ? "no" : "unknown");

    /* Post subscriptions to the card which owns us */
    pa_assert_se(core = p->core);
    PA_IDXSET_FOREACH(card, core->cards, state)
        if (p == pa_hashmap_get(card->ports, p->name))
            pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, card->index);
#if 0
/* This stuff is temporarily commented out while figuring out whether to actually do this */
    if (p->is_output)
        PA_IDXSET_FOREACH(sink, core->sinks, state)
            if (p == pa_hashmap_get(sink->ports, p->name))
                pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, sink->index);
    if (p->is_input)
        PA_IDXSET_FOREACH(source, core->sources, state)
            if (p == pa_hashmap_get(source->ports, p->name))
                pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, source->index);
#endif

    pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], p);
}
Ejemplo n.º 17
0
/* Called from main context */
void pa_source_output_set_name(pa_source_output *o, const char *name) {
    const char *old;
    pa_assert_ctl_context();
    pa_source_output_assert_ref(o);

    if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
        return;

    old = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME);

    if (old && name && !strcmp(old, name))
        return;

    if (name)
        pa_proplist_sets(o->proplist, PA_PROP_MEDIA_NAME, name);
    else
        pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME);

    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
        pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
        pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
    }
}
Ejemplo n.º 18
0
/* Called from main context */
void pa_source_output_put(pa_source_output *o) {
    pa_source_output_state_t state;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();

    pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);

    /* The following fields must be initialized properly */
    pa_assert(o->push);
    pa_assert(o->kill);

    state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;

    update_n_corked(o, state);
    o->state = state;

    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);

    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);

    pa_source_update_status(o->source);
}
Ejemplo n.º 19
0
/* Called from main context */
int pa_source_output_new(
        pa_source_output**_o,
        pa_core *core,
        pa_source_output_new_data *data) {

    pa_source_output *o;
    pa_resampler *resampler = NULL;
    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
    int r;
    char *pt;

    pa_assert(_o);
    pa_assert(core);
    pa_assert(data);
    pa_assert_ctl_context();

    if (data->client)
        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);

    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0)
        return r;

    pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);

    if (!data->source) {
        data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE);
        data->save_source = FALSE;
    }

    pa_return_val_if_fail(data->source, -PA_ERR_NOENTITY);
    pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE);
    pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID);

    if (!data->sample_spec_is_set)
        data->sample_spec = data->source->sample_spec;

    pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID);

    if (!data->channel_map_is_set) {
        if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec))
            data->channel_map = data->source->channel_map;
        else
            pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
    }

    pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID);
    pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);

    if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT)
        data->sample_spec.format = data->source->sample_spec.format;

    if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE)
        data->sample_spec.rate = data->source->sample_spec.rate;

    if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
        data->sample_spec.channels = data->source->sample_spec.channels;
        data->channel_map = data->source->channel_map;
    }

    pa_assert(pa_sample_spec_valid(&data->sample_spec));
    pa_assert(pa_channel_map_valid(&data->channel_map));

    if (data->resample_method == PA_RESAMPLER_INVALID)
        data->resample_method = core->resample_method;

    pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);

    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
        return r;

    if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
        pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
        pa_log("Failed to create source output: source is suspended.");
        return -PA_ERR_BADSTATE;
    }

    if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
        pa_log("Failed to create source output: too many outputs per source.");
        return -PA_ERR_TOOLARGE;
    }

    if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
        !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {

        if (!(resampler = pa_resampler_new(
                      core->mempool,
                      &data->source->sample_spec, &data->source->channel_map,
                      &data->sample_spec, &data->channel_map,
                      data->resample_method,
                      ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
                      ((data->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
                      (core->disable_remixing || (data->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
                      (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
            pa_log_warn("Unsupported resampling operation.");
            return -PA_ERR_NOTSUPPORTED;
        }
    }

    o = pa_msgobject_new(pa_source_output);
    o->parent.parent.free = source_output_free;
    o->parent.process_msg = pa_source_output_process_msg;

    o->core = core;
    o->state = PA_SOURCE_OUTPUT_INIT;
    o->flags = data->flags;
    o->proplist = pa_proplist_copy(data->proplist);
    o->driver = pa_xstrdup(pa_path_get_filename(data->driver));
    o->module = data->module;
    o->source = data->source;
    o->destination_source = data->destination_source;
    o->client = data->client;

    o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
    o->requested_resample_method = data->resample_method;
    o->sample_spec = data->sample_spec;
    o->channel_map = data->channel_map;

    o->direct_on_input = data->direct_on_input;

    o->save_source = data->save_source;

    reset_callbacks(o);
    o->userdata = NULL;

    o->thread_info.state = o->state;
    o->thread_info.attached = FALSE;
    o->thread_info.sample_spec = o->sample_spec;
    o->thread_info.resampler = resampler;
    o->thread_info.requested_source_latency = (pa_usec_t) -1;
    o->thread_info.direct_on_input = o->direct_on_input;

    o->thread_info.delay_memblockq = pa_memblockq_new(
            0,
            MEMBLOCKQ_MAXLENGTH,
            0,
            pa_frame_size(&o->source->sample_spec),
            0,
            1,
            0,
            &o->source->silence);

    pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
    pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);

    if (o->client)
        pa_assert_se(pa_idxset_put(o->client->source_outputs, o, NULL) >= 0);

    if (o->direct_on_input)
        pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);

    pt = pa_proplist_to_string_sep(o->proplist, "\n    ");
    pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s\n    %s",
                o->index,
                pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)),
                o->source->name,
                pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec),
                pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
                pt);
    pa_xfree(pt);

    /* Don't forget to call pa_source_output_put! */

    *_o = o;
    return 0;
}
Ejemplo n.º 20
0
/* Called from main context */
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) {
    pa_resampler *new_resampler;

    pa_source_output_assert_ref(o);
    pa_assert_ctl_context();
    pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
    pa_assert(!o->source);
    pa_source_assert_ref(dest);

    if (!pa_source_output_may_move_to(o, dest))
        return -1;

    if (o->thread_info.resampler &&
        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) &&
        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map))

        /* Try to reuse the old resampler if possible */
        new_resampler = o->thread_info.resampler;

    else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
             !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
             !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) {

        /* Okey, we need a new resampler for the new source */

        if (!(new_resampler = pa_resampler_new(
                      o->core->mempool,
                      &dest->sample_spec, &dest->channel_map,
                      &o->sample_spec, &o->channel_map,
                      o->requested_resample_method,
                      ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
                      ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
                      (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
            pa_log_warn("Unsupported resampling operation.");
            return -PA_ERR_NOTSUPPORTED;
        }
    } else
        new_resampler = NULL;

    if (o->moving)
        o->moving(o, dest);

    o->source = dest;
    o->save_source = save;
    pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL);

    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
        o->source->n_corked++;

    /* Replace resampler */
    if (new_resampler != o->thread_info.resampler) {
        if (o->thread_info.resampler)
            pa_resampler_free(o->thread_info.resampler);
        o->thread_info.resampler = new_resampler;

        pa_memblockq_free(o->thread_info.delay_memblockq);

        o->thread_info.delay_memblockq = pa_memblockq_new(
                0,
                MEMBLOCKQ_MAXLENGTH,
                0,
                pa_frame_size(&o->source->sample_spec),
                0,
                1,
                0,
                &o->source->silence);
        o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
    }

    pa_source_update_status(dest);

    pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0);

    pa_log_debug("Successfully moved source output %i to %s.", o->index, dest->name);

    /* Notify everyone */
    pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], o);
    pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);

    return 0;
}
Ejemplo n.º 21
0
static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
    pa_bluetooth_transport *t = userdata;

    pa_assert(io);
    pa_assert(t);

    if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
        pa_log_info("Lost RFCOMM connection.");
        goto fail;
    }

    if (events & PA_IO_EVENT_INPUT) {
        char buf[512];
        ssize_t len;
        int gain, dummy;
        bool  do_reply = false;

        len = pa_read(fd, buf, 511, NULL);
        if (len < 0) {
            pa_log_error("RFCOMM read error: %s", pa_cstrerror(errno));
            goto fail;
        }
        buf[len] = 0;
        pa_log_debug("RFCOMM << %s", buf);

        /* There are only four HSP AT commands:
         * AT+VGS=value: value between 0 and 15, sent by the HS to AG to set the speaker gain.
         * +VGS=value is sent by AG to HS as a response to an AT+VGS command or when the gain
         * is changed on the AG side.
         * AT+VGM=value: value between 0 and 15, sent by the HS to AG to set the microphone gain.
         * +VGM=value is sent by AG to HS as a response to an AT+VGM command or when the gain
         * is changed on the AG side.
         * AT+CKPD=200: Sent by HS when headset button is pressed.
         * RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because
         * it does not expect a reply. */
        if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM=%d\r\n", &gain) == 1) {
            t->speaker_gain = gain;
            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);
            do_reply = true;

        } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS=%d\r\n", &gain) == 1) {
            t->microphone_gain = gain;
            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);
            do_reply = true;
        } else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) {
            do_reply = true;
        } else {
            do_reply = false;
        }

        if (do_reply) {
            pa_log_debug("RFCOMM >> OK");

            len = write(fd, "\r\nOK\r\n", 6);

            /* we ignore any errors, it's not critical and real errors should
             * be caught with the HANGUP and ERROR events handled above */
            if (len < 0)
                pa_log_error("RFCOMM write error: %s", pa_cstrerror(errno));
        }
    }

    return;

fail:
    pa_bluetooth_transport_unlink(t);
    pa_bluetooth_transport_free(t);
}
Ejemplo n.º 22
0
/* Called from main context */
pa_source* pa_source_new(
        pa_core *core,
        pa_source_new_data *data,
        pa_source_flags_t flags) {

    pa_source *s;
    const char *name;
    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
    char *pt;

    pa_assert(core);
    pa_assert(data);
    pa_assert(data->name);
    pa_assert_ctl_context();

    s = pa_msgobject_new(pa_source);

    if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
        pa_log_debug("Failed to register name %s.", data->name);
        pa_xfree(s);
        return NULL;
    }

    pa_source_new_data_set_name(data, name);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
        pa_xfree(s);
        pa_namereg_unregister(core, name);
        return NULL;
    }

    /* FIXME, need to free s here on failure */

    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
    pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);

    pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));

    if (!data->channel_map_is_set)
        pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));

    pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
    pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);

    if (!data->volume_is_set)
        pa_cvolume_reset(&data->volume, data->sample_spec.channels);

    pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
    pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));

    if (!data->muted_is_set)
        data->muted = FALSE;

    if (data->card)
        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);

    pa_device_init_description(data->proplist);
    pa_device_init_icon(data->proplist, FALSE);
    pa_device_init_intended_roles(data->proplist);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
        pa_xfree(s);
        pa_namereg_unregister(core, name);
        return NULL;
    }

    s->parent.parent.free = source_free;
    s->parent.process_msg = pa_source_process_msg;

    s->core = core;
    s->state = PA_SOURCE_INIT;
    s->flags = flags;
    s->priority = 0;
    s->suspend_cause = 0;
    s->name = pa_xstrdup(name);
    s->proplist = pa_proplist_copy(data->proplist);
    s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
    s->module = data->module;
    s->card = data->card;

    s->priority = pa_device_init_priority(s->proplist);

    s->sample_spec = data->sample_spec;
    s->channel_map = data->channel_map;

    s->outputs = pa_idxset_new(NULL, NULL);
    s->n_corked = 0;
    s->monitor_of = NULL;
    s->output_from_master = NULL;

    s->volume = data->volume;
    pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
    s->base_volume = PA_VOLUME_NORM;
    s->n_volume_steps = PA_VOLUME_NORM+1;
    s->muted = data->muted;
    s->refresh_volume = s->refresh_muted = FALSE;

    reset_callbacks(s);
    s->userdata = NULL;

    s->asyncmsgq = NULL;

    /* As a minor optimization we just steal the list instead of
     * copying it here */
    s->ports = data->ports;
    data->ports = NULL;

    s->active_port = NULL;
    s->save_port = FALSE;

    if (data->active_port && s->ports)
        if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
            s->save_port = data->save_port;

    if (!s->active_port && s->ports) {
        void *state;
        pa_device_port *p;

        PA_HASHMAP_FOREACH(p, s->ports, state)
            if (!s->active_port || p->priority > s->active_port->priority)
                s->active_port = p;
    }