static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec) { Uint16 test_format; pa_sample_spec paspec; pa_buffer_attr paattr; pa_channel_map pacmap; paspec.format = PA_SAMPLE_INVALID; for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) { switch ( test_format ) { case AUDIO_U8: paspec.format = PA_SAMPLE_U8; break; case AUDIO_S16LSB: paspec.format = PA_SAMPLE_S16LE; break; case AUDIO_S16MSB: paspec.format = PA_SAMPLE_S16BE; break; } if ( paspec.format != PA_SAMPLE_INVALID ) break; } if (paspec.format == PA_SAMPLE_INVALID ) { SDL_SetError("Couldn't find any suitable audio formats"); return(-1); } spec->format = test_format; paspec.channels = spec->channels; paspec.rate = spec->freq; /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(spec); /* Allocate mixing buffer */ mixlen = spec->size; mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); if ( mixbuf == NULL ) { return(-1); } SDL_memset(mixbuf, spec->silence, spec->size); /* Reduced prebuffering compared to the defaults. */ paattr.tlength = mixlen; paattr.minreq = mixlen; paattr.fragsize = mixlen; paattr.prebuf = mixlen; paattr.maxlength = mixlen * 4; /* The SDL ALSA output hints us that we use Windows' channel mapping */ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */ SDL_NAME(pa_channel_map_init_auto)( &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX); /* Connect to the PulseAudio server */ stream = SDL_NAME(pa_simple_new)( SDL_getenv("PASERVER"), /* server */ get_progname(), /* application name */ PA_STREAM_PLAYBACK, /* playback mode */ SDL_getenv("PADEVICE"), /* device on the server */ "Simple DirectMedia Layer", /* stream description */ &paspec, /* sample format spec */ &pacmap, /* channel map */ &paattr, /* buffering attributes */ NULL /* error code */ ); if ( stream == NULL ) { PULSE_CloseAudio(this); SDL_SetError("Could not connect to PulseAudio"); return(-1); } /* Get the parent process id (we're the parent of the audio thread) */ parent = getpid(); return(0); }
static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec) { int state; Uint16 test_format; pa_sample_spec paspec; pa_buffer_attr paattr; pa_channel_map pacmap; pa_stream_flags_t flags = 0; paspec.format = PA_SAMPLE_INVALID; for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) { switch ( test_format ) { case AUDIO_U8: paspec.format = PA_SAMPLE_U8; break; case AUDIO_S16LSB: paspec.format = PA_SAMPLE_S16LE; break; case AUDIO_S16MSB: paspec.format = PA_SAMPLE_S16BE; break; } if ( paspec.format != PA_SAMPLE_INVALID ) break; test_format = SDL_NextAudioFormat(); } if (paspec.format == PA_SAMPLE_INVALID ) { SDL_SetError("Couldn't find any suitable audio formats"); return(-1); } spec->format = test_format; paspec.channels = spec->channels; paspec.rate = spec->freq; #ifdef PA_STREAM_ADJUST_LATENCY spec->samples /= 2; #endif SDL_CalculateAudioSpec(spec); mixlen = spec->size; mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); if ( mixbuf == NULL ) { return(-1); } SDL_memset(mixbuf, spec->silence, spec->size); #ifdef PA_STREAM_ADJUST_LATENCY paattr.tlength = mixlen * 4; paattr.prebuf = -1; paattr.maxlength = -1; paattr.minreq = mixlen; flags = PA_STREAM_ADJUST_LATENCY; #else paattr.tlength = mixlen*2; paattr.prebuf = mixlen*2; paattr.maxlength = mixlen*2; paattr.minreq = mixlen; #endif SDL_NAME(pa_channel_map_init_auto)( &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX); if (!(mainloop = SDL_NAME(pa_mainloop_new)())) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_new() failed"); return(-1); } if (this->hidden->caption == NULL) { char *title = NULL; SDL_WM_GetCaption(&title, NULL); PULSE_SetCaption(this, title); } mainloop_api = SDL_NAME(pa_mainloop_get_api)(mainloop); if (!(context = SDL_NAME(pa_context_new)(mainloop_api, this->hidden->caption))) { PULSE_CloseAudio(this); SDL_SetError("pa_context_new() failed"); return(-1); } if (SDL_NAME(pa_context_connect)(context, NULL, 0, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("Could not setup connection to PulseAudio"); return(-1); } do { if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_iterate() failed"); return(-1); } state = SDL_NAME(pa_context_get_state)(context); if (!PA_CONTEXT_IS_GOOD(state)) { PULSE_CloseAudio(this); SDL_SetError("Could not connect to PulseAudio"); return(-1); } } while (state != PA_CONTEXT_READY); stream = SDL_NAME(pa_stream_new)( context, "Simple DirectMedia Layer", &paspec, &pacmap ); if ( stream == NULL ) { PULSE_CloseAudio(this); SDL_SetError("Could not setup PulseAudio stream"); return(-1); } if (SDL_NAME(pa_stream_connect_playback)(stream, NULL, &paattr, flags, NULL, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("Could not connect PulseAudio stream"); return(-1); } do { if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_iterate() failed"); return(-1); } state = SDL_NAME(pa_stream_get_state)(stream); if (!PA_STREAM_IS_GOOD(state)) { PULSE_CloseAudio(this); SDL_SetError("Could not create to PulseAudio stream"); return(-1); } } while (state != PA_STREAM_READY); return(0); }
static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec) { int state; Uint16 test_format; pa_sample_spec paspec; pa_buffer_attr paattr; pa_channel_map pacmap; pa_stream_flags_t flags = 0; paspec.format = PA_SAMPLE_INVALID; for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) { switch ( test_format ) { case AUDIO_U8: paspec.format = PA_SAMPLE_U8; break; case AUDIO_S16LSB: paspec.format = PA_SAMPLE_S16LE; break; case AUDIO_S16MSB: paspec.format = PA_SAMPLE_S16BE; break; } if ( paspec.format != PA_SAMPLE_INVALID ) break; } if (paspec.format == PA_SAMPLE_INVALID ) { SDL_SetError("Couldn't find any suitable audio formats"); return(-1); } spec->format = test_format; paspec.channels = spec->channels; paspec.rate = spec->freq; /* Calculate the final parameters for this audio specification */ #ifdef PA_STREAM_ADJUST_LATENCY spec->samples /= 2; /* Mix in smaller chunck to avoid underruns */ #endif SDL_CalculateAudioSpec(spec); /* Allocate mixing buffer */ mixlen = spec->size; mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); if ( mixbuf == NULL ) { return(-1); } SDL_memset(mixbuf, spec->silence, spec->size); /* Reduced prebuffering compared to the defaults. */ #ifdef PA_STREAM_ADJUST_LATENCY paattr.tlength = mixlen * 4; /* 2x original requested bufsize */ paattr.prebuf = -1; paattr.maxlength = -1; paattr.minreq = mixlen; /* -1 can lead to pa_stream_writable_size() >= mixlen never becoming true */ flags = PA_STREAM_ADJUST_LATENCY; #else paattr.tlength = mixlen*2; paattr.prebuf = mixlen*2; paattr.maxlength = mixlen*2; paattr.minreq = mixlen; #endif /* The SDL ALSA output hints us that we use Windows' channel mapping */ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */ SDL_NAME(pa_channel_map_init_auto)( &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX); /* Set up a new main loop */ if (!(mainloop = SDL_NAME(pa_mainloop_new)())) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_new() failed"); return(-1); } mainloop_api = SDL_NAME(pa_mainloop_get_api)(mainloop); if (!(context = SDL_NAME(pa_context_new)(mainloop_api, get_progname()))) { PULSE_CloseAudio(this); SDL_SetError("pa_context_new() failed"); return(-1); } /* Connect to the PulseAudio server */ if (SDL_NAME(pa_context_connect)(context, NULL, 0, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("Could not setup connection to PulseAudio"); return(-1); } do { if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_iterate() failed"); return(-1); } state = SDL_NAME(pa_context_get_state)(context); if (!PA_CONTEXT_IS_GOOD(state)) { PULSE_CloseAudio(this); SDL_SetError("Could not connect to PulseAudio"); return(-1); } } while (state != PA_CONTEXT_READY); stream = SDL_NAME(pa_stream_new)( context, "Simple DirectMedia Layer", /* stream description */ &paspec, /* sample format spec */ &pacmap /* channel map */ ); if ( stream == NULL ) { PULSE_CloseAudio(this); SDL_SetError("Could not setup PulseAudio stream"); return(-1); } if (SDL_NAME(pa_stream_connect_playback)(stream, NULL, &paattr, flags, NULL, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("Could not connect PulseAudio stream"); return(-1); } do { if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) { PULSE_CloseAudio(this); SDL_SetError("pa_mainloop_iterate() failed"); return(-1); } state = SDL_NAME(pa_stream_get_state)(stream); if (!PA_STREAM_IS_GOOD(state)) { PULSE_CloseAudio(this); SDL_SetError("Could not create to PulseAudio stream"); return(-1); } } while (state != PA_STREAM_READY); return(0); }