コード例 #1
0
static void pulse_stop_capture(ALCdevice *device)
{
    pulse_data *data = device->ExtraData;
    pa_operation *o;

    o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
    wait_for_operation(o, data->loop);
}
コード例 #2
0
/** Issue special libao controls on the device */
static int control(int cmd, void *arg) {
    
    if (!context || !stream)
        return CONTROL_ERROR;
    
    switch (cmd) {

        case AOCONTROL_SET_DEVICE:
            /* Change the playback device */
            sink = (char*)arg;
            return CONTROL_OK;

        case AOCONTROL_GET_DEVICE:
            /* Return the playback device */
            *(char**)arg = sink;
            return CONTROL_OK;
        
        case AOCONTROL_GET_VOLUME: {
            /* Return the current volume of the playback stream */
            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
                
            volume = PA_VOLUME_NORM;
            wait_for_operation(pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL));
            vol->left = vol->right = (int) (pa_volume_to_user(volume)*100);
            return CONTROL_OK;
        }
            
        case AOCONTROL_SET_VOLUME: {
            /* Set the playback volume of the stream */
            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
            int v = vol->left;
            if (vol->right > v)
                v = vol->left;
            
            wait_for_operation(pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), pa_volume_from_user((double)v/100), NULL, NULL));
            
            return CONTROL_OK;
        }
            
        default:
            /* Unknown CONTROL command */
            return CONTROL_UNKNOWN;
    }
}
コード例 #3
0
/** Play the specified data to the polypaudio server */
static int play(void* data, int len, int flags) {
    assert(stream && context);

    if (pa_stream_get_state(stream) != PA_STREAM_READY)
        return -1;

    if (!len)
        wait_for_operation(pa_stream_trigger(stream, NULL, NULL));
    else
        pa_stream_write(stream, data, len, NULL, 0);

    wait_for_completion();

    if (pa_stream_get_state(stream) != PA_STREAM_READY)
        return -1;

    return len;
}
コード例 #4
0
/** Destroy libao driver */
static void uninit(int immed) {
    if (stream) {
        if (!immed && pa_stream_get_state(stream) == PA_STREAM_READY)
                wait_for_operation(pa_stream_drain(stream, NULL, NULL));
        
        pa_stream_unref(stream);
        stream = NULL;
    }

    if (context) {
        pa_context_unref(context);
        context = NULL;
    }

    if (mainloop) {
        pa_mainloop_free(mainloop);
        mainloop = NULL;
    }
}
コード例 #5
0
static void pulse_stop_playback(ALCdevice *device)
{
    pulse_data *data = device->ExtraData;
    pa_operation *o;

    if(!data->stream)
        return;

    data->killNow = AL_TRUE;
    if(data->thread)
    {
        StopThread(data->thread);
        data->thread = NULL;
    }
    data->killNow = AL_FALSE;

    pa_threaded_mainloop_lock(data->loop);

    o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
    wait_for_operation(o, data->loop);

    pa_threaded_mainloop_unlock(data->loop);
}
コード例 #6
0
/** Reset the audio stream, i.e. flush the playback buffer on the server side */
static void reset(void) {
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
    wait_for_operation(pa_stream_flush(stream, NULL, NULL));
}
コード例 #7
0
/** Resume the audio stream by uncorking it on the server */
static void audio_resume(void) {
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
    wait_for_operation(pa_stream_cork(stream, 0, NULL, NULL));
}
コード例 #8
0
/* OpenAL */
static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name)
{
    const char *pulse_name = NULL;
    pa_stream_flags_t flags;
    pa_sample_spec spec;
    pulse_data *data;
    pa_operation *o;

    if(device_name)
    {
        ALuint i;

        if(!allDevNameMap)
            probe_devices(AL_FALSE);

        for(i = 0; i < numDevNames; i++)
        {
            if(strcmp(device_name, allDevNameMap[i].name) == 0)
            {
                pulse_name = allDevNameMap[i].device_name;
                break;
            }
        }
        if(i == numDevNames)
            return ALC_INVALID_VALUE;
    }

    if(pulse_open(device) == ALC_FALSE)
        return ALC_INVALID_VALUE;

    data = device->ExtraData;
    pa_threaded_mainloop_lock(data->loop);

    flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
            PA_STREAM_FIX_CHANNELS;
    if(!GetConfigValueBool("pulse", "allow-moves", 0))
        flags |= PA_STREAM_DONT_MOVE;

    spec.format = PA_SAMPLE_S16NE;
    spec.rate = 44100;
    spec.channels = 2;

    data->stream = connect_playback_stream(pulse_name, data->loop, data->context,
                                           flags, NULL, &spec, NULL);
    if(!data->stream)
    {
        pa_threaded_mainloop_unlock(data->loop);
        pulse_close(device);
        return ALC_INVALID_VALUE;
    }

    data->device_name = strdup(pa_stream_get_device_name(data->stream));
    o = pa_context_get_sink_info_by_name(data->context, data->device_name,
                                         sink_name_callback, device);
    wait_for_operation(o, data->loop);

    pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);

    pa_threaded_mainloop_unlock(data->loop);

    return ALC_NO_ERROR;
}
コード例 #9
0
static void probe_devices(ALboolean capture)
{
    pa_threaded_mainloop *loop;

    if(capture == AL_FALSE)
        allDevNameMap = malloc(sizeof(DevMap) * 1);
    else
        allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);

    if((loop=pa_threaded_mainloop_new()) &&
            pa_threaded_mainloop_start(loop) >= 0)
    {
        pa_context *context;

        pa_threaded_mainloop_lock(loop);
        context = connect_context(loop, AL_FALSE);
        if(context)
        {
            pa_operation *o;

            if(capture == AL_FALSE)
            {
                pa_stream_flags_t flags;
                pa_sample_spec spec;
                pa_stream *stream;

                flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
                        PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;

                spec.format = PA_SAMPLE_S16NE;
                spec.rate = 44100;
                spec.channels = 2;

                stream = connect_playback_stream(NULL, loop, context, flags,
                                                 NULL, &spec, NULL);
                if(stream)
                {
                    o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop);
                    wait_for_operation(o, loop);

                    pa_stream_disconnect(stream);
                    pa_stream_unref(stream);
                    stream = NULL;
                }

                o = pa_context_get_sink_info_list(context, sink_device_callback, loop);
            }
            else
            {
                pa_stream_flags_t flags;
                pa_sample_spec spec;
                pa_stream *stream;

                flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
                        PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;

                spec.format = PA_SAMPLE_S16NE;
                spec.rate = 44100;
                spec.channels = 1;

                stream = connect_record_stream(NULL, loop, context, flags,
                                               NULL, &spec, NULL);
                if(stream)
                {
                    o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop);
                    wait_for_operation(o, loop);

                    pa_stream_disconnect(stream);
                    pa_stream_unref(stream);
                    stream = NULL;
                }

                o = pa_context_get_source_info_list(context, source_device_callback, loop);
            }
            wait_for_operation(o, loop);

            pa_context_disconnect(context);
            pa_context_unref(context);
        }
        pa_threaded_mainloop_unlock(loop);
        pa_threaded_mainloop_stop(loop);
    }
    if(loop)
        pa_threaded_mainloop_free(loop);
}
コード例 #10
0
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
{
    const char *pulse_name = NULL;
    pa_stream_flags_t flags = 0;
    pa_channel_map chanmap;
    pulse_data *data;
    pa_operation *o;
    ALuint samples;

    if(device_name)
    {
        ALuint i;

        if(!allCaptureDevNameMap)
            probe_devices(AL_TRUE);

        for(i = 0; i < numCaptureDevNames; i++)
        {
            if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
            {
                pulse_name = allCaptureDevNameMap[i].device_name;
                break;
            }
        }
        if(i == numCaptureDevNames)
            return ALC_INVALID_VALUE;
    }

    if(pulse_open(device) == ALC_FALSE)
        return ALC_INVALID_VALUE;

    data = device->ExtraData;
    pa_threaded_mainloop_lock(data->loop);

    data->spec.rate = device->Frequency;
    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);

    switch(device->FmtType)
    {
    case DevFmtUByte:
        data->spec.format = PA_SAMPLE_U8;
        break;
    case DevFmtShort:
        data->spec.format = PA_SAMPLE_S16NE;
        break;
    case DevFmtInt:
        data->spec.format = PA_SAMPLE_S32NE;
        break;
    case DevFmtFloat:
        data->spec.format = PA_SAMPLE_FLOAT32NE;
        break;
    case DevFmtByte:
    case DevFmtUShort:
    case DevFmtUInt:
        ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }

    if(pa_sample_spec_valid(&data->spec) == 0)
    {
        ERR("Invalid sample format\n");
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }

    if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
    {
        ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }

    samples = device->UpdateSize * device->NumUpdates;
    samples = maxu(samples, 100 * device->Frequency / 1000);

    data->attr.minreq = -1;
    data->attr.prebuf = -1;
    data->attr.maxlength = samples * pa_frame_size(&data->spec);
    data->attr.tlength = -1;
    data->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
                          pa_frame_size(&data->spec);

    flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
    if(!GetConfigValueBool("pulse", "allow-moves", 0))
        flags |= PA_STREAM_DONT_MOVE;

    data->stream = connect_record_stream(pulse_name, data->loop, data->context,
                                         flags, &data->attr, &data->spec,
                                         &chanmap);
    if(!data->stream)
    {
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }
    pa_stream_set_state_callback(data->stream, stream_state_callback2, device);

    data->device_name = strdup(pa_stream_get_device_name(data->stream));
    o = pa_context_get_source_info_by_name(data->context, data->device_name,
                                           source_name_callback, device);
    wait_for_operation(o, data->loop);

    pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);

    pa_threaded_mainloop_unlock(data->loop);
    return ALC_NO_ERROR;

