Commit bf7b6262 authored by Sam Lantinga's avatar Sam Lantinga

Date: Sat, 13 Sep 2003 15:50:43 +0300

From: "Mike Gorchak"
Subject: QNX fixes

improved sound code for the QNX, added workarounds for known bugs, fixed photon detect code. Update .qpg file.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40719
parent 794bba8f
...@@ -78,7 +78,7 @@ script you must manually delete the libtool.m4 stuff from the acinclu- ...@@ -78,7 +78,7 @@ script you must manually delete the libtool.m4 stuff from the acinclu-
de.m4 file (it comes after the ESD detection code up to the end of the de.m4 file (it comes after the ESD detection code up to the end of the
file), because the libtool stuff in the acinclude.m4 file is very old file), because the libtool stuff in the acinclude.m4 file is very old
and doesn't know anything about QNX. Just remove it, then run and doesn't know anything about QNX. Just remove it, then run
"libtoolize --force --copy" and after that run autogen.sh. "libtoolize --force --copy" and after that run the autogen.sh script.
====================================================================== ======================================================================
Some building issues: Some building issues:
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
</QPG:Files> </QPG:Files>
<QPG:PackageFilter> <QPG:PackageFilter>
<QPM:PackageManifest> <QPM:PackageManifest>
<QPM:PackageDescription> <QPM:PackageDescription>
<QPM:PackageType>Library</QPM:PackageType> <QPM:PackageType>Library</QPM:PackageType>
<QPM:PackageName>SDL</QPM:PackageName> <QPM:PackageName>SDL</QPM:PackageName>
...@@ -59,6 +60,7 @@ ...@@ -59,6 +60,7 @@
<QPM:PackageRepository>http://qnx.org.ru/repository</QPM:PackageRepository> <QPM:PackageRepository>http://qnx.org.ru/repository</QPM:PackageRepository>
<QPM:FileVersion>2.0</QPM:FileVersion> <QPM:FileVersion>2.0</QPM:FileVersion>
</QPM:PackageDescription> </QPM:PackageDescription>
<QPM:ProductDescription> <QPM:ProductDescription>
<QPM:ProductName>SDL</QPM:ProductName> <QPM:ProductName>SDL</QPM:ProductName>
<QPM:ProductIdentifier>SDL</QPM:ProductIdentifier> <QPM:ProductIdentifier>SDL</QPM:ProductIdentifier>
...@@ -74,11 +76,12 @@ ...@@ -74,11 +76,12 @@
<QPM:AuthorEmail>slouken@libsdl.org</QPM:AuthorEmail> <QPM:AuthorEmail>slouken@libsdl.org</QPM:AuthorEmail>
<QPM:ProductIconSmall/> <QPM:ProductIconSmall/>
<QPM:ProductIconLarge/> <QPM:ProductIconLarge/>
<QPM:ProductDescriptionShort>This is the Simple DirectMedia Layer, a generic API that provides low level access to audio, keyboard, mouse, and display framebuffer across multiple platforms.</QPM:ProductDescriptionShort> <QPM:ProductDescriptionShort>This is the Simple DirectMedia Layer (SDL), a generic API that provides low level access to audio, keyboard, mouse, and display framebuffer across multiple platforms.</QPM:ProductDescriptionShort>
<QPM:ProductDescriptionLong>This is the Simple DirectMedia Layer, a generic API that provides low level access to audio, keyboard, mouse, and display framebuffer across multiple platforms. This is the libraries, include files and other resources you can use to develop and run SDL applications.</QPM:ProductDescriptionLong> <QPM:ProductDescriptionLong>This is the Simple DirectMedia Layer (SDL), a generic API that provides low level access to audio, keyboard, mouse, and display framebuffer across multiple platforms. This is the libraries, include files and other resources you can use to develop and run SDL applications.</QPM:ProductDescriptionLong>
<QPM:ProductDescriptionURL>http://www.libsdl.org</QPM:ProductDescriptionURL> <QPM:ProductDescriptionURL>http://www.libsdl.org</QPM:ProductDescriptionURL>
<QPM:ProductDescriptionEmbedURL/> <QPM:ProductDescriptionEmbedURL/>
</QPM:ProductDescription> </QPM:ProductDescription>
<QPM:ReleaseDescription> <QPM:ReleaseDescription>
<QPM:ReleaseVersion>@VERSION@</QPM:ReleaseVersion> <QPM:ReleaseVersion>@VERSION@</QPM:ReleaseVersion>
<QPM:ReleaseUrgency>High</QPM:ReleaseUrgency> <QPM:ReleaseUrgency>High</QPM:ReleaseUrgency>
...@@ -87,25 +90,53 @@ ...@@ -87,25 +90,53 @@
<QPM:ReleaseNoteMajor/> <QPM:ReleaseNoteMajor/>
<QPM:ReleaseBuild>1</QPM:ReleaseBuild> <QPM:ReleaseBuild>1</QPM:ReleaseBuild>
<QPM:CountryExclude/> <QPM:CountryExclude/>
<QPM:ReleaseCopyright>GNU General Public License</QPM:ReleaseCopyright> <QPM:ReleaseCopyright>GNU Lesser General Public License</QPM:ReleaseCopyright>
</QPM:ReleaseDescription> </QPM:ReleaseDescription>
<QPM:ContentDescription> <QPM:ContentDescription>
<QPM:ContentTopic>Software Development/Libraries and Extensions/C Libraries</QPM:ContentTopic> <QPM:ContentTopic xmlmultiple="true">Software Development/Libraries and Extensions/C Libraries</QPM:ContentTopic>
<QPM:ContentKeyword>SDL, audio, graphics, demos, games, emulators, media, layer</QPM:ContentKeyword> <QPM:ContentKeyword>SDL, audio, graphics, demos, games, emulators, media, layer</QPM:ContentKeyword>
<QPM:Processor/>
<QPM:TargetProcessor/>
<QPM:TargetOS>qnx6</QPM:TargetOS> <QPM:TargetOS>qnx6</QPM:TargetOS>
<QPM:HostOS>qnx6</QPM:HostOS> <QPM:HostOS>none</QPM:HostOS>
<QPM:DisplayEnvironment>Photon</QPM:DisplayEnvironment> <QPM:DisplayEnvironment xmlmultiple="true">Photon</QPM:DisplayEnvironment>
<QPM:TargetAudience>Developer</QPM:TargetAudience> <QPM:TargetAudience xmlmultiple="true">Developer</QPM:TargetAudience>
<QPM:TargetAudience>User</QPM:TargetAudience> <QPM:TargetAudience xmlmultiple="true">User</QPM:TargetAudience>
</QPM:ContentDescription> </QPM:ContentDescription>
<QPM:LicenseUrl>repdata://LicenseUrl/COPYING</QPM:LicenseUrl> <QPM:LicenseUrl>repdata://LicenseUrl/COPYING</QPM:LicenseUrl>
</QPM:PackageManifest>
</QPG:PackageFilter>
<QPG:PackageFilter proc="none" target="none">
<QPM:PackageManifest>
<QPM:ProductInstallationDependencies>
<QPM:ProductRequirements></QPM:ProductRequirements>
</QPM:ProductInstallationDependencies>
</QPM:PackageManifest>
</QPG:PackageFilter>
<QPG:PackageFilter proc="x86" target="none">
<QPM:PackageManifest>
<QPM:ProductInstallationDependencies> <QPM:ProductInstallationDependencies>
<QPM:ProductRequirements/> <QPM:ProductRequirements></QPM:ProductRequirements>
</QPM:ProductInstallationDependencies> </QPM:ProductInstallationDependencies>
</QPM:PackageManifest> </QPM:PackageManifest>
</QPG:PackageFilter> </QPG:PackageFilter>
<QPG:PackageFilter proc="none" target="x86">
<QPM:PackageManifest>
<QPM:ProductInstallationDependencies>
<QPM:ProductRequirements></QPM:ProductRequirements>
</QPM:ProductInstallationDependencies>
</QPM:PackageManifest>
</QPG:PackageFilter>
<QPG:PackageFilter proc="x86" target="x86">
<QPM:PackageManifest>
<QPM:ProductInstallationDependencies>
<QPM:ProductRequirements></QPM:ProductRequirements>
</QPM:ProductInstallationDependencies>
</QPM:PackageManifest>
</QPG:PackageFilter>
</QPG:Values> </QPG:Values>
</QPG:Generation> </QPG:Generation>
...@@ -30,8 +30,9 @@ ...@@ -30,8 +30,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <sched.h> #include <sched.h>
#include <sys/asoundlib.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/neutrino.h>
#include <sys/asoundlib.h>
#include "SDL_audio.h" #include "SDL_audio.h"
#include "SDL_error.h" #include "SDL_error.h"
...@@ -41,11 +42,12 @@ ...@@ -41,11 +42,12 @@
#include "SDL_nto_audio.h" #include "SDL_nto_audio.h"
/* The tag name used by NTO audio */ /* The tag name used by NTO audio */
#define DRIVER_NAME "nto" #define DRIVER_NAME "qsa-nto"
/* default channel communication parameters */ /* default channel communication parameters */
#define DEFAULT_CPARAMS_RATE 22050 #define DEFAULT_CPARAMS_RATE 22050
#define DEFAULT_CPARAMS_VOICES 1 #define DEFAULT_CPARAMS_VOICES 1
/* FIXME: need to add in the near future flexible logic with frag_size and frags count */
#define DEFAULT_CPARAMS_FRAG_SIZE 4096 #define DEFAULT_CPARAMS_FRAG_SIZE 4096
#define DEFAULT_CPARAMS_FRAGS_MIN 1 #define DEFAULT_CPARAMS_FRAGS_MIN 1
#define DEFAULT_CPARAMS_FRAGS_MAX 1 #define DEFAULT_CPARAMS_FRAGS_MAX 1
...@@ -53,304 +55,345 @@ ...@@ -53,304 +55,345 @@
/* Open the audio device for playback, and don't block if busy */ /* Open the audio device for playback, and don't block if busy */
#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK #define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
#define QSA_NO_WORKAROUNDS 0x00000000
#define QSA_MMAP_WORKAROUND 0x00000001
struct BuggyCards
{
char* cardname;
unsigned long bugtype;
};
#define QSA_WA_CARDS 3
struct BuggyCards buggycards[QSA_WA_CARDS]=
{
{"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
{"Vortex 8820", QSA_MMAP_WORKAROUND},
{"Vortex 8830", QSA_MMAP_WORKAROUND},
};
/* Audio driver functions */ /* Audio driver functions */
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec); static void NTO_ThreadInit(_THIS);
static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec);
static void NTO_WaitAudio(_THIS); static void NTO_WaitAudio(_THIS);
static void NTO_PlayAudio(_THIS); static void NTO_PlayAudio(_THIS);
static Uint8 *NTO_GetAudioBuf(_THIS); static Uint8* NTO_GetAudioBuf(_THIS);
static void NTO_CloseAudio(_THIS); static void NTO_CloseAudio(_THIS);
static snd_pcm_channel_status_t cstatus; /* card names check to apply the workarounds */
static snd_pcm_channel_params_t cparams; static int NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
static snd_pcm_channel_setup_t csetup; {
char scardname[33];
int it;
if (snd_card_get_name(cardno, scardname, 32)<0)
{
return 0;
}
for (it=0; it<QSA_WA_CARDS; it++)
{
if (strcmp(buggycards[it].cardname, scardname)==0)
{
if (buggycards[it].bugtype==checkfor)
{
return 1;
}
}
}
return 0;
}
static void NTO_ThreadInit(_THIS)
{
int status;
struct sched_param param;
/* increasing default 10 priority to 25 to avoid jerky sound */
status=SchedGet(0, 0, &param);
param.sched_priority=param.sched_curpriority+15;
status=SchedSet(0, 0, SCHED_NOCHANGE, &param);
}
/* PCM transfer channel parameters initialize function */ /* PCM transfer channel parameters initialize function */
static void init_pcm_cparams(snd_pcm_channel_params_t* cparams) static void NTO_InitAudioParams(snd_pcm_channel_params_t* cpars)
{ {
memset(cparams,0,sizeof(snd_pcm_channel_params_t)); memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
cparams->channel = SND_PCM_CHANNEL_PLAYBACK; cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
cparams->mode = SND_PCM_MODE_BLOCK; cpars->mode = SND_PCM_MODE_BLOCK;
cparams->start_mode = SND_PCM_START_DATA; cpars->start_mode = SND_PCM_START_DATA;
cparams->stop_mode = SND_PCM_STOP_STOP; cpars->stop_mode = SND_PCM_STOP_STOP;
cparams->format.format = SND_PCM_SFMT_S16_LE; cpars->format.format = SND_PCM_SFMT_S16_LE;
cparams->format.interleave = 1; cpars->format.interleave = 1;
cparams->format.rate = DEFAULT_CPARAMS_RATE; cpars->format.rate = DEFAULT_CPARAMS_RATE;
cparams->format.voices = DEFAULT_CPARAMS_VOICES; cpars->format.voices = DEFAULT_CPARAMS_VOICES;
cparams->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE; cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
cparams->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN; cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
cparams->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
} }
static int Audio_Available(void) static int NTO_AudioAvailable(void)
{ {
/* /* See if we can open a nonblocking channel.
See if we can open a nonblocking channel.
Return value '1' means we can. Return value '1' means we can.
Return value '0' means we cannot. Return value '0' means we cannot. */
*/
int available; int available;
int rval; int rval;
snd_pcm_t *handle; snd_pcm_t* handle;
available = 0; available = 0;
handle = NULL; handle = NULL;
rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS); rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
if (rval >= 0){ if (rval >= 0)
{
available = 1; available = 1;
if ((rval = snd_pcm_close(handle)) < 0){ if ((rval = snd_pcm_close(handle)) < 0)
SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval)); {
SDL_SetError("NTO_AudioAvailable(): snd_pcm_close failed: %s\n", snd_strerror(rval));
available = 0; available = 0;
} }
} }
else{ else
SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval)); {
SDL_SetError("NTO_AudioAvailable(): there are no available audio devices.\n");
} }
#ifdef DEBUG_AUDIO return (available);
fprintf(stderr,"AudioAvailable rtns %d\n", available);
#endif
return(available);
} }
static void Audio_DeleteDevice(SDL_AudioDevice *device) static void NTO_DeleteAudioDevice(SDL_AudioDevice *device)
{ {
#ifdef DEBUG_AUDIO if ((device)&&(device->hidden))
fprintf(stderr,"Audio_DeleteDevice\n"); {
#endif
free(device->hidden); free(device->hidden);
}
if (device)
{
free(device); free(device);
}
} }
static SDL_AudioDevice *Audio_CreateDevice(int devindex) static SDL_AudioDevice* NTO_CreateAudioDevice(int devindex)
{ {
SDL_AudioDevice *this; SDL_AudioDevice *this;
#ifdef DEBUG_AUDIO
fprintf(stderr,"Audio_CreateDevice\n");
#endif
/* Initialize all variables that we clean on shutdown */ /* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( this ) { if (this)
memset(this, 0, (sizeof *this)); {
this->hidden = (struct SDL_PrivateAudioData *) memset(this, 0, sizeof(SDL_AudioDevice));
malloc((sizeof *this->hidden)); this->hidden = (struct SDL_PrivateAudioData *)malloc(sizeof(struct SDL_PrivateAudioData));
} }
if ( (this == NULL) || (this->hidden == NULL) ) { if ((this == NULL) || (this->hidden == NULL))
{
SDL_OutOfMemory(); SDL_OutOfMemory();
if ( this ) { if (this)
{
free(this); free(this);
} }
return(0); return (0);
} }
memset(this->hidden, 0, (sizeof *this->hidden)); memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
audio_handle = NULL; audio_handle = NULL;
/* Set the function pointers */ /* Set the function pointers */
this->ThreadInit = NTO_ThreadInit;
this->OpenAudio = NTO_OpenAudio; this->OpenAudio = NTO_OpenAudio;
this->WaitAudio = NTO_WaitAudio; this->WaitAudio = NTO_WaitAudio;
this->PlayAudio = NTO_PlayAudio; this->PlayAudio = NTO_PlayAudio;
this->GetAudioBuf = NTO_GetAudioBuf; this->GetAudioBuf = NTO_GetAudioBuf;
this->CloseAudio = NTO_CloseAudio; this->CloseAudio = NTO_CloseAudio;
this->free = Audio_DeleteDevice; this->free = NTO_DeleteAudioDevice;
return this; return this;
} }
AudioBootStrap QNXNTOAUDIO_bootstrap = { AudioBootStrap QNXNTOAUDIO_bootstrap =
DRIVER_NAME, "QNX6 NTO PCM audio", {
Audio_Available, Audio_CreateDevice DRIVER_NAME, "QNX6 QSA-NTO Audio",
NTO_AudioAvailable,
NTO_CreateAudioDevice
}; };
/* This function waits until it is possible to write a full sound buffer */ /* This function waits until it is possible to write a full sound buffer */
static void NTO_WaitAudio(_THIS) static void NTO_WaitAudio(_THIS)
{ {
fd_set wfds; fd_set wfds;
int selectret;
FD_ZERO(&wfds);
FD_SET(audio_fd, &wfds);
FD_SET( audio_fd, &wfds ); do {
switch( select( audio_fd + 1, NULL, &wfds, NULL, NULL ) ) selectret=select(audio_fd + 1, NULL, &wfds, NULL, NULL);
switch (selectret)
{ {
case -1: case -1:
case 0: case 0: SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", strerror(errno));
/* Error */
SDL_SetError("select() in NTO_WaitAudio failed: %s\n", strerror(errno));
break;
default:
if(FD_ISSET(audio_fd, &wfds))
return; return;
default: if (FD_ISSET(audio_fd, &wfds))
{
return;
}
break;
} }
} while(1);
} }
static void NTO_PlayAudio(_THIS) static void NTO_PlayAudio(_THIS)
{ {
int written, rval; int written, rval;
int towrite; int towrite;
void* pcmbuffer;
#ifdef DEBUG_AUDIO if (!this->enabled)
fprintf(stderr, "NTO_PlayAudio\n"); {
#endif
if( !this->enabled){
return; return;
} }
towrite = pcm_len; towrite = this->spec.size;
pcmbuffer = pcm_buf;
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */ /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do { do {
written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
#ifdef DEBUG_AUDIO if (written != towrite)
fprintf(stderr, "NTO_PlayAudio: written = %d towrite = %d\n",written,towrite); {
#endif if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
if (written != towrite){ {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){ /* Let a little CPU time go by and try to write again */
SDL_Delay(1); /* Let a little CPU time go by and try to write again */ SDL_Delay(1);
#ifdef DEBUG_AUDIO /* if we wrote some data */
fprintf(stderr, "errno == EAGAIN written %d\n", written); towrite -= written;
#endif pcmbuffer += written * this->spec.channels;
towrite -= written; //we wrote some data
continue; continue;
} }
else if((errno == EINVAL) || (errno == EIO)){ else
if(errno == EIO){ {
#ifdef DEBUG_AUDIO if ((errno == EINVAL) || (errno == EIO))
fprintf(stderr,"snd_pcm_plugin_write failed EIO: %s\n", snd_strerror(written)); {
#endif
}
if(errno == EINVAL){
#ifdef DEBUG_AUDIO
fprintf(stderr,"snd_pcm_plugin_write failed EINVAL: %s\n", snd_strerror(written));
#endif
}
memset(&cstatus, 0, sizeof(cstatus)); memset(&cstatus, 0, sizeof(cstatus));
if( (rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0 ){ cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
#ifdef DEBUG_AUDIO if ((rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0)
fprintf(stderr, "snd_pcm_plugin_status failed %s\n",snd_strerror(rval)); {
#endif SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
SDL_SetError("snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
return; return;
} }
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY))
if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY) ){ {
#ifdef DEBUG_AUDIO if ((rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
fprintf(stderr, "buffer underrun\n"); {
#endif SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
if ( (rval = snd_pcm_plugin_prepare (audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0 ){
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_PlayAudio: prepare failed %s\n",snd_strerror(rval));
#endif
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",snd_strerror(rval) );
return; return;
} }
} }
continue; continue;
} }
else{ else
#ifdef DEBUG_AUDIO {
fprintf(stderr, "NTO_PlayAudio: snd_pcm_plugin_write failed unknown errno %d %s\n",errno, snd_strerror(rval));
#endif
return; return;
} }
}
} }
else else
{ {
towrite -= written; //we wrote all remaining data /* we wrote all remaining data */
towrite -= written;
pcmbuffer += written * this->spec.channels;
} }
} while ( (towrite > 0) && (this->enabled) ); } while ((towrite > 0) && (this->enabled));
/* If we couldn't write, assume fatal error for now */ /* If we couldn't write, assume fatal error for now */
if ( towrite != 0 ) { if (towrite != 0)
{
this->enabled = 0; this->enabled = 0;
} }
return; return;
} }
static Uint8 *NTO_GetAudioBuf(_THIS) static Uint8* NTO_GetAudioBuf(_THIS)
{ {
#ifdef DEBUG_AUDIO return pcm_buf;
fprintf(stderr, "NTO_GetAudioBuf: pcm_buf %X\n",(Uint8 *)pcm_buf);
#endif
return(pcm_buf);
} }
static void NTO_CloseAudio(_THIS) static void NTO_CloseAudio(_THIS)
{ {
int rval; int rval;
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_CloseAudio\n");
#endif
this->enabled = 0; this->enabled = 0;
if ( audio_handle != NULL ) { if (audio_handle != NULL)
if ((rval = snd_pcm_plugin_flush(audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0){ {
SDL_SetError("snd_pcm_plugin_flush failed: %s\n",snd_strerror(rval)); if ((rval = snd_pcm_plugin_flush(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
{
SDL_SetError("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n", snd_strerror(rval));
return; return;
} }
if ((rval = snd_pcm_close(audio_handle)) < 0){ if ((rval = snd_pcm_close(audio_handle)) < 0)
SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval)); {
SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",snd_strerror(rval));
return; return;
} }
audio_handle = NULL; audio_handle = NULL;
} }
} }
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec) static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec)
{ {
int rval; int rval;
int format; int format;
Uint16 test_format; Uint16 test_format;
int twidth;
int found; int found;
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_OpenAudio\n");
#endif
audio_handle = NULL; audio_handle = NULL;
this->enabled = 0; this->enabled = 0;
if ( pcm_buf != NULL ) { if (pcm_buf != NULL)
free((Uint8 *)pcm_buf); {
SDL_FreeAudioMem(pcm_buf);
pcm_buf = NULL; pcm_buf = NULL;
} }
/* initialize channel transfer parameters to default */ /* initialize channel transfer parameters to default */
init_pcm_cparams(&cparams); NTO_InitAudioParams(&cparams);
/* Open the audio device */ /* Open the audio device */
rval = snd_pcm_open_preferred(&audio_handle, NULL, NULL, OPEN_FLAGS); rval = snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
if ( rval < 0 ) { if (rval < 0)
SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval)); {
return(-1); SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", snd_strerror(rval));
return (-1);
} }
if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND))
{
/* enable count status parameter */ /* enable count status parameter */
if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP))<0){ if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP)) < 0)
{
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval)); SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval));
return(-1); return (-1);
}
} }
/* Try for a closest match on audio format */ /* Try for a closest match on audio format */
format = 0; format = 0;
found = 0; /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
for ( test_format = SDL_FirstAudioFormat(spec->format); !found ; ) found = 0;
{
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x spec->samples %d\n", test_format,spec->samples);
#endif
for (test_format=SDL_FirstAudioFormat(spec->format); !found ;)
{
/* if match found set format to equivalent ALSA format */ /* if match found set format to equivalent ALSA format */
switch ( test_format ) { switch (test_format)
{
case AUDIO_U8: case AUDIO_U8:
format = SND_PCM_SFMT_U8; format = SND_PCM_SFMT_U8;
found = 1; found = 1;
...@@ -378,15 +421,18 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec) ...@@ -378,15 +421,18 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec)
default: default:
break; break;
} }
if ( ! found ) {
if (!found)
{
test_format = SDL_NextAudioFormat(); test_format = SDL_NextAudioFormat();
} }
} }
/* assumes test_format not 0 on success */ /* assumes test_format not 0 on success */
if ( test_format == 0 ) { if (test_format == 0)
SDL_SetError("Couldn't find any hardware audio formats"); {
return(-1); SDL_SetError("NTO_OpenAudio(): Couldn't find any hardware audio formats");
return (-1);
} }
spec->format = test_format; spec->format = test_format;
...@@ -397,87 +443,61 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec) ...@@ -397,87 +443,61 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec)
/* Set mono or stereo audio (currently only two channels supported) */ /* Set mono or stereo audio (currently only two channels supported) */
cparams.format.voices = spec->channels; cparams.format.voices = spec->channels;
#ifdef DEBUG_AUDIO
fprintf(stderr,"intializing channels %d\n", cparams.format.voices);
#endif
/* Set rate */ /* Set rate */
cparams.format.rate = spec->freq ; cparams.format.rate = spec->freq;
/* Setup the transfer parameters according to cparams */ /* Setup the transfer parameters according to cparams */
rval = snd_pcm_plugin_params(audio_handle, &cparams); rval = snd_pcm_plugin_params(audio_handle, &cparams);
if (rval < 0) { if (rval < 0)
SDL_SetError("snd_pcm_channel_params failed: %s\n", snd_strerror (rval)); {
return(-1); SDL_SetError("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", snd_strerror(rval));
return (-1);
} }
/* Make sure channel is setup right one last time */ /* Make sure channel is setup right one last time */
memset( &csetup, 0, sizeof( csetup ) ); memset(&csetup, 0x00, sizeof(csetup));
csetup.channel = SND_PCM_CHANNEL_PLAYBACK; csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if ( snd_pcm_plugin_setup( audio_handle, &csetup ) < 0 ) if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0)
{
SDL_SetError("Unable to setup playback channel\n" );
return(-1);
}
else
{ {
#ifdef DEBUG_AUDIO SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
fprintf(stderr,"requested format: %d\n",cparams.format.format); return -1;
fprintf(stderr,"requested frag size: %d\n",cparams.buf.block.frag_size);
fprintf(stderr,"requested max frags: %d\n\n",cparams.buf.block.frags_max);
fprintf(stderr,"real format: %d\n", csetup.format.format );
fprintf(stderr,"real frag size : %d\n", csetup.buf.block.frag_size );
fprintf(stderr,"real max frags : %d\n", csetup.buf.block.frags_max );
#endif
} }
/*
Allocate memory to the audio buffer and initialize with silence (Note that
buffer size must be a multiple of fragment size, so find closest multiple)
*/
twidth = snd_pcm_format_width(format); /* Calculate the final parameters for this audio specification */
if (twidth < 0) { SDL_CalculateAudioSpec(spec);
printf("snd_pcm_format_width failed\n");
twidth = 0;
}
#ifdef DEBUG_AUDIO pcm_len = spec->size;
fprintf(stderr,"format is %d bits wide\n",twidth);
#endif
pcm_len = spec->size ; if (pcm_len==0)
{
#ifdef DEBUG_AUDIO pcm_len = csetup.buf.block.frag_size * spec->channels * (snd_pcm_format_width(format)/8);
fprintf(stderr,"pcm_len set to %d\n", pcm_len);
#endif
if (pcm_len == 0){
pcm_len = csetup.buf.block.frag_size;
} }
pcm_buf = (Uint8*)malloc(pcm_len); /* Allocate memory to the audio buffer and initialize with silence (Note that
if (pcm_buf == NULL) { buffer size must be a multiple of fragment size, so find closest multiple)
SDL_SetError("pcm_buf malloc failed\n"); */
return(-1); pcm_buf = (Uint8*)SDL_AllocAudioMem(pcm_len);
if (pcm_buf == NULL)
{
SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
return (-1);
} }
memset(pcm_buf,spec->silence,pcm_len); memset(pcm_buf, spec->silence, pcm_len);
#ifdef DEBUG_AUDIO
fprintf(stderr,"pcm_buf malloced and silenced.\n");
#endif
/* get the file descriptor */ /* get the file descriptor */
if( (audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0){ if ((audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
fprintf(stderr, "snd_pcm_file_descriptor failed with error code: %d\n", audio_fd); {
SDL_SetError("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", snd_strerror(rval));
return (-1);
} }
/* Trigger audio playback */ /* Trigger audio playback */
rval = snd_pcm_plugin_prepare( audio_handle, SND_PCM_CHANNEL_PLAYBACK); rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
if (rval < 0) { if (rval < 0)
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror (rval)); {
return(-1); SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
return (-1);
} }
this->enabled = 1; this->enabled = 1;
...@@ -485,6 +505,6 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec) ...@@ -485,6 +505,6 @@ static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec)
/* Get the parent process id (we're the parent of the audio thread) */ /* Get the parent process id (we're the parent of the audio thread) */
parent = getpid(); parent = getpid();
/* We're ready to rock and roll. :-) */ /* We're really ready to rock and roll. :-) */
return(0); return (0);
} }
...@@ -20,18 +20,21 @@ ...@@ -20,18 +20,21 @@
slouken@libsdl.org slouken@libsdl.org
*/ */
#ifndef _NTO_PCM_audio_h #ifndef __SDL_NTO_AUDIO_H__
#define _NTO_PCM_audio_h #define __SDL_NTO_AUDIO_H__
#include "SDL_sysaudio.h" #include "SDL_sysaudio.h"
#include <sys/asoundlib.h> #include <sys/asoundlib.h>
/* Hidden "this" pointer for the video functions */ /* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this #define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData { struct SDL_PrivateAudioData
{
/* The audio device handle */ /* The audio device handle */
snd_pcm_t *audio_handle; int cardno;
int deviceno;
snd_pcm_t* audio_handle;
/* The audio file descriptor */ /* The audio file descriptor */
int audio_fd; int audio_fd;
...@@ -40,16 +43,24 @@ struct SDL_PrivateAudioData { ...@@ -40,16 +43,24 @@ struct SDL_PrivateAudioData {
pid_t parent; pid_t parent;
/* Raw mixing buffer */ /* Raw mixing buffer */
Uint8 *pcm_buf; Uint8* pcm_buf;
int pcm_len; Uint32 pcm_len;
/* QSA parameters */
snd_pcm_channel_status_t cstatus;
snd_pcm_channel_params_t cparams;
snd_pcm_channel_setup_t csetup;
}; };
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
/* Old variable names */ #define cardno (this->hidden->cardno)
#define deviceno (this->hidden->deviceno)
#define audio_handle (this->hidden->audio_handle) #define audio_handle (this->hidden->audio_handle)
#define audio_fd (this->hidden->audio_fd) #define audio_fd (this->hidden->audio_fd)
#define parent (this->hidden->parent) #define parent (this->hidden->parent)
#define pcm_buf (this->hidden->pcm_buf) #define pcm_buf (this->hidden->pcm_buf)
#define pcm_len (this->hidden->pcm_len) #define pcm_len (this->hidden->pcm_len)
#define cstatus (this->hidden->cstatus)
#define cparams (this->hidden->cparams)
#define csetup (this->hidden->csetup)
#endif /* _NTO_PCM_audio_h */ #endif /* __SDL_NTO_AUDIO_H__ */
...@@ -64,12 +64,14 @@ static void* ph_GL_GetProcAddress(_THIS, const char* proc); ...@@ -64,12 +64,14 @@ static void* ph_GL_GetProcAddress(_THIS, const char* proc);
static int ph_GL_MakeCurrent(_THIS); static int ph_GL_MakeCurrent(_THIS);
#endif /* HAVE_OPENGL */ #endif /* HAVE_OPENGL */
static int phstatus=-1;
static int ph_Available(void) static int ph_Available(void)
{ {
int phstat=-1; if (phstatus==-1)
{
phstat=PtInit(0); phstatus=PtInit(NULL);
if (phstat==0) if (phstatus==0)
{ {
return 1; return 1;
} }
...@@ -77,6 +79,8 @@ static int ph_Available(void) ...@@ -77,6 +79,8 @@ static int ph_Available(void)
{ {
return 0; return 0;
} }
}
return 1;
} }
static SDL_VideoDevice *ph_CreateDevice(int devindex) static SDL_VideoDevice *ph_CreateDevice(int devindex)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment