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    Carsten Griwodz
2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    griff@kom.tu-darmstadt.de
2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    based on linux/SDL_dspaudio.c by Sam Lantinga
2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/
2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h"
2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Allow access to a raw mixing buffer */
2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <errno.h>
2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <unistd.h>
3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <fcntl.h>
3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/time.h>
3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/ioctl.h>
3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/stat.h>
3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_timer.h"
3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_audio.h"
3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audiomem.h"
3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audio_c.h"
3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_audiodev_c.h"
4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_paudio.h"
4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define DEBUG_AUDIO 1
4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * I guess nobody ever uses audio... Shame over AIX header files.  */
4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/machine.h>
4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#undef BIG_ENDIAN
4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sys/audio.h>
4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* The tag name used by paud audio */
5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define Paud_DRIVER_NAME         "paud"
5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Open the audio device for playback, and don't block if busy */
5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* #define OPEN_FLAGS	(O_WRONLY|O_NONBLOCK) */
5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define OPEN_FLAGS	O_WRONLY
5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Audio driver functions */
5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec);
5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_WaitAudio(_THIS);
6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_PlayAudio(_THIS);
6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic Uint8 *Paud_GetAudioBuf(_THIS);
6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_CloseAudio(_THIS);
6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Audio driver bootstrap functions */
6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int Audio_Available(void)
6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int fd;
6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int available;
7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	available = 0;
7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( fd >= 0 ) {
7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		available = 1;
7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		close(fd);
7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return(available);
7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Audio_DeleteDevice(SDL_AudioDevice *device)
8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_free(device->hidden);
8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_free(device);
8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic SDL_AudioDevice *Audio_CreateDevice(int devindex)
8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_AudioDevice *this;
8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Initialize all variables that we clean on shutdown */
9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( this ) {
9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_memset(this, 0, (sizeof *this));
9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		this->hidden = (struct SDL_PrivateAudioData *)
9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				SDL_malloc((sizeof *this->hidden));
9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( (this == NULL) || (this->hidden == NULL) ) {
9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_OutOfMemory();
9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( this ) {
10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_free(this);
10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return(0);
10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_memset(this->hidden, 0, (sizeof *this->hidden));
10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_fd = -1;
10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Set the function pointers */
10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->OpenAudio = Paud_OpenAudio;
10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->WaitAudio = Paud_WaitAudio;
11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->PlayAudio = Paud_PlayAudio;
11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->GetAudioBuf = Paud_GetAudioBuf;
11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->CloseAudio = Paud_CloseAudio;
11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	this->free = Audio_DeleteDevice;
11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return this;
11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
11946be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerAudioBootStrap Paud_bootstrap = {
12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Paud_DRIVER_NAME, "AIX Paudio",
12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Audio_Available, Audio_CreateDevice
12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner};
12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* This function waits until it is possible to write a full sound buffer */
12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_WaitAudio(_THIS)
12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    fd_set fdset;
12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    /* See if we need to use timed audio synchronization */
13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    if ( frame_ticks ) {
13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        /* Use timer for general audio synchronization */
13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        Sint32 ticks;
13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        if ( ticks > 0 ) {
13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    SDL_Delay(ticks);
13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        }
13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    } else {
13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        audio_buffer  paud_bufinfo;
14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        /* Use select() for audio synchronization */
14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        struct timeval timeout;
14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        FD_ZERO(&fdset);
14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        FD_SET(audio_fd, &fdset);
14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "Couldn't get audio buffer information\n");
14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            timeout.tv_sec  = 10;
15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            timeout.tv_usec = 0;
15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        } else {
15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    long ms_in_buf = paud_bufinfo.write_buf_time;
15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            timeout.tv_sec  = ms_in_buf/1000;
15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    ms_in_buf       = ms_in_buf - timeout.tv_sec*1000;
15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            timeout.tv_usec = ms_in_buf*1000;
15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf( stderr,
15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		     "Waiting for write_buf_time=%ld,%ld\n",
16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		     timeout.tv_sec,
16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		     timeout.tv_usec );
16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        fprintf(stderr, "Waiting for audio to get ready\n");
16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
16846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            const char *message = "Audio timeout - buggy audio driver? (disabled)";
17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            /*
17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	     * In general we should never print to the screen,
17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner             * but in this case we have no other way of letting
17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner             * the user know what happened.
17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner             */
17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            this->enabled = 0;
17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            /* Don't try to close - may hang */
17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            audio_fd = -1;
17946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "Done disabling audio\n");
18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        }
18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        fprintf(stderr, "Ready!\n");
18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner    }
18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_PlayAudio(_THIS)
19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int written;
19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Write the audio data, checking for EAGAIN on broken audio drivers */
19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	do {
19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		written = write(audio_fd, mixbuf, mixlen);
19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			SDL_Delay(1);	/* Let a little CPU time go by */
19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	} while ( (written < 0) &&
20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	          ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* If timer synchronization is enabled, set the next write frame */
20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( frame_ticks ) {
20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		next_frame += frame_ticks;
20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* If we couldn't write, assume fatal error for now */
20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( written < 0 ) {
20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		this->enabled = 0;
21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	fprintf(stderr, "Wrote %d bytes of audio data\n", written);
21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic Uint8 *Paud_GetAudioBuf(_THIS)
21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return mixbuf;
21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void Paud_CloseAudio(_THIS)
22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( mixbuf != NULL ) {
22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_FreeAudioMem(mixbuf);
22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		mixbuf = NULL;
22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( audio_fd >= 0 ) {
22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		close(audio_fd);
22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		audio_fd = -1;
23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec)
23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{
23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	char          audiodev[1024];
23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int           format;
23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	int           bytes_per_sample;
23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	Uint16        test_format;
23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_init    paud_init;
24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_buffer  paud_bufinfo;
24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_status  paud_status;
24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_control paud_control;
24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_change  paud_change;
24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Reset the timer synchronization flag */
24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	frame_ticks = 0.0;
24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Open the audio device */
24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( audio_fd < 0 ) {
25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * We can't set the buffer size - just ask the device for the maximum
25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * that we can have.
25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't get audio buffer information");
26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	mixbuf = NULL;
26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( spec->channels > 1 )
26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    spec->channels = 2;
26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	else
26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    spec->channels = 1;
27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Fields in the audio_init structure:
27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Ignored by us:
27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.slot_number;         * slot number of the adapter
27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.device_id;           * adapter identification number
27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Input:
28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.srate;           * the sampling rate in Hz
28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.bits_per_sample; * 8, 16, 32, ...
28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.bsize;           * block size for this rate
28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.mode;            * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.channels;        * 1=mono, 2=stereo
28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.flags;           * FIXED - fixed length data
28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * TWOS_COMPLEMENT - 2's complement data
29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * SIGNED - signed? comment seems wrong in sys/audio.h
29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * BIG_ENDIAN
29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.operation;       * PLAY, RECORD
29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Output:
29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.flags;           * PITCH            - pitch is supported
29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * INPUT            - input is supported
29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * OUTPUT           - output is supported
29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * MONITOR          - monitor is supported
30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * VOLUME           - volume is supported
30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * VOLUME_DELAY     - volume delay is supported
30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * BALANCE          - balance is supported
30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * BALANCE_DELAY    - balance delay is supported
30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * TREBLE           - treble control is supported
30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * BASS             - bass control is supported
30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * BESTFIT_PROVIDED - best fit returned
30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * LOAD_CODE        - DSP load needed
30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.rc;              * NO_PLAY         - DSP code can't do play requests
30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * NO_RECORD       - DSP code can't do record requests
31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * INVALID_REQUEST - request was invalid
31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * CONFLICT        - conflict with open's flags
31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *                       * OVERLOADED      - out of DSP MIPS or memory
31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * paud.position_resolution; * smallest increment for position
31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_init.srate = spec->freq;
31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_init.mode = PCM;
31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_init.operation = PLAY;
31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_init.channels = spec->channels;
32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Try for a closest match on audio format */
32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	format = 0;
32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	for ( test_format = SDL_FirstAudioFormat(spec->format);
32446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner						! format && test_format; ) {
32546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
32646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
32746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
32846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		switch ( test_format ) {
32946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_U8:
33046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 1;
33146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 8;
33246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = TWOS_COMPLEMENT | FIXED;
33346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
33446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
33546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_S8:
33646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 1;
33746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 8;
33846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = SIGNED |
33946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					      TWOS_COMPLEMENT | FIXED;
34046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
34146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
34246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_S16LSB:
34346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 2;
34446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 16;
34546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = SIGNED |
34646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					      TWOS_COMPLEMENT | FIXED;
34746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
34846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
34946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_S16MSB:
35046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 2;
35146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 16;
35246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = BIG_ENDIAN |
35346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					      SIGNED |
35446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					      TWOS_COMPLEMENT | FIXED;
35546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
35646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
35746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_U16LSB:
35846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 2;
35946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 16;
36046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = TWOS_COMPLEMENT | FIXED;
36146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
36246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
36346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			case AUDIO_U16MSB:
36446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    bytes_per_sample = 2;
36546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.bits_per_sample = 16;
36646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    paud_init.flags = BIG_ENDIAN |
36746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner					      TWOS_COMPLEMENT | FIXED;
36846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    format = 1;
36946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			    break;
37046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			default:
37146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner				break;
37246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
37346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		if ( ! format ) {
37446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			test_format = SDL_NextAudioFormat();
37546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		}
37646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
37746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( format == 0 ) {
37846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
37946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "Couldn't find any hardware audio formats\n");
38046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
38146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    SDL_SetError("Couldn't find any hardware audio formats");
38246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    return -1;
38346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
38446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	spec->format = test_format;
38546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
38646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
38746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * We know the buffer size and the max number of subsequent writes
38846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * that can be pending. If more than one can pend, allow the application
38946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * to do something like double buffering between our write buffer and
39046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * the device's own buffer that we are filling with write() anyway.
39146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
39246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * We calculate spec->samples like this because SDL_CalculateAudioSpec()
39346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
39446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * into spec->size in return.
39546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
39646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( paud_bufinfo.request_buf_cap == 1 )
39746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{
39846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    spec->samples = paud_bufinfo.write_buf_cap
39946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  / bytes_per_sample
40046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  / spec->channels;
40146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
40246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	else
40346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	{
40446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    spec->samples = paud_bufinfo.write_buf_cap
40546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  / bytes_per_sample
40646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  / spec->channels
40746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner			  / 2;
40846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
40946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_init.bsize = bytes_per_sample * spec->channels;
41046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
41146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_CalculateAudioSpec(spec);
41246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
41346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
41446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * The AIX paud device init can't modify the values of the audio_init
41546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * structure that we pass to it. So we don't need any recalculation
41646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * of this stuff and no reinit call as in linux dsp and dma code.
41746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 *
41846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * /dev/paud supports all of the encoding formats, so we don't need
41946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * to do anything like reopening the device, either.
42046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
42146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 ) {
42246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    switch ( paud_init.rc )
42346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    {
42446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case 1 :
42546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: DSP can't do play requests");
42646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
42746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
42846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case 2 :
42946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: DSP can't do record requests");
43046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
43146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
43246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case 4 :
43346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: request was invalid");
43446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
43546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
43646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case 5 :
43746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: conflict with open's flags");
43846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
43946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
44046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    case 6 :
44146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: out of DSP MIPS or memory");
44246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
44346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
44446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    default :
44546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		SDL_SetError("Couldn't set audio format: not documented in sys/audio.h");
44646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
44746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		break;
44846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    }
44946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
45046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
45146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Allocate mixing buffer */
45246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	mixlen = spec->size;
45346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
45446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( mixbuf == NULL ) {
45546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner		return -1;
45646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
45746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	SDL_memset(mixbuf, spec->silence, spec->size);
45846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
45946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
46046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Set some paramters: full volume, first speaker that we can find.
46146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Ignore the other settings for now.
46246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
46346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_change.input = AUDIO_IGNORE;         /* the new input source */
46446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.output = OUTPUT_1;            /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
46546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.monitor = AUDIO_IGNORE;       /* the new monitor state */
46646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.volume = 0x7fffffff;          /* volume level [0-0x7fffffff] */
46746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.volume_delay = AUDIO_IGNORE;  /* the new volume delay */
46846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.balance = 0x3fffffff;         /* the new balance */
46946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
47046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.treble = AUDIO_IGNORE;        /* the new treble state */
47146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.bass = AUDIO_IGNORE;          /* the new bass state */
47246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        paud_change.pitch = AUDIO_IGNORE;         /* the new pitch state */
47346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
47446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_control.ioctl_request = AUDIO_CHANGE;
47546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_control.request_info = (char*)&paud_change;
47646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
47746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
47846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "Can't change audio display settings\n" );
47946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
48046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
48146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
48246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/*
48346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * Tell the device to expect data. Actual start will wait for
48446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 * the first write() call.
48546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	 */
48646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_control.ioctl_request = AUDIO_START;
48746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	paud_control.position = 0;
48846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
48946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef DEBUG_AUDIO
49046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner            fprintf(stderr, "Can't start audio play\n" );
49146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif
49246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    SDL_SetError("Can't start audio play");
49346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	    return -1;
49446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	}
49546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
49646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        /* Check to see if we need to use select() workaround */
49746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        { char *workaround;
49846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                workaround = SDL_getenv("SDL_DSP_NOSELECT");
49946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                if ( workaround ) {
50046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                        frame_ticks = (float)(spec->samples*1000)/spec->freq;
50146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                        next_frame = SDL_GetTicks()+frame_ticks;
50246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner                }
50346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner        }
50446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
50546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* Get the parent process id (we're the parent of the audio thread) */
50646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	parent = getpid();
50746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
50846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	/* We're ready to rock and roll. :-) */
50946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner	return 0;
51046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}
51146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner
512