fail:
    pulse_close(device);
    return ALC_INVALID_VALUE;
}
コード例 #11
0
static ALCboolean pulse_reset_playback(ALCdevice *device)
{
    pulse_data *data = device->ExtraData;
    pa_stream_flags_t flags = 0;
    pa_channel_map chanmap;
    ALuint len;

    pa_threaded_mainloop_lock(data->loop);

    if(data->stream)
    {
        pa_stream_set_moved_callback(data->stream, NULL, NULL);
#if PA_CHECK_VERSION(0,9,15)
        if(pa_stream_set_buffer_attr_callback)
            pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
#endif
        pa_stream_disconnect(data->stream);
        pa_stream_unref(data->stream);
        data->stream = NULL;
    }

    if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
    {
        pa_operation *o;
        o = pa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
        wait_for_operation(o, data->loop);
    }
    if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
        flags |= PA_STREAM_FIX_RATE;

    flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
    flags |= PA_STREAM_ADJUST_LATENCY;
    flags |= PA_STREAM_START_CORKED;
    if(!GetConfigValueBool("pulse", "allow-moves", 0))
        flags |= PA_STREAM_DONT_MOVE;

    switch(device->FmtType)
    {
    case DevFmtByte:
        device->FmtType = DevFmtUByte;
    /* fall-through */
    case DevFmtUByte:
        data->spec.format = PA_SAMPLE_U8;
        break;
    case DevFmtUShort:
        device->FmtType = DevFmtShort;
    /* fall-through */
    case DevFmtShort:
        data->spec.format = PA_SAMPLE_S16NE;
        break;
    case DevFmtUInt:
        device->FmtType = DevFmtInt;
    /* fall-through */
    case DevFmtInt:
        data->spec.format = PA_SAMPLE_S32NE;
        break;
    case DevFmtFloat:
        data->spec.format = PA_SAMPLE_FLOAT32NE;
        break;
    }
    data->spec.rate = device->Frequency;
    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);

    if(pa_sample_spec_valid(&data->spec) == 0)
    {
        ERR("Invalid sample format\n");
        pa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
    {
        ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
        pa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }
    SetDefaultWFXChannelOrder(device);

    data->attr.fragsize = -1;
    data->attr.prebuf = 0;
    data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec);
    data->attr.tlength = data->attr.minreq * maxu(device->NumUpdates, 2);
    data->attr.maxlength = -1;

    data->stream = connect_playback_stream(data->device_name, data->loop,
                                           data->context, flags, &data->attr,
                                           &data->spec, &chanmap);
    if(!data->stream)
    {
        pa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }
    pa_stream_set_state_callback(data->stream, stream_state_callback2, device);

    data->spec = *(pa_stream_get_sample_spec(data->stream));
    if(device->Frequency != data->spec.rate)
    {
        pa_operation *o;

        /* Server updated our playback rate, so modify the buffer attribs
         * accordingly. */
        device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
                                      data->spec.rate + 0.5);
        data->attr.minreq  = device->UpdateSize * pa_frame_size(&data->spec);
        data->attr.tlength = data->attr.minreq * clampu(device->NumUpdates, 2, 16);
        data->attr.maxlength = -1;
        data->attr.prebuf  = 0;

        o = pa_stream_set_buffer_attr(data->stream, &data->attr,
                                      stream_success_callback, device);
        wait_for_operation(o, data->loop);

        device->Frequency = data->spec.rate;
    }

    pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
#if PA_CHECK_VERSION(0,9,15)
    if(pa_stream_set_buffer_attr_callback)
        pa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
#endif
    stream_buffer_attr_callback(data->stream, device);

    len = data->attr.minreq / pa_frame_size(&data->spec);
    if((CPUCapFlags&CPU_CAP_SSE))
        len = (len+3)&~3;
    device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
    device->NumUpdates = clampu(device->NumUpdates, 2, 16);
    device->UpdateSize = len;

    pa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;
}