src/audio/nto/SDL_nto_audio.c
author Sam Lantinga
Sun, 16 Jun 2002 04:17:57 +0000
changeset 418 337f3ec4c385
parent 297 f6ffac90895c
child 424 b82518082828
permissions -rw-r--r--
Updated the QNX audio code for QNX 6.2 (thanks Travis!)
slouken@418
     1
Date: Sun, 16 Jun 2002 00:59:13 -0300
slouken@418
     2
From: Travis <smallfri@bigfoot.com>
slouken@418
     3
To: slouken@libsdl.org
slouken@418
     4
Subject: NTO Audio Fixes
slouken@418
     5
slouken@0
     6
/*
slouken@0
     7
    SDL - Simple DirectMedia Layer
slouken@297
     8
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
slouken@0
     9
slouken@0
    10
    This library is free software; you can redistribute it and/or
slouken@0
    11
    modify it under the terms of the GNU Library General Public
slouken@0
    12
    License as published by the Free Software Foundation; either
slouken@0
    13
    version 2 of the License, or (at your option) any later version.
slouken@0
    14
slouken@0
    15
    This library is distributed in the hope that it will be useful,
slouken@0
    16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    18
    Library General Public License for more details.
slouken@0
    19
slouken@0
    20
    You should have received a copy of the GNU Library General Public
slouken@0
    21
    License along with this library; if not, write to the Free
slouken@0
    22
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    23
slouken@0
    24
    Sam Lantinga
slouken@252
    25
    slouken@libsdl.org
slouken@0
    26
*/
slouken@0
    27
slouken@0
    28
#include <stdlib.h>
slouken@0
    29
#include <stdio.h>
slouken@0
    30
#include <string.h>
slouken@0
    31
#include <errno.h>
slouken@0
    32
#include <unistd.h>
slouken@0
    33
#include <fcntl.h>
slouken@0
    34
#include <signal.h>
slouken@0
    35
#include <sys/types.h>
slouken@0
    36
#include <sys/time.h>
slouken@0
    37
#include <sched.h>
slouken@0
    38
#include <sys/asoundlib.h>
slouken@418
    39
#include <sys/select.h>
slouken@0
    40
slouken@0
    41
#include "SDL_audio.h"
slouken@0
    42
#include "SDL_error.h"
slouken@0
    43
#include "SDL_audiomem.h"
slouken@0
    44
#include "SDL_audio_c.h"
slouken@0
    45
#include "SDL_timer.h"
slouken@0
    46
#include "SDL_nto_audio.h"
slouken@0
    47
slouken@0
    48
/* The tag name used by NTO audio */
slouken@0
    49
#define DRIVER_NAME         "nto"
slouken@0
    50
slouken@0
    51
/* default channel communication parameters */
slouken@0
    52
#define DEFAULT_CPARAMS_RATE 22050
slouken@0
    53
#define DEFAULT_CPARAMS_VOICES 1
slouken@418
    54
#define DEFAULT_CPARAMS_FRAG_SIZE 4096
slouken@0
    55
#define DEFAULT_CPARAMS_FRAGS_MIN 1
slouken@283
    56
#define DEFAULT_CPARAMS_FRAGS_MAX 1
slouken@0
    57
slouken@0
    58
/* Open the audio device for playback, and don't block if busy */
slouken@418
    59
#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
slouken@0
    60
slouken@0
    61
/* Audio driver functions */
slouken@0
    62
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec);
slouken@0
    63
static void NTO_WaitAudio(_THIS);
slouken@0
    64
static void NTO_PlayAudio(_THIS);
slouken@0
    65
static Uint8 *NTO_GetAudioBuf(_THIS);
slouken@0
    66
static void NTO_CloseAudio(_THIS);
slouken@0
    67
slouken@0
    68
static snd_pcm_channel_status_t cstatus;
slouken@418
    69
static snd_pcm_channel_params_t cparams;
slouken@418
    70
static snd_pcm_channel_setup_t  csetup;
slouken@0
    71
slouken@0
    72
/* PCM transfer channel parameters initialize function */
slouken@0
    73
