Пример #1
0
static void stream_read_callback(pa_stream *stream, size_t length, void *pdata) //{{{
{
    ALCdevice *Device = pdata;
    pulse_data *data = Device->ExtraData;
    const void *buf;

    if(ppa_stream_peek(stream, &buf, &length) < 0)
    {
        AL_PRINT("pa_stream_peek() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));
        return;
    }

    assert(buf);
    assert(length);

    length /= data->frame_size;

    if(data->samples < length)
        AL_PRINT("stream_read_callback: buffer overflow!\n");

    WriteRingBuffer(data->ring, buf, (length<data->samples) ? length : data->samples);

    ppa_stream_drop(stream);
} //}}}
static ALCuint pulse_available_samples( ALCdevice* device ) //{{{
{
	pulse_data* data = device->ExtraData;
	size_t samples;

	ppa_threaded_mainloop_lock( data->loop );
	/* Capture is done in fragment-sized chunks, so we loop until we get all
	 * that's available */
	samples = ( device->Connected ? ppa_stream_readable_size( data->stream ) : 0 );

	while ( samples > 0 )
	{
		const void* buf;
		size_t length;

		if ( ppa_stream_peek( data->stream, &buf, &length ) < 0 )
		{
			AL_PRINT( "pa_stream_peek() failed: %s\n",
			          ppa_strerror( ppa_context_errno( data->context ) ) );
			break;
		}

		WriteRingBuffer( data->ring, buf, length / data->frame_size );
		samples -= length;

		ppa_stream_drop( data->stream );
	}

	ppa_threaded_mainloop_unlock( data->loop );

	return RingBufferSize( data->ring );
} //}}}
Пример #3
0
static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
{
    pulse_data *data = device->ExtraData;
    ALCuint available = RingBufferSize(data->ring);
    const void *buf;
    size_t length;

    available *= data->frame_size;
    samples *= data->frame_size;

    ppa_threaded_mainloop_lock(data->loop);
    if(available+ppa_stream_readable_size(data->stream) < samples)
    {
        ppa_threaded_mainloop_unlock(data->loop);
        alcSetError(device, ALC_INVALID_VALUE);
        return;
    }

    available = min(available, samples);
    if(available > 0)
    {
        ReadRingBuffer(data->ring, buffer, available/data->frame_size);
        buffer = (ALubyte*)buffer + available;
        samples -= available;
    }

    /* Capture is done in fragment-sized chunks, so we loop until we get all
     * that's requested */
    while(samples > 0)
    {
        if(ppa_stream_peek(data->stream, &buf, &length) < 0)
        {
            AL_PRINT("pa_stream_peek() failed: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));
            break;
        }
        available = min(length, samples);

        memcpy(buffer, buf, available);
        buffer = (ALubyte*)buffer + available;
        buf = (const ALubyte*)buf + available;
        samples -= available;
        length -= available;

        /* Any unread data in the fragment will be lost, so save it */
        length /= data->frame_size;
        if(length > 0)
        {
            if(length > data->samples)
                length = data->samples;
            WriteRingBuffer(data->ring, buf, length);
        }

        ppa_stream_drop(data->stream);
    }
    ppa_threaded_mainloop_unlock(data->loop);
} //}}}
static pa_stream* connect_playback_stream( ALCdevice* device,
                                           pa_stream_flags_t flags, pa_buffer_attr* attr, pa_sample_spec* spec,
                                           pa_channel_map* chanmap )
{
	pulse_data* data = device->ExtraData;
	pa_stream_state_t state;
	pa_stream* stream;

	stream = ppa_stream_new( data->context, "Playback Stream", spec, chanmap );

	if ( !stream )
	{
		AL_PRINT( "pa_stream_new() failed: %s\n",
		          ppa_strerror( ppa_context_errno( data->context ) ) );
		return NULL;
	}

	ppa_stream_set_state_callback( stream, stream_state_callback, data->loop );

	if ( ppa_stream_connect_playback( stream, data->device_name, attr, flags, NULL, NULL ) < 0 )
	{
		AL_PRINT( "Stream did not connect: %s\n",
		          ppa_strerror( ppa_context_errno( data->context ) ) );
		ppa_stream_unref( stream );
		return NULL;
	}

	while ( ( state = ppa_stream_get_state( stream ) ) != PA_STREAM_READY )
	{
		if ( !PA_STREAM_IS_GOOD( state ) )
		{
			AL_PRINT( "Stream did not get ready: %s\n",
			          ppa_strerror( ppa_context_errno( data->context ) ) );
			ppa_stream_unref( stream );
			return NULL;
		}

		ppa_threaded_mainloop_wait( data->loop );
	}

	ppa_stream_set_state_callback( stream, NULL, NULL );

	return stream;
}
static pa_context* connect_context( pa_threaded_mainloop* loop )
{
	const char* name = "OpenAL Soft";
	char path_name[PATH_MAX];
	pa_context_state_t state;
	pa_context* context;
	int err;

	if ( ppa_get_binary_name( path_name, sizeof( path_name ) ) )
	{
		name = ppa_path_get_filename( path_name );
	}

	context = ppa_context_new( ppa_threaded_mainloop_get_api( loop ), name );

	if ( !context )
	{
		AL_PRINT( "pa_context_new() failed\n" );
		return NULL;
	}

	ppa_context_set_state_callback( context, context_state_callback, loop );

	if ( ( err = ppa_context_connect( context, NULL, pulse_ctx_flags, NULL ) ) >= 0 )
	{
		while ( ( state = ppa_context_get_state( context ) ) != PA_CONTEXT_READY )
		{
			if ( !PA_CONTEXT_IS_GOOD( state ) )
			{
				err = ppa_context_errno( context );
				break;
			}

			ppa_threaded_mainloop_wait( loop );
		}
	}

	ppa_context_set_state_callback( context, NULL, NULL );

	if ( err < 0 )
	{
		AL_PRINT( "Context did not connect: %s\n", ppa_strerror( err ) );
		ppa_context_unref( context );
		return NULL;
	}

	return context;
}
Пример #6
0
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
{
    pulse_data *data;
    pa_stream_state_t state;

    if(!pa_handle)
        return ALC_FALSE;

    if(!device_name)
        device_name = pulse_capture_device;
    else if(strcmp(device_name, pulse_capture_device) != 0)
        return ALC_FALSE;

    if(pulse_open(device, device_name) == ALC_FALSE)
        return ALC_FALSE;

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

    data->samples = device->UpdateSize * device->NumUpdates;
    data->frame_size = aluBytesFromFormat(device->Format) *
                       aluChannelsFromFormat(device->Format);

    if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
    {
        ppa_threaded_mainloop_unlock(data->loop);
        pulse_close(device);
        return ALC_FALSE;
    }

    data->attr.minreq = -1;
    data->attr.prebuf = -1;
    data->attr.maxlength = -1;
    data->attr.tlength = -1;
    data->attr.fragsize = data->frame_size * data->samples / 2;
    data->stream_name = "Capture Stream";

    data->spec.rate = device->Frequency;
    data->spec.channels = aluChannelsFromFormat(device->Format);

    switch(aluBytesFromFormat(device->Format))
    {
        case 1:
            data->spec.format = PA_SAMPLE_U8;
            break;
        case 2:
            data->spec.format = PA_SAMPLE_S16NE;
            break;
        case 4:
            data->spec.format = PA_SAMPLE_FLOAT32NE;
            break;
        default:
            AL_PRINT("Unknown format: 0x%x\n", device->Format);
            ppa_threaded_mainloop_unlock(data->loop);
            pulse_close(device);
            return ALC_FALSE;
    }

    if(ppa_sample_spec_valid(&data->spec) == 0)
    {
        AL_PRINT("Invalid sample format\n");
        ppa_threaded_mainloop_unlock(data->loop);
        pulse_close(device);
        return ALC_FALSE;
    }

    data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL);
    if(!data->stream)
    {
        AL_PRINT("pa_stream_new() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_threaded_mainloop_unlock(data->loop);
        pulse_close(device);
        return ALC_FALSE;
    }

    if(ppa_stream_connect_record(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY) < 0)
    {
        AL_PRINT("Stream did not connect: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_stream_unref(data->stream);
        ppa_threaded_mainloop_unlock(data->loop);

        data->stream = NULL;
        pulse_close(device);
        return ALC_FALSE;
    }

    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
    {
        if(!PA_STREAM_IS_GOOD(state))
        {
            AL_PRINT("Stream did not get ready: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));

            ppa_stream_unref(data->stream);
            ppa_threaded_mainloop_unlock(data->loop);

            data->stream = NULL;
            pulse_close(device);
            return ALC_FALSE;
        }

        ppa_threaded_mainloop_unlock(data->loop);
        Sleep(1);
        ppa_threaded_mainloop_lock(data->loop);
    }

    ppa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;
} //}}}
Пример #7
0
static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    pa_stream_state_t state;

    ppa_threaded_mainloop_lock(data->loop);

    data->frame_size = aluBytesFromFormat(device->Format) *
                       aluChannelsFromFormat(device->Format);
    data->attr.minreq = data->frame_size * device->UpdateSize;
    data->attr.prebuf = -1;
    data->attr.maxlength = -1;
    data->attr.fragsize = -1;
    data->attr.tlength = data->attr.minreq * device->NumUpdates;
    data->stream_name = "Playback Stream";

    switch(aluBytesFromFormat(device->Format))
    {
        case 1:
            data->spec.format = PA_SAMPLE_U8;
            break;
        case 2:
            data->spec.format = PA_SAMPLE_S16NE;
            break;
        case 4:
            data->spec.format = PA_SAMPLE_FLOAT32NE;
            break;
        default:
            AL_PRINT("Unknown format: 0x%x\n", device->Format);
            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
    }
    data->spec.rate = device->Frequency;
    data->spec.channels = aluChannelsFromFormat(device->Format);

    if(ppa_sample_spec_valid(&data->spec) == 0)
    {
        AL_PRINT("Invalid sample format\n");
        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, NULL);
    if(!data->stream)
    {
        AL_PRINT("pa_stream_new() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    if(ppa_stream_connect_playback(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0)
    {
        AL_PRINT("Stream did not connect: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_stream_unref(data->stream);
        data->stream = NULL;

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
    {
        if(!PA_STREAM_IS_GOOD(state))
        {
            AL_PRINT("Stream did not get ready: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));

            ppa_stream_unref(data->stream);
            data->stream = NULL;

            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
        }

        ppa_threaded_mainloop_unlock(data->loop);
        Sleep(1);
        ppa_threaded_mainloop_lock(data->loop);
    }

    data->attr = *(ppa_stream_get_buffer_attr(data->stream));
    if((data->attr.tlength%data->attr.minreq) != 0)
        AL_PRINT("tlength (%d) is not a multiple of minreq (%d)!\n",
                 data->attr.tlength, data->attr.minreq);
    device->UpdateSize = data->attr.minreq;
    device->NumUpdates = data->attr.tlength/data->attr.minreq;

    ppa_stream_set_write_callback(data->stream, stream_write_callback, device);

    ppa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;
} //}}}
Пример #8
0
static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
{
    pulse_data *data = ppa_xmalloc0(sizeof(pulse_data));
    pa_context_state_t state;

    if(ppa_get_binary_name(data->path_name, sizeof(data->path_name)))
        data->context_name = ppa_path_get_filename(data->path_name);
    else
        data->context_name = "OpenAL Soft";

    if(!(data->loop = ppa_threaded_mainloop_new()))
    {
        AL_PRINT("pa_threaded_mainloop_new() failed!\n");
        goto out;
    }

    if(ppa_threaded_mainloop_start(data->loop) < 0)
    {
        AL_PRINT("pa_threaded_mainloop_start() failed\n");
        goto out;
    }

    ppa_threaded_mainloop_lock(data->loop);

    data->context = ppa_context_new(ppa_threaded_mainloop_get_api(data->loop), data->context_name);
    if(!data->context)
    {
        AL_PRINT("pa_context_new() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_threaded_mainloop_unlock(data->loop);
        goto out;
    }

    if(ppa_context_connect(data->context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0)
    {
        AL_PRINT("Context did not connect: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_context_unref(data->context);
        data->context = NULL;

        ppa_threaded_mainloop_unlock(data->loop);
        goto out;
    }

    while((state=ppa_context_get_state(data->context)) != PA_CONTEXT_READY)
    {
        if(!PA_CONTEXT_IS_GOOD(state))
        {
            AL_PRINT("Context did not get ready: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));

            ppa_context_unref(data->context);
            data->context = NULL;

            ppa_threaded_mainloop_unlock(data->loop);
            goto out;
        }

        ppa_threaded_mainloop_unlock(data->loop);
        Sleep(1);
        ppa_threaded_mainloop_lock(data->loop);
    }

    device->szDeviceName = strdup(device_name);
    device->ExtraData = data;

    ppa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;

out:
    if(data->loop)
    {
        ppa_threaded_mainloop_stop(data->loop);
        ppa_threaded_mainloop_free(data->loop);
    }

    ppa_xfree(data);
    return ALC_FALSE;
} //}}}
static ALCboolean pulse_open_capture( ALCdevice* device, const ALCchar* device_name ) //{{{
{
	char* pulse_name = NULL;
	pulse_data* data;
	pa_stream_flags_t flags = 0;
	pa_stream_state_t state;
	pa_channel_map chanmap;

	if ( !pulse_load() )
	{
		return ALC_FALSE;
	}

	if ( !allCaptureDevNameMap )
	{
		probe_devices( AL_TRUE );
	}

	if ( !device_name )
	{
		device_name = allCaptureDevNameMap[0].name;
	}
	else
	{
		ALuint i;

		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_FALSE;
		}
	}

	if ( pulse_open( device, device_name ) == ALC_FALSE )
	{
		return ALC_FALSE;
	}

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

	data->samples = device->UpdateSize * device->NumUpdates;
	data->frame_size = aluFrameSizeFromFormat( device->Format );

	if ( !( data->ring = CreateRingBuffer( data->frame_size, data->samples ) ) )
	{
		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

	data->attr.minreq = -1;
	data->attr.prebuf = -1;
	data->attr.maxlength = data->frame_size * data->samples;
	data->attr.tlength = -1;
	data->attr.fragsize = min( data->frame_size * data->samples,
	                           10 * device->Frequency / 1000 );

	data->spec.rate = device->Frequency;
	data->spec.channels = aluChannelsFromFormat( device->Format );

	switch ( aluBytesFromFormat( device->Format ) )
	{
		case 1:
			data->spec.format = PA_SAMPLE_U8;
			break;

		case 2:
			data->spec.format = PA_SAMPLE_S16NE;
			break;

		case 4:
			data->spec.format = PA_SAMPLE_FLOAT32NE;
			break;

		default:
			AL_PRINT( "Unknown format: 0x%x\n", device->Format );
			ppa_threaded_mainloop_unlock( data->loop );
			goto fail;
	}

	if ( ppa_sample_spec_valid( &data->spec ) == 0 )
	{
		AL_PRINT( "Invalid sample format\n" );
		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

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

	data->stream = ppa_stream_new( data->context, "Capture Stream", &data->spec, &chanmap );

	if ( !data->stream )
	{
		AL_PRINT( "pa_stream_new() failed: %s\n",
		          ppa_strerror( ppa_context_errno( data->context ) ) );

		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

	ppa_stream_set_state_callback( data->stream, stream_state_callback, data->loop );

	flags |= PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY;

	if ( ppa_stream_connect_record( data->stream, pulse_name, &data->attr, flags ) < 0 )
	{
		AL_PRINT( "Stream did not connect: %s\n",
		          ppa_strerror( ppa_context_errno( data->context ) ) );

		ppa_stream_unref( data->stream );
		data->stream = NULL;

		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

	while ( ( state = ppa_stream_get_state( data->stream ) ) != PA_STREAM_READY )
	{
		if ( !PA_STREAM_IS_GOOD( state ) )
		{
			AL_PRINT( "Stream did not get ready: %s\n",
			          ppa_strerror( ppa_context_errno( data->context ) ) );

			ppa_stream_unref( data->stream );
			data->stream = NULL;

			ppa_threaded_mainloop_unlock( data->loop );
			goto fail;
		}

		ppa_threaded_mainloop_wait( data->loop );
	}

	ppa_stream_set_state_callback( data->stream, stream_state_callback2, device );

	ppa_threaded_mainloop_unlock( data->loop );
	return ALC_TRUE;

fail:
	pulse_close( device );
	return ALC_FALSE;
} //}}}
Пример #10
0
static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    pa_stream_flags_t flags = 0;
    pa_stream_state_t state;
    pa_channel_map chanmap;

    ppa_threaded_mainloop_lock(data->loop);

    if(!ConfigValueExists(NULL, "format"))
    {
        pa_operation *o;
        struct {
            pa_threaded_mainloop *loop;
            char *name;
        } server_data;
        server_data.loop = data->loop;
        server_data.name = NULL;

        o = ppa_context_get_server_info(data->context, server_info_callback, &server_data);
        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
            ppa_threaded_mainloop_wait(data->loop);
        ppa_operation_unref(o);
        if(server_data.name)
        {
            o = ppa_context_get_sink_info_by_name(data->context, server_data.name, sink_info_callback, device);
            while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
                ppa_threaded_mainloop_wait(data->loop);
            ppa_operation_unref(o);
            free(server_data.name);
        }
    }
    if(!ConfigValueExists(NULL, "frequency"))
        flags |= PA_STREAM_FIX_RATE;

    data->frame_size = aluBytesFromFormat(device->Format) *
                       aluChannelsFromFormat(device->Format);
    data->stream_name = "Playback Stream";
    data->attr.minreq = -1;
    data->attr.prebuf = -1;
    data->attr.fragsize = -1;
    data->attr.tlength = device->UpdateSize * device->NumUpdates *
                         data->frame_size;
    data->attr.maxlength = data->attr.tlength;

    switch(aluBytesFromFormat(device->Format))
    {
        case 1:
            data->spec.format = PA_SAMPLE_U8;
            break;
        case 2:
            data->spec.format = PA_SAMPLE_S16NE;
            break;
        case 4:
            data->spec.format = PA_SAMPLE_FLOAT32NE;
            break;
        default:
            AL_PRINT("Unknown format: 0x%x\n", device->Format);
            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
    }
    data->spec.rate = device->Frequency;
    data->spec.channels = aluChannelsFromFormat(device->Format);

    if(ppa_sample_spec_valid(&data->spec) == 0)
    {
        AL_PRINT("Invalid sample format\n");
        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

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

    data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, &chanmap);
    if(!data->stream)
    {
        AL_PRINT("pa_stream_new() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    ppa_stream_set_state_callback(data->stream, stream_state_callback, device);

    if(ppa_stream_connect_playback(data->stream, NULL, &data->attr, flags, NULL, NULL) < 0)
    {
        AL_PRINT("Stream did not connect: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_stream_unref(data->stream);
        data->stream = NULL;

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
    {
        if(!PA_STREAM_IS_GOOD(state))
        {
            AL_PRINT("Stream did not get ready: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));

            ppa_stream_unref(data->stream);
            data->stream = NULL;

            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
        }

        ppa_threaded_mainloop_wait(data->loop);
    }
    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);

    data->spec = *(ppa_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. */
        data->attr.tlength = (ALuint64)(data->attr.tlength/data->frame_size) *
                             data->spec.rate / device->Frequency * data->frame_size;
        data->attr.maxlength = data->attr.tlength;

        o = ppa_stream_set_buffer_attr(data->stream, &data->attr,
                                       stream_success_callback, device);
        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
            ppa_threaded_mainloop_wait(data->loop);
        ppa_operation_unref(o);

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

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

    stream_write_callback(data->stream, data->attr.tlength, device);
    ppa_stream_set_write_callback(data->stream, stream_write_callback, device);

    ppa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;
} //}}}
Пример #11
0
static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    pa_stream_state_t state;
    pa_channel_map chanmap;

    ppa_threaded_mainloop_lock(data->loop);

    data->frame_size = aluBytesFromFormat(device->Format) *
                       aluChannelsFromFormat(device->Format);
    data->attr.minreq = data->frame_size * device->UpdateSize;
    data->attr.prebuf = -1;
    data->attr.maxlength = -1;
    data->attr.fragsize = -1;
    data->attr.tlength = data->attr.minreq * device->NumUpdates;
    data->stream_name = "Playback Stream";

    switch(aluBytesFromFormat(device->Format))
    {
        case 1:
            data->spec.format = PA_SAMPLE_U8;
            break;
        case 2:
            data->spec.format = PA_SAMPLE_S16NE;
            break;
        case 4:
            data->spec.format = PA_SAMPLE_FLOAT32NE;
            break;
        default:
            AL_PRINT("Unknown format: 0x%x\n", device->Format);
            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
    }
    data->spec.rate = device->Frequency;
    data->spec.channels = aluChannelsFromFormat(device->Format);

    if(ppa_sample_spec_valid(&data->spec) == 0)
    {
        AL_PRINT("Invalid sample format\n");
        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

#ifdef _WIN32
    if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
    {
        AL_PRINT("Couldn't build map for channel count (%d)!", data->spec.channels);
        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }
#else
    switch(data->spec.channels)
    {
    case 1:
        ppa_channel_map_parse(&chanmap, "mono");
        break;
    case 2:
        ppa_channel_map_parse(&chanmap, "front-left,front-right");
        break;
    case 4:
        ppa_channel_map_parse(&chanmap, "front-left,front-right,rear-left,rear-right");
        break;
    case 6:
        ppa_channel_map_parse(&chanmap, "front-left,front-right,rear-left,rear-right,front-center,lfe");
        break;
    case 7:
        ppa_channel_map_parse(&chanmap, "front-left,front-right,front-center,lfe,rear-center,side-left,side-right");
        break;
    case 8:
        ppa_channel_map_parse(&chanmap, "front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right");
        break;
    default:
        AL_PRINT("Got unhandled channel count (%d)!", data->spec.channels);
        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }
#endif

    data->stream = ppa_stream_new(data->context, data->stream_name, &data->spec, &chanmap);
    if(!data->stream)
    {
        AL_PRINT("pa_stream_new() failed: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    ppa_stream_set_state_callback(data->stream, stream_state_callback, device);
    ppa_stream_set_write_callback(data->stream, stream_write_callback, device);

    if(ppa_stream_connect_playback(data->stream, NULL, &data->attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0)
    {
        AL_PRINT("Stream did not connect: %s\n",
                 ppa_strerror(ppa_context_errno(data->context)));

        ppa_stream_unref(data->stream);
        data->stream = NULL;

        ppa_threaded_mainloop_unlock(data->loop);
        return ALC_FALSE;
    }

    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
    {
        if(!PA_STREAM_IS_GOOD(state))
        {
            AL_PRINT("Stream did not get ready: %s\n",
                     ppa_strerror(ppa_context_errno(data->context)));

            ppa_stream_unref(data->stream);
            data->stream = NULL;

            ppa_threaded_mainloop_unlock(data->loop);
            return ALC_FALSE;
        }

        ppa_threaded_mainloop_wait(data->loop);
        ppa_threaded_mainloop_accept(data->loop);
    }
    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);

    stream_buffer_attr_callback(data->stream, device);
    ppa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);

    ppa_threaded_mainloop_unlock(data->loop);
    return ALC_TRUE;
} //}}}