Пример #1
0
static void my_flush_events(struct SoundIoPrivate *si, bool wait) {
    SoundIo *soundio = &si->pub;
    SoundIoJack *sij = &si->backend_data.jack;
    int err;

    bool cb_shutdown = false;

    soundio_os_mutex_lock(sij->mutex);

    if (wait)
        soundio_os_cond_wait(sij->cond, sij->mutex);

    if (sij->is_shutdown && !sij->emitted_shutdown_cb) {
        sij->emitted_shutdown_cb = true;
        cb_shutdown = true;
    }

    soundio_os_mutex_unlock(sij->mutex);

    if (cb_shutdown) {
        soundio->on_backend_disconnect(soundio, SoundIoErrorBackendDisconnected);
    } else {
        if (!sij->refresh_devices_flag.test_and_set()) {
            if ((err = refresh_devices(si))) {
                sij->refresh_devices_flag.clear();
            } else {
                soundio->on_devices_change(soundio);
            }
        }
    }
}
Пример #2
0
static void context_state_callback(pa_context *context, void *userdata) {
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
    SoundIo *soundio = &si->pub;

    switch (pa_context_get_state(context)) {
    case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
        return;
    case PA_CONTEXT_CONNECTING: // A connection is being established.
        return;
    case PA_CONTEXT_AUTHORIZING: // The client is authorizing itself to the daemon.
        return;
    case PA_CONTEXT_SETTING_NAME: // The client is passing its application name to the daemon.
        return;
    case PA_CONTEXT_READY: // The connection is established, the context is ready to execute operations.
        sipa->ready_flag = true;
        pa_threaded_mainloop_signal(sipa->main_loop, 0);
        return;
    case PA_CONTEXT_TERMINATED: // The connection was terminated cleanly.
        pa_threaded_mainloop_signal(sipa->main_loop, 0);
        return;
    case PA_CONTEXT_FAILED: // The connection failed or was disconnected.
        if (sipa->ready_flag) {
            sipa->connection_err = SoundIoErrorBackendDisconnected;
        } else {
            sipa->connection_err = SoundIoErrorInitAudioBackend;
            sipa->ready_flag = true;
        }
        pa_threaded_mainloop_signal(sipa->main_loop, 0);
        soundio->on_events_signal(soundio);
        return;
    }
}
Пример #3
0
static void notify_devices_change(SoundIoPrivate *si) {
    SoundIo *soundio = &si->pub;
    SoundIoJack *sij = &si->backend_data.jack;
    sij->refresh_devices_flag.clear();
    soundio_os_mutex_lock(sij->mutex);
    soundio_os_cond_signal(sij->cond, sij->mutex);
    soundio->on_events_signal(soundio);
    soundio_os_mutex_unlock(sij->mutex);
}
Пример #4
0
static void force_device_scan_pa(SoundIoPrivate *si) {
    SoundIo *soundio = &si->pub;
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
    pa_threaded_mainloop_lock(sipa->main_loop);
    sipa->device_scan_queued = true;
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
    soundio->on_events_signal(soundio);
    pa_threaded_mainloop_unlock(sipa->main_loop);
}
Пример #5
0
static void shutdown_callback(void *arg) {
    SoundIoPrivate *si = (SoundIoPrivate *)arg;
    SoundIo *soundio = &si->pub;
    SoundIoJack *sij = &si->backend_data.jack;
    soundio_os_mutex_lock(sij->mutex);
    sij->is_shutdown = true;
    soundio_os_cond_signal(sij->cond, sij->mutex);
    soundio->on_events_signal(soundio);
    soundio_os_mutex_unlock(sij->mutex);
}
Пример #6
0
static void subscribe_callback(pa_context *context,
        pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
{
    SoundIoPrivate *si = (SoundIoPrivate *)userdata;
    SoundIo *soundio = &si->pub;
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
    sipa->device_scan_queued = true;
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
    soundio->on_events_signal(soundio);
}
Пример #7
0
static void my_flush_events(SoundIoPrivate *si, bool wait) {
    SoundIo *soundio = &si->pub;
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;

    bool change = false;
    bool cb_shutdown = false;
    SoundIoDevicesInfo *old_devices_info = nullptr;

    pa_threaded_mainloop_lock(sipa->main_loop);

    if (wait)
        pa_threaded_mainloop_wait(sipa->main_loop);

    if (sipa->device_scan_queued && !sipa->connection_err) {
        sipa->device_scan_queued = false;
        sipa->connection_err = refresh_devices(si);
        cleanup_refresh_devices(si);
    }

    if (sipa->connection_err && !sipa->emitted_shutdown_cb) {
        sipa->emitted_shutdown_cb = true;
        cb_shutdown = true;
    } else if (sipa->ready_devices_info) {
        old_devices_info = si->safe_devices_info;
        si->safe_devices_info = sipa->ready_devices_info;
        sipa->ready_devices_info = nullptr;
        change = true;
    }

    pa_threaded_mainloop_unlock(sipa->main_loop);

    if (cb_shutdown)
        soundio->on_backend_disconnect(soundio, sipa->connection_err);
    else if (change)
        soundio->on_devices_change(soundio);

    soundio_destroy_devices_info(old_devices_info);
}
Пример #8
0
// call this while holding the main loop lock
static int refresh_devices(SoundIoPrivate *si) {
    SoundIo *soundio = &si->pub;
    SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;

    assert(!sipa->current_devices_info);
    sipa->current_devices_info = allocate<SoundIoDevicesInfo>(1);
    if (!sipa->current_devices_info)
        return SoundIoErrorNoMem;

    pa_operation *list_sink_op = pa_context_get_sink_info_list(sipa->pulse_context, sink_info_callback, si);
    pa_operation *list_source_op = pa_context_get_source_info_list(sipa->pulse_context, source_info_callback, si);
    pa_operation *server_info_op = pa_context_get_server_info(sipa->pulse_context, server_info_callback, si);

    int err;
    if ((err = perform_operation(si, list_sink_op))) {
        return err;
    }
    if ((err = perform_operation(si, list_source_op))) {
        return err;
    }
    if ((err = perform_operation(si, server_info_op))) {
        return err;
    }

    if (sipa->device_query_err) {
        return sipa->device_query_err;
    }

    // based on the default sink name, figure out the default output index
    // if the name doesn't match just pick the first one. if there are no
    // devices then we need to set it to -1.
    sipa->current_devices_info->default_output_index = -1;
    sipa->current_devices_info->default_input_index = -1;

    if (sipa->current_devices_info->input_devices.length > 0) {
        sipa->current_devices_info->default_input_index = 0;
        for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) {
            SoundIoDevice *device = sipa->current_devices_info->input_devices.at(i);
            assert(device->aim == SoundIoDeviceAimInput);
            if (strcmp(device->id, sipa->default_source_name) == 0) {
                sipa->current_devices_info->default_input_index = i;
            }
        }
    }

    if (sipa->current_devices_info->output_devices.length > 0) {
        sipa->current_devices_info->default_output_index = 0;
        for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) {
            SoundIoDevice *device = sipa->current_devices_info->output_devices.at(i);
            assert(device->aim == SoundIoDeviceAimOutput);
            if (strcmp(device->id, sipa->default_sink_name) == 0) {
                sipa->current_devices_info->default_output_index = i;
            }
        }
    }

    soundio_destroy_devices_info(sipa->ready_devices_info);
    sipa->ready_devices_info = sipa->current_devices_info;
    sipa->current_devices_info = nullptr;
    pa_threaded_mainloop_signal(sipa->main_loop, 0);
    soundio->on_events_signal(soundio);

    return 0;
}