static void init_pcm_cparams(snd_pcm_channel_params_t* cparams)
slouken@0
    74
{
slouken@0
    75
	memset(cparams,0,sizeof(snd_pcm_channel_params_t));
slouken@0
    76
slouken@0
    77
	cparams->channel = SND_PCM_CHANNEL_PLAYBACK;
slouken@0
    78
	cparams->mode = SND_PCM_MODE_BLOCK;
slouken@418
    79
	cparams->start_mode = SND_PCM_START_DATA;
slouken@0
    80
	cparams->stop_mode  = SND_PCM_STOP_STOP;
slouken@0
    81
	cparams->format.format = SND_PCM_SFMT_S16_LE;
slouken@0
    82
	cparams->format.interleave = 1;
slouken@0
    83
	cparams->format.rate = DEFAULT_CPARAMS_RATE;
slouken@0
    84
	cparams->format.voices = DEFAULT_CPARAMS_VOICES;
slouken@0
    85
	cparams->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
slouken@0
    86
	cparams->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
slouken@0
    87
	cparams->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
slouken@0
    88
}
slouken@0
    89
slouken@418
    90
static int Audio_Available(void)
slouken@418
    91
{
slouken@418
    92
	/*
slouken@418
    93
		See if we can open a nonblocking channel.
slouken@418
    94
		Return value '1' means we can.
slouken@418
    95
		Return value '0' means we cannot.
slouken@418
    96
	*/
slouken@0
    97
slouken@0
    98
	int available;
slouken@0
    99
	int rval;
slouken@0
   100
	snd_pcm_t *handle;
slouken@0
   101
slouken@0
   102
	available = 0;
slouken@0
   103
	handle = NULL;
slouken@0
   104
slouken@418
   105
	rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
slouken@0
   106
slouken@418
   107
	if (rval >= 0){
slouken@418
   108
		available = 1;
slouken@418
   109
		
slouken@418
   110
		if ((rval = snd_pcm_close(handle)) < 0){
slouken@418
   111
			SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval));
slouken@0
   112
			available = 0;
slouken@418
   113
		}
slouken@0
   114
	}
slouken@418
   115
	else{
slouken@418
   116
		SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval));
slouken@0
   117
	}
slouken@0
   118
	
slouken@418
   119
	#ifdef DEBUG_AUDIO
slouken@0
   120
	fprintf(stderr,"AudioAvailable rtns %d\n", available);
slouken@418
   121
	#endif
slouken@418
   122
	
slouken@0
   123
	return(available);
slouken@0
   124
}
slouken@0
   125
slouken@0
   126
static void Audio_DeleteDevice(SDL_AudioDevice *device)
slouken@0
   127
{
slouken@418
   128
	#ifdef DEBUG_AUDIO
slouken@0
   129
	fprintf(stderr,"Audio_DeleteDevice\n");
slouken@418
   130
	#endif
slouken@0
   131
slouken@0
   132
	free(device->hidden);
slouken@0
   133
	free(device);
slouken@0
   134
}
slouken@0
   135
slouken@0
   136
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
slouken@0
   137
{
slouken@0
   138
	SDL_AudioDevice *this;
slouken@418
   139
	#ifdef DEBUG_AUDIO
slouken@0
   140
	fprintf(stderr,"Audio_CreateDevice\n");
slouken@418
   141
	#endif
slouken@0
   142
	/* Initialize all variables that we clean on shutdown */
slouken@0
   143
	this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
slouken@0
   144
	if ( this ) {
slouken@0
   145
		memset(this, 0, (sizeof *this));
slouken@0
   146
		this->hidden = (struct SDL_PrivateAudioData *)
slouken@418
   147
		malloc((sizeof *this->hidden));
slouken@0
   148
	}
slouken@0
   149
	if ( (this == NULL) || (this->hidden == NULL) ) {
slouken@0
   150
		SDL_OutOfMemory();
slouken@0
   151
		if ( this ) {
slouken@0
   152
			free(this);
slouken@0
   153
		}
slouken@0
   154
		return(0);
slouken@0
   155
	}
slouken@0
   156
	memset(this->hidden, 0, (sizeof *this->hidden));
slouken@0
   157
	audio_handle = NULL;
slouken@0
   158
slouken@0
   159
	/* Set the function pointers */
slouken@0
   160
	this->OpenAudio = NTO_OpenAudio;
slouken@0
   161
	this->WaitAudio = NTO_WaitAudio;
slouken@0
   162
	this->PlayAudio = NTO_PlayAudio;
slouken@0
   163
	this->GetAudioBuf = NTO_GetAudioBuf;
slouken@0
   164
	this->CloseAudio = NTO_CloseAudio;
slouken@0
   165
slouken@0
   166
	this->free = Audio_DeleteDevice;
slouken@0
   167
slouken@0
   168
	return this;
slouken@0
   169
}
slouken@0
   170
