146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/*
246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    SDL - Simple DirectMedia Layer
346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Copyright (C) 1997-2006 Sam Lantinga
446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is free software; you can redistribute it and/or
646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    modify it under the terms of the GNU Lesser General Public
746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License as published by the Free Software Foundation; either
846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    version 2.1 of the License, or (at your option) any later version.
946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    This library is distributed in the hope that it will be useful,
1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    but WITHOUT ANY WARRANTY; without even the implied warranty of
1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Lesser General Public License for more details.
1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    You should have received a copy of the GNU Lesser General Public
1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    License along with this library; if not, write to the Free Software
1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    Sam Lantinga
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    slouken@libsdl.org
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Allow access to an ESD network stream mixing buffer */
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/types.h>
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <unistd.h>
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <signal.h>
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <errno.h>
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <esd.h>
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_timer.h"
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_audio.h"
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audiomem.h"
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audio_c.h"
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audiodev_c.h"
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_esdaudio.h"
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_name.h"
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_loadso.h"
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define SDL_NAME(X)	X
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* The tag name used by ESD audio */
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ESD_DRIVER_NAME		"esd"
4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Audio driver functions */
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_WaitAudio(_THIS);
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_PlayAudio(_THIS);
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic Uint8 *ESD_GetAudioBuf(_THIS);
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_CloseAudio(_THIS);
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void *esd_handle = NULL;
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int esd_loaded = 0;
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int (*SDL_NAME(esd_open_sound))( const char *host );
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int (*SDL_NAME(esd_close))( int esd );
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate,
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                                         const char *host, const char *name );
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic struct {
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	const char *name;
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	void **func;
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} esd_functions[] = {
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{ "esd_open_sound",	(void **)&SDL_NAME(esd_open_sound)	},
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{ "esd_close",		(void **)&SDL_NAME(esd_close)		},
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{ "esd_play_stream",	(void **)&SDL_NAME(esd_play_stream)	},
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner};
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void UnloadESDLibrary()
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( esd_loaded ) {
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_UnloadObject(esd_handle);
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		esd_handle = NULL;
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		esd_loaded = 0;
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int LoadESDLibrary(void)
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int i, retval = -1;
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	esd_handle = SDL_LoadObject(esd_library);
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( esd_handle ) {
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		esd_loaded = 1;
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		retval = 0;
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		for ( i=0; i<SDL_arraysize(esd_functions); ++i ) {
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			*esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( !*esd_functions[i].func ) {
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				retval = -1;
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				UnloadESDLibrary();
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return retval;
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void UnloadESDLibrary()
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return;
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int LoadESDLibrary(void)
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return 0;
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Audio driver bootstrap functions */
11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int Audio_Available(void)
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int connection;
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int available;
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	available = 0;
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( LoadESDLibrary() < 0 ) {
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return available;
12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	connection = SDL_NAME(esd_open_sound)(NULL);
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( connection >= 0 ) {
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		available = 1;
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_NAME(esd_close)(connection);
13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	UnloadESDLibrary();
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(available);
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Audio_DeleteDevice(SDL_AudioDevice *device)
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_free(device->hidden);
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_free(device);
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	UnloadESDLibrary();
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic SDL_AudioDevice *Audio_CreateDevice(int devindex)
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_AudioDevice *this;
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Initialize all variables that we clean on shutdown */
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	LoadESDLibrary();
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( this ) {
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_memset(this, 0, (sizeof *this));
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		this->hidden = (struct SDL_PrivateAudioData *)
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_malloc((sizeof *this->hidden));
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( (this == NULL) || (this->hidden == NULL) ) {
15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_OutOfMemory();
15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( this ) {
16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_free(this);
16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return(0);
16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_fd = -1;
16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Set the function pointers */
16846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->OpenAudio = ESD_OpenAudio;
16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->WaitAudio = ESD_WaitAudio;
17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->PlayAudio = ESD_PlayAudio;
17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->GetAudioBuf = ESD_GetAudioBuf;
17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->CloseAudio = ESD_CloseAudio;
17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->free = Audio_DeleteDevice;
17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return this;
17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
17946be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerAudioBootStrap ESD_bootstrap = {
18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	ESD_DRIVER_NAME, "Enlightened Sound Daemon",
18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Audio_Available, Audio_CreateDevice
18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner};
18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* This function waits until it is possible to write a full sound buffer */
18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_WaitAudio(_THIS)
18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Sint32 ticks;
18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Check to see if the thread-parent process is still alive */
19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{ static int cnt = 0;
19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		/* Note that this only works with thread implementations
19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		   that use a different process id for each thread.
19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		*/
19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( kill(parent, 0) < 0 ) {
19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				this->enabled = 0;
19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Use timer for general audio synchronization */
20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ticks > 0 ) {
20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_Delay(ticks);
20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_PlayAudio(_THIS)
20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int written;
21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Write the audio data, checking for EAGAIN on broken audio drivers */
21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	do {
21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		written = write(audio_fd, mixbuf, mixlen);
21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Delay(1);	/* Let a little CPU time go by */
21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} while ( (written < 0) &&
21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	          ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Set the next write frame */
22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	next_frame += frame_ticks;
22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* If we couldn't write, assume fatal error for now */
22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( written < 0 ) {
22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		this->enabled = 0;
22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic Uint8 *ESD_GetAudioBuf(_THIS)
23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(mixbuf);
23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void ESD_CloseAudio(_THIS)
23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( mixbuf != NULL ) {
23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_FreeAudioMem(mixbuf);
23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		mixbuf = NULL;
24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( audio_fd >= 0 ) {
24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_NAME(esd_close)(audio_fd);
24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		audio_fd = -1;
24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Try to get the name of the program */
24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic char *get_progname(void)
24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	char *progname = NULL;
25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef __LINUX__
25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	FILE *fp;
25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	static char temp[BUFSIZ];
25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	fp = fopen(temp, "r");
25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( fp != NULL ) {
25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( fgets(temp, sizeof(temp)-1, fp) ) {
25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			progname = SDL_strrchr(temp, '/');
26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			if ( progname == NULL ) {
26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				progname = temp;
26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			} else {
26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				progname = progname+1;
26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			}
26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		fclose(fp);
26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(progname);
27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	esd_format_t format;
27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Convert audio spec to the ESD audio format */
27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	format = (ESD_STREAM | ESD_PLAY);
27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	switch ( spec->format & 0xFF ) {
27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 8:
28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			format |= ESD_BITS8;
28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		case 16:
28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			format |= ESD_BITS16;
28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			break;
28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		default:
28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_SetError("Unsupported ESD audio format");
28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			return(-1);
28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( spec->channels == 1 ) {
29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		format |= ESD_MONO;
29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} else {
29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		format |= ESD_STEREO;
29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if 0
29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	spec->samples = ESD_BUF_SIZE;	/* Darn, no way to change this yet */
29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Open a connection to the ESD audio server */
29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname());
30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( audio_fd < 0 ) {
30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't open ESD connection");
30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return(-1);
30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Calculate the final parameters for this audio specification */
30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_CalculateAudioSpec(spec);
30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	frame_ticks = (float)(spec->samples*1000)/spec->freq;
30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	next_frame = SDL_GetTicks()+frame_ticks;
30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Allocate mixing buffer */
31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	mixlen = spec->size;
31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( mixbuf == NULL ) {
31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return(-1);
31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_memset(mixbuf, spec->silence, spec->size);
31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Get the parent process id (we're the parent of the audio thread) */
31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	parent = getpid();
32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* We're ready to rock and roll. :-) */
32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(0);
32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
324