Beispiel #1
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);
} //}}}
Beispiel #2
0
static void pulse_close(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;

    ppa_threaded_mainloop_lock(data->loop);

    if(data->stream)
    {
        ppa_stream_disconnect(data->stream);
        ppa_stream_unref(data->stream);
    }

    ppa_context_disconnect(data->context);
    ppa_context_unref(data->context);

    ppa_threaded_mainloop_unlock(data->loop);

    ppa_threaded_mainloop_stop(data->loop);
    ppa_threaded_mainloop_free(data->loop);

    device->ExtraData = NULL;
    free(device->szDeviceName);
    device->szDeviceName = NULL;
    DestroyRingBuffer(data->ring);

    ppa_xfree(data);
} //}}}
static void pulse_stop_playback( ALCdevice* device ) //{{{
{
	pulse_data* data = device->ExtraData;

	if ( !data->stream )
	{
		return;
	}

	ppa_threaded_mainloop_lock( data->loop );

#if PA_CHECK_VERSION(0,9,15)

	if ( ppa_stream_set_buffer_attr_callback )
	{
		ppa_stream_set_buffer_attr_callback( data->stream, NULL, NULL );
	}

#endif
	ppa_stream_set_moved_callback( data->stream, NULL, NULL );
	ppa_stream_set_write_callback( data->stream, NULL, NULL );
	ppa_stream_disconnect( data->stream );
	ppa_stream_unref( data->stream );
	data->stream = NULL;

	ppa_threaded_mainloop_unlock( data->loop );
} //}}}
static void probe_devices( ALboolean capture )
{
	pa_threaded_mainloop* loop;

	if ( capture == AL_FALSE )
	{
		allDevNameMap = malloc( sizeof( DevMap ) * 1 );
		allDevNameMap[0].name = strdup( "PulseAudio Default" );
		allDevNameMap[0].device_name = NULL;
		numDevNames = 1;
	}
	else
	{
		allCaptureDevNameMap = malloc( sizeof( DevMap ) * 1 );
		allCaptureDevNameMap[0].name = strdup( "PulseAudio Default" );
		allCaptureDevNameMap[0].device_name = NULL;
		numCaptureDevNames = 1;
	}

	if ( ( loop = ppa_threaded_mainloop_new() ) &&
	     ppa_threaded_mainloop_start( loop ) >= 0 )
	{
		pa_context* context;

		ppa_threaded_mainloop_lock( loop );
		context = connect_context( loop );

		if ( context )
		{
			pa_operation* o;

			if ( capture == AL_FALSE )
			{
				o = ppa_context_get_sink_info_list( context, sink_device_callback, loop );
			}
			else
			{
				o = ppa_context_get_source_info_list( context, source_device_callback, loop );
			}

			while ( ppa_operation_get_state( o ) == PA_OPERATION_RUNNING )
			{
				ppa_threaded_mainloop_wait( loop );
			}

			ppa_operation_unref( o );

			ppa_context_disconnect( context );
			ppa_context_unref( context );
		}

		ppa_threaded_mainloop_unlock( loop );
		ppa_threaded_mainloop_stop( loop );
	}

	if ( loop )
	{
		ppa_threaded_mainloop_free( loop );
	}
}
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 );
} //}}}
static ALCboolean pulse_open( ALCdevice* device, const ALCchar* device_name ) //{{{
{
	pulse_data* data = ppa_xmalloc( sizeof( pulse_data ) );
	memset( data, 0, sizeof( *data ) );

	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 );
	device->ExtraData = data;

	data->context = connect_context( data->loop );

	if ( !data->context )
	{
		ppa_threaded_mainloop_unlock( data->loop );
		goto out;
	}

	ppa_context_set_state_callback( data->context, context_state_callback2, device );

	device->szDeviceName = strdup( device_name );

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

	device->ExtraData = NULL;
	ppa_xfree( data );
	return ALC_FALSE;
} //}}}
Beispiel #7
0
static void pulse_stop_capture(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;

    ppa_threaded_mainloop_lock(data->loop);
    ppa_stream_set_read_callback(data->stream, NULL, NULL);
    ppa_threaded_mainloop_unlock(data->loop);
} //}}}
Beispiel #8
0
static void pulse_stop_capture(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    pa_operation *o;

    ppa_threaded_mainloop_lock(data->loop);
    o = ppa_stream_cork(data->stream, 1, stream_success_callback, device);
    while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
        ppa_threaded_mainloop_wait(data->loop);
    ppa_operation_unref(o);
    ppa_threaded_mainloop_unlock(data->loop);
} //}}}
Beispiel #9
0
static ALCuint pulse_available_samples(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    ALCuint ret;

    ppa_threaded_mainloop_lock(data->loop);
    ret  = RingBufferSize(data->ring);
    ret += ppa_stream_readable_size(data->stream)/data->frame_size;
    ppa_threaded_mainloop_unlock(data->loop);

    return ret;
} //}}}
Beispiel #10
0
static void pulse_stop_playback(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;

    if(!data->stream)
        return;

    ppa_threaded_mainloop_lock(data->loop);

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

    ppa_threaded_mainloop_unlock(data->loop);
} //}}}
Beispiel #11
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;
} //}}}
Beispiel #12
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_reset_playback( ALCdevice* device ) //{{{
{
	pulse_data* data = device->ExtraData;
	pa_stream_flags_t flags = 0;
	pa_channel_map chanmap;

	ppa_threaded_mainloop_lock( data->loop );

	if ( !ConfigValueExists( NULL, "format" ) )
	{
		pa_operation* o;
		o = ppa_context_get_sink_info_by_name( data->context, data->device_name, sink_info_callback, device );

		while ( ppa_operation_get_state( o ) == PA_OPERATION_RUNNING )
		{
			ppa_threaded_mainloop_wait( data->loop );
		}

		ppa_operation_unref( o );
	}

	if ( !ConfigValueExists( NULL, "frequency" ) )
	{
		flags |= PA_STREAM_FIX_RATE;
	}

	data->frame_size = aluFrameSizeFromFormat( device->Format );
	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 = connect_playback_stream( device, flags, &data->attr, &data->spec, &chanmap );

	if ( !data->stream )
	{
		ppa_threaded_mainloop_unlock( data->loop );
		return ALC_FALSE;
	}

	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
	ppa_stream_set_moved_callback( data->stream, stream_device_callback, device );

	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;
} //}}}
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;
} //}}}
Beispiel #15
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;
} //}}}
// OpenAL {{{
static ALCboolean pulse_open_playback( ALCdevice* device, const ALCchar* device_name ) //{{{
{
	char* pulse_name = NULL;
	pa_sample_spec spec;
	pulse_data* data;
	ALuint len;

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

	if ( !device_name )
	{
		device_name = pulse_device;
	}
	else if ( strcmp( device_name, pulse_device ) != 0 )
	{
		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_FALSE;
		}
	}

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

	data = device->ExtraData;

	ppa_threaded_mainloop_lock( data->loop );

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

	data->device_name = pulse_name;
	pa_stream* stream = connect_playback_stream( device, 0, NULL, &spec, NULL );

	if ( !stream )
	{
		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

	if ( ppa_stream_is_suspended( stream ) )
	{
		ppa_stream_disconnect( stream );
		ppa_stream_unref( stream );
		ppa_threaded_mainloop_unlock( data->loop );
		goto fail;
	}

	data->device_name = strdup( ppa_stream_get_device_name( stream ) );

	ppa_stream_disconnect( stream );
	ppa_stream_unref( stream );

	ppa_threaded_mainloop_unlock( data->loop );

	len = GetConfigValueInt( "pulse", "buffer-length", 2048 );

	if ( len != 0 )
	{
		device->UpdateSize = len;
		device->NumUpdates = 1;
	}

	return ALC_TRUE;

fail:
	pulse_close( device );
	return ALC_FALSE;
} //}}}
Beispiel #17
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;
} //}}}