slouken@0
   171
/* Don't change the name from "ALSA_bootstrap" - that's how it's called */
slouken@0
   172
AudioBootStrap ALSA_bootstrap = {
slouken@0
   173
	DRIVER_NAME, "Neutrino PCM audio",
slouken@0
   174
	Audio_Available, Audio_CreateDevice
slouken@0
   175
};
slouken@0
   176
slouken@0
   177
/* This function waits until it is possible to write a full sound buffer */
slouken@0
   178
static void NTO_WaitAudio(_THIS)
slouken@0
   179
{
slouken@418
   180
	fd_set wfds;
slouken@0
   181
slouken@418
   182
	FD_SET( audio_fd, &wfds );
slouken@418
   183
	switch( select( audio_fd + 1, NULL, &wfds, NULL, NULL ) )
slouken@0
   184
	{
slouken@418
   185
		case -1:
slouken@418
   186
		case 0:
slouken@418
   187
			/* Error */
slouken@418
   188
			SDL_SetError("select() in NTO_WaitAudio failed: %s\n", strerror(errno));
slouken@418
   189
			break;
slouken@418
   190
		default:
slouken@418
   191
			if(FD_ISSET(audio_fd, &wfds))
slouken@418
   192
				return;
slouken@418
   193
	}
slouken@0
   194
}
slouken@0
   195
slouken@0
   196
static void NTO_PlayAudio(_THIS)
slouken@0
   197
{
slouken@418
   198
	int written, rval;
slouken@418
   199
	int towrite;
slouken@0
   200
slouken@418
   201
	#ifdef DEBUG_AUDIO
slouken@418
   202
	fprintf(stderr, "NTO_PlayAudio\n");
slouken@418
   203
	#endif
slouken@0
   204
slouken@418
   205
	if( !this->enabled){
slouken@418
   206
		return;
slouken@418
   207
	}
slouken@0
   208
slouken@0
   209
	towrite = pcm_len;
slouken@0
   210
	
slouken@418
   211
	/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
slouken@418
   212
	do {
slouken@0
   213
		written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
slouken@418
   214
		#ifdef DEBUG_AUDIO
slouken@0
   215
		fprintf(stderr, "NTO_PlayAudio: written = %d towrite = %d\n",written,towrite);
slouken@418
   216
		#endif
slouken@418
   217
		if (written != towrite){
slouken@418
   218
			if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){
slouken@418
   219
				SDL_Delay(1);   /* Let a little CPU time go by and try to write again */
slouken@418
   220
				#ifdef DEBUG_AUDIO
slouken@0
   221
				fprintf(stderr, "errno == EAGAIN written %d\n", written);
slouken@418
   222
				#endif
slouken@0
   223
				towrite -= written; //we wrote some data
slouken@0
   224
				continue;
slouken@418
   225
			}		
slouken@418
   226
			else if((errno == EINVAL) || (errno == EIO)){
slouken@418
   227
				if(errno == EIO){
slouken@418
   228
					#ifdef DEBUG_AUDIO
slouken@418
   229
					fprintf(stderr,"snd_pcm_plugin_write failed EIO: %s\n", snd_strerror(written));
slouken@418
   230
					#endif
slouken@418
   231
				}
slouken@418
   232
				if(errno == EINVAL){
slouken@418
   233
					#ifdef DEBUG_AUDIO
slouken@418
   234
					fprintf(stderr,"snd_pcm_plugin_write failed EINVAL: %s\n", snd_strerror(written));	
slouken@418
   235
					#endif
slouken@418
   236
				}
slouken@418
   237
				
slouken@418
   238
				memset(&cstatus, 0, sizeof(cstatus));
slouken@418
   239
				if( (rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0 ){
slouken@418
   240
					#ifdef DEBUG_AUDIO
slouken@0
   241
					fprintf(stderr, "snd_pcm_plugin_status failed %s\n",snd_strerror(rval));
slouken@418
   242
					#endif
slouken@418
   243
					SDL_SetError("snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
slouken@418
   244
					return;
slouken@418
   245
				}	
slouken@0
   246
		        
slouken@418
   247
				if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY) ){
slouken@418
   248
					#ifdef DEBUG_AUDIO
slouken@0
   249
					fprintf(stderr, "buffer underrun\n");
slouken@418
   250
					#endif
slouken@418
   251
					if ( (rval = snd_pcm_plugin_prepare (audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0 ){
slouken@418
   252
						#ifdef DEBUG_AUDIO
slouken@0
   253
						fprintf(stderr, "NTO_PlayAudio: prepare failed %s\n",snd_strerror(rval));
slouken@418
   254
						#endif
slouken@0
   255
						SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",snd_strerror(rval) );
slouken@0
   256
						return;
slouken@0
   257
					}
slouken@0
   258
				}		        		
slouken@0
   259
 				continue;
slouken@0
   260
			}
slouken@418
   261
			else{
slouken@418
   262
				#ifdef DEBUG_AUDIO
slouken@418
   263
				fprintf(stderr, "NTO_PlayAudio: snd_pcm_plugin_write failed unknown errno %d %s\n",errno, snd_strerror(rval));
slouken@418
   264
				#endif
slouken@0
   265
				return;
slouken@0
   266
			}
slouken@0
   267
			
slouken@0
   268
		}
slouken@0
   269
		else
slouken@0
   270
		{
slouken@0
   271
			towrite -= written; //we wrote all remaining data
slouken@0
   272
		}
slouken@418
   273
	} while ( (towrite > 0)  && (this->enabled) );
slouken@0
   274
slouken@418
   275
	/* If we couldn't write, assume fatal error for now */
slouken@418
   276
	if ( towrite != 0 ) {
slouken@418
   277
		this->enabled = 0;
slouken@418
   278
	}
slouken@0
   279
	return;
slouken@0
   280
}
slouken@0
   281
slouken@0
   282
static Uint8 *NTO_GetAudioBuf(_THIS)
slouken@0
   283
{
slouken@418
   284
	#ifdef DEBUG_AUDIO
slouken@418
   285
	fprintf(stderr, "NTO_GetAudioBuf: pcm_buf %X\n",(Uint8 *)pcm_buf);
slouken@418
   286
	#endif
slouken@0
   287
	return(pcm_buf);
slouken@0
   288
}
slouken@0
   289
slouken@0
   290
static void NTO_CloseAudio(_THIS)
slouken@0
   291
{
slouken@0
   292
	int rval;
slouken@0
   293
slouken@418
   294
	#ifdef DEBUG_AUDIO
slouken@418
   295
	fprintf(stderr, "NTO_CloseAudio\n");
slouken@418
   296
	#endif
slouken@418
   297
slouken@418
   298
	this->enabled = 0;
slouken@0
   299
slouken@0
   300
	if ( audio_handle != NULL ) {
slouken@418
   301
		if ((rval = snd_pcm_plugin_flush(audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0){
slouken@418
   302
			SDL_SetError("snd_pcm_plugin_flush failed: %s\n",snd_strerror(rval));
slouken@0
   303
			return;
slouken@0
   304
		}
slouken@418
   305
		if ((rval = snd_pcm_close(audio_handle)) < 0){
slouken@0
   306
			SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval));
slouken@0
   307
			return;
slouken@0
   308
		}
slouken@0
   309
		audio_handle = NULL;
slouken@0
   310
	}
slouken@0
   311
}
slouken@0
   312
slouken@0
   313
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec)
slouken@0
   314
{
slouken@0
   315
	int rval;
slouken@0
   316
	int format;
slouken@0
   317
	Uint16 test_format;
slouken@0
   318
	int twidth;
slouken@0
   319
	int found;
slouken@0
   320
slouken@418
   321
	#ifdef DEBUG_AUDIO
slouken@418
   322
	fprintf(stderr, "NTO_OpenAudio\n");
slouken@418
   323
	#endif
slouken@0
   324
	
slouken@0
   325
	audio_handle = NULL;
slouken@418
   326
	this->enabled = 0;
slouken@0
   327
slouken@0
   328
	if ( pcm_buf != NULL ) {
slouken@0
   329
		free((Uint8 *)pcm_buf); 
slouken@0
   330
		pcm_buf = NULL;
slouken@0
   331
	}
slouken@0
   332
	 
slouken@0
   333
	/* initialize channel transfer parameters to default */
slouken@0
   334
	init_pcm_cparams(&cparams);
slouken@0
   335
slouken@0
   336
	/* Open the audio device */
slouken@418
   337
	rval = snd_pcm_open_preferred(&audio_handle, NULL, NULL, OPEN_FLAGS);
slouken@0
   338
	if ( rval < 0 ) {
slouken@0
   339
		SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval));
slouken@0
   340
		return(-1);
slouken@0
   341
	}
slouken@0
   342
slouken@418
   343
	/* enable count status parameter */
slouken@418
   344
	if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP))<0){
slouken@418
   345
		SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval));
slouken@418
   346
		return(-1);
slouken@418
   347
	}
slouken@0
   348
slouken@0
   349
	/* Try for a closest match on audio format */
slouken@0
   350
	format = 0;
slouken@418
   351
 	found = 0; /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
slouken@0
   352
	for ( test_format = SDL_FirstAudioFormat(spec->format);	!found ; ) 
slouken@0
   353
	{
slouken@418
   354
		#ifdef DEBUG_AUDIO
slouken@0
   355
		fprintf(stderr, "Trying format 0x%4.4x spec->samples %d\n", test_format,spec->samples);
slouken@418
   356
		#endif
slouken@418
   357
		
slouken@418
   358
		/* if match found set format to equivalent ALSA format */
slouken@418
   359
		switch ( test_format ) {
slouken@0
   360
			case AUDIO_U8:
slouken@0
   361
				format = SND_PCM_SFMT_U8;
slouken@0
   362
				found = 1;
slouken@0
   363
				break;
slouken@0
   364
			case AUDIO_S8:
slouken@0
   365
				format = SND_PCM_SFMT_S8;
slouken@0
   366
				found = 1;
slouken@0
   367
				break;
slouken@0
   368
			case AUDIO_S16LSB:
slouken@0
   369
				format = SND_PCM_SFMT_S16_LE;
slouken@0
   370
				found = 1;
slouken@0
   371
				break;
slouken@0
   372
			case AUDIO_S16MSB:
slouken@0
   373
				format = SND_PCM_SFMT_S16_BE;
slouken@0
   374
				found = 1;
slouken@0
   375
				break;
slouken@0
   376
			case AUDIO_U16LSB:
slouken@0
   377
				format = SND_PCM_SFMT_U16_LE;
slouken@0
   378
				found = 1;
slouken@0
   379
				break;
slouken@0
   380
			case AUDIO_U16MSB:
slouken@0
   381
				format = SND_PCM_SFMT_U16_BE;
slouken@0
   382
				found = 1;
slouken@0
   383
				break;
slouken@0
   384
			default:
slouken@0
   385
				break;
slouken@0
   386
		}
slouken@0
   387
		if ( ! found ) {
slouken@0
   388
			test_format = SDL_NextAudioFormat();
slouken@0
   389
		}
slouken@0
   390
	}
slouken@418
   391
slouken@0
   392
	/* assumes test_format not 0 on success */
slouken@0
   393
	if ( test_format == 0 ) {
slouken@0
   394
		SDL_SetError("Couldn't find any hardware audio formats");
slouken@0
   395
		return(-1);
slouken@0
   396
	}
slouken@418
   397
slouken@0
   398
	spec->format = test_format;
slouken@0
   399
slouken@0
   400
	/* Set the audio format */
slouken@0
   401
	cparams.format.format = format;
slouken@0
   402
slouken@0
   403
	/* Set mono or stereo audio (currently only two channels supported) */
slouken@0
   404
	cparams.format.voices = spec->channels;
slouken@0
   405
	
slouken@418
   406
	#ifdef DEBUG_AUDIO
slouken@0
   407
	fprintf(stderr,"intializing channels %d\n", cparams.format.voices);
slouken@418
   408
	#endif
slouken@0
   409
slouken@0
   410
	/* Set rate */
slouken@0
   411
	cparams.format.rate = spec->freq ;
slouken@0
   412
slouken@0
   413
	/* Setup the transfer parameters according to cparams */
slouken@0
   414
	rval = snd_pcm_plugin_params(audio_handle, &cparams);
slouken@0
   415
	if (rval < 0) {
slouken@0
   416
		SDL_SetError("snd_pcm_channel_params failed: %s\n", snd_strerror (rval));
slouken@0
   417
		return(-1);
slouken@0
   418
	}
slouken@0
   419
slouken@418
   420
	/*  Make sure channel is setup right one last time */
slouken@418
   421
	memset( &csetup, 0, sizeof( csetup ) );
slouken@418
   422
	csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
slouken@418
   423
	if ( snd_pcm_plugin_setup( audio_handle, &csetup ) < 0 )
slouken@418
   424
	{
slouken@418
   425
		SDL_SetError("Unable to setup playback channel\n" );
slouken@418
   426
		return(-1);
slouken@418
   427
	}
slouken@418
   428
	else
slouken@418
   429
	{
slouken@418
   430
		#ifdef DEBUG_AUDIO
slouken@418
   431
		fprintf(stderr,"requested format: %d\n",cparams.format.format);
slouken@418
   432
		fprintf(stderr,"requested frag size: %d\n",cparams.buf.block.frag_size);
slouken@418
   433
		fprintf(stderr,"requested max frags: %d\n\n",cparams.buf.block.frags_max);
slouken@0
   434
slouken@418
   435
		fprintf(stderr,"real format: %d\n", csetup.format.format );
slouken@418
   436
		fprintf(stderr,"real frag size : %d\n", csetup.buf.block.frag_size );
slouken@0
   437
		fprintf(stderr,"real max frags : %d\n", csetup.buf.block.frags_max );
slouken@418
   438
		#endif
slouken@418
   439
	}
slouken@0
   440
slouken@418
   441
	/*
slouken@418
   442
		Allocate memory to the audio buffer and initialize with silence (Note that
slouken@418
   443
		buffer size must be a multiple of fragment size, so find closest multiple)
slouken@418
   444
	*/
slouken@418
   445
	
slouken@418
   446
	twidth = snd_pcm_format_width(format);
slouken@418
   447
	if (twidth < 0) {
slouken@418
   448
		printf("snd_pcm_format_width failed\n");
slouken@418
   449
		twidth = 0;
slouken@418
   450
	}
slouken@418
   451
slouken@418
   452
	#ifdef DEBUG_AUDIO
slouken@418
   453
	fprintf(stderr,"format is %d bits wide\n",twidth);
slouken@418
   454
	#endif
slouken@0
   455
slouken@418
   456
	pcm_len = spec->size ;
slouken@418
   457
	
slouken@418
   458
	#ifdef DEBUG_AUDIO
slouken@418
   459
	fprintf(stderr,"pcm_len set to %d\n", pcm_len);
slouken@418
   460
	#endif
slouken@418
   461
slouken@418
   462
	if (pcm_len == 0){
slouken@418
   463
		pcm_len = csetup.buf.block.frag_size;
slouken@418
   464
	}
slouken@0
   465
slouken@418
   466
	pcm_buf = (Uint8*)malloc(pcm_len);
slouken@418
   467
	if (pcm_buf == NULL) {
slouken@418
   468
		SDL_SetError("pcm_buf malloc failed\n");
slouken@418
   469
		return(-1);
slouken@418
   470
	}
slouken@418
   471
	memset(pcm_buf,spec->silence,pcm_len);
slouken@418
   472
slouken@418
   473
	#ifdef DEBUG_AUDIO
slouken@418
   474
	fprintf(stderr,"pcm_buf malloced and silenced.\n");
slouken@418
   475
	#endif
slouken@418
   476
slouken@418
   477
	/* get the file descriptor */
slouken@418
   478
	if( (audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0){
slouken@418
   479
		fprintf(stderr, "snd_pcm_file_descriptor failed with error code: %d\n", audio_fd);
slouken@418
   480
	}
slouken@0
   481
slouken@0
   482
	/* Trigger audio playback */
slouken@0
   483
	rval = snd_pcm_plugin_prepare( audio_handle, SND_PCM_CHANNEL_PLAYBACK);
slouken@0
   484
	if (rval < 0) {
slouken@418
   485
		SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror (rval));
slouken@418
   486
		return(-1);
slouken@0
   487
	}
slouken@418
   488
slouken@418
   489
	this->enabled = 1;
slouken@418
   490
slouken@0
   491
	/* Get the parent process id (we're the parent of the audio thread) */
slouken@0
   492
	parent = getpid();
slouken@0
   493
slouken@0
   494
	/* We're ready to rock and roll. :-) */
slouken@0
   495
	return(0);
slouken@0
   496
}
slouken@0
   497