From ba27176106682be6aaf266ee678ac8b0a2aa4935 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 20 Jul 2023 20:09:25 -0400 Subject: [PATCH] vitaaudio: Untested attempt to move Vita audio to SDL3's audio API. --- src/audio/vita/SDL_vitaaudio.c | 150 ++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 66 deletions(-) diff --git a/src/audio/vita/SDL_vitaaudio.c b/src/audio/vita/SDL_vitaaudio.c index 5cd40e6996..314f423027 100644 --- a/src/audio/vita/SDL_vitaaudio.c +++ b/src/audio/vita/SDL_vitaaudio.c @@ -38,41 +38,41 @@ #define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63) #define SCE_AUDIO_MAX_VOLUME 0x8000 -static int VITAAUD_OpenCaptureDevice(SDL_AudioDevice *_this) +static int VITAAUD_OpenCaptureDevice(SDL_AudioDevice *device) { - _this->spec.freq = 16000; - _this->spec.samples = 512; - _this->spec.channels = 1; + device->spec.freq = 16000; + device->spec.channels = 1; + device->sample_frames = 512; - SDL_CalculateAudioSpec(&_this->spec); + SDL_UpdatedAudioDeviceFormat(device); - _this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE, 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO); + device->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE, 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO); - if (_this->hidden->port < 0) { - return SDL_SetError("Couldn't open audio in port: %x", _this->hidden->port); + if (device->hidden->port < 0) { + return SDL_SetError("Couldn't open audio in port: %x", device->hidden->port); } return 0; } -static int VITAAUD_OpenDevice(SDL_AudioDevice *_this, const char *devname) +static int VITAAUD_OpenDevice(SDL_AudioDevice *device, const char *devname) { int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN; int vols[2] = { SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME }; SDL_AudioFormat test_format; const SDL_AudioFormat *closefmts; - _this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc(sizeof(*_this->hidden)); - if (_this->hidden == NULL) { + device->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc(sizeof(*device->hidden)); + if (device->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(_this->hidden, 0, sizeof(*_this->hidden)); + SDL_memset(device->hidden, 0, sizeof(*device->hidden)); - closefmts = SDL_ClosestAudioFormats(_this->spec.format); + closefmts = SDL_ClosestAudioFormats(device->spec.format); while ((test_format = *(closefmts++)) != 0) { if (test_format == SDL_AUDIO_S16LSB) { - _this->spec.format = test_format; + device->spec.format = test_format; break; } } @@ -81,106 +81,125 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *_this, const char *devname) return SDL_SetError("Unsupported audio format"); } - if (_this->iscapture) { - return VITAAUD_OpenCaptureDevice(_this); + if (device->iscapture) { + return VITAAUD_OpenCaptureDevice(device); } - /* The sample count must be a multiple of 64. */ - _this->spec.samples = SCE_AUDIO_SAMPLE_ALIGN(_this->spec.samples); + // The sample count must be a multiple of 64. + device->sample_frames = SCE_AUDIO_SAMPLE_ALIGN(device->sample_frames); - /* Update the fragment size as size in bytes. */ - SDL_CalculateAudioSpec(&_this->spec); + // Update the fragment size as size in bytes. + SDL_UpdatedAudioDeviceFormat(device); /* Allocate the mixing buffer. Its size and starting address must be a multiple of 64 bytes. Our sample count is already a multiple of 64, so spec->size should be a multiple of 64 as well. */ - mixlen = _this->spec.size * NUM_BUFFERS; - _this->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen); - if (_this->hidden->rawbuf == NULL) { + mixlen = device->buffer_size * NUM_BUFFERS; + device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen); + if (device->hidden->rawbuf == NULL) { return SDL_SetError("Couldn't allocate mixing buffer"); } - /* Setup the hardware channel. */ - if (_this->spec.channels == 1) { + // Setup the hardware channel. + if (device->spec.channels == 1) { format = SCE_AUDIO_OUT_MODE_MONO; } else { format = SCE_AUDIO_OUT_MODE_STEREO; } - if (_this->spec.freq < 48000) { + // the main port requires 48000Hz audio, so this drops to the background music port if necessary + if (device->spec.freq < 48000) { port = SCE_AUDIO_OUT_PORT_TYPE_BGM; } - _this->hidden->port = sceAudioOutOpenPort(port, _this->spec.samples, _this->spec.freq, format); - if (_this->hidden->port < 0) { - SDL_aligned_free(_this->hidden->rawbuf); - _this->hidden->rawbuf = NULL; - return SDL_SetError("Couldn't open audio out port: %x", _this->hidden->port); + device->hidden->port = sceAudioOutOpenPort(port, device->sample_frames, device->spec.freq, format); + if (device->hidden->port < 0) { + SDL_aligned_free(device->hidden->rawbuf); + device->hidden->rawbuf = NULL; + return SDL_SetError("Couldn't open audio out port: %x", device->hidden->port); } - sceAudioOutSetVolume(_this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols); + sceAudioOutSetVolume(device->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols); - SDL_memset(_this->hidden->rawbuf, 0, mixlen); + SDL_memset(device->hidden->rawbuf, 0, mixlen); for (i = 0; i < NUM_BUFFERS; i++) { - _this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size]; + device->hidden->mixbufs[i] = &device->hidden->rawbuf[i * device->buffer_size]; } - _this->hidden->next_buffer = 0; + device->hidden->next_buffer = 0; return 0; } -static void VITAAUD_PlayDevice(SDL_AudioDevice *_this) +static void VITAAUD_PlayDevice(SDL_AudioDevice *device) { - Uint8 *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer]; + Uint8 *mixbuf = device->hidden->mixbufs[device->hidden->next_buffer]; - sceAudioOutOutput(_this->hidden->port, mixbuf); + sceAudioOutOutput(device->hidden->port, mixbuf); - _this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS; + device->hidden->next_buffer = (device->hidden->next_buffer + 1) % NUM_BUFFERS; } -/* This function waits until it is possible to write a full sound buffer */ -static void VITAAUD_WaitDevice(SDL_AudioDevice *_this) +// This function waits until it is possible to write a full sound buffer +static void VITAAUD_WaitDevice(SDL_AudioDevice *device) { - /* Because we block when sending audio, there's no need for this function to do anything. */ + // !!! FIXME: we might just need to sleep roughly as long as playback buffers take to process, based on sample rate, etc. + while (!SDL_AtomicGet(&device->shutdown) && (sceAudioOutGetRestSample(device->hidden->port) >= device->buffer_size)) { + SDL_Delay(1); + } } -static Uint8 *VITAAUD_GetDeviceBuf(SDL_AudioDevice *_this) +static Uint8 *VITAAUD_GetDeviceBuf(SDL_AudioDevice *device) { - return _this->hidden->mixbufs[_this->hidden->next_buffer]; + return device->hidden->mixbufs[device->hidden->next_buffer]; } -static void VITAAUD_CloseDevice(SDL_AudioDevice *_this) +static void VITAAUD_CloseDevice(SDL_AudioDevice *device) { - if (_this->hidden->port >= 0) { - if (_this->iscapture) { - sceAudioInReleasePort(_this->hidden->port); + if (device->hidden->port >= 0) { + if (device->iscapture) { + sceAudioInReleasePort(device->hidden->port); } else { - sceAudioOutReleasePort(_this->hidden->port); + sceAudioOutReleasePort(device->hidden->port); } - _this->hidden->port = -1; + device->hidden->port = -1; } - if (!_this->iscapture && _this->hidden->rawbuf != NULL) { - SDL_aligned_free(_this->hidden->rawbuf); - _this->hidden->rawbuf = NULL; + if (!device->iscapture && device->hidden->rawbuf != NULL) { + SDL_aligned_free(device->hidden->rawbuf); + device->hidden->rawbuf = NULL; } } -static int VITAAUD_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen) +static void VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device) +{ + // there's only a blocking call to obtain more data, so we'll just sleep as + // long as a buffer would run. + const Uint64 endticks = SDL_GetTicks() + ((device->sample_frames * 1000) / device->spec.freq); + while (!SDL_AtomicGet(&device->shutdown) && (SDL_GetTicks() < endticks)) { + SDL_Delay(1); + } +} + +static int VITAAUD_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen) { int ret; - SDL_assert(buflen == _this->spec.size); - ret = sceAudioInInput(_this->hidden->port, buffer); + SDL_assert(buflen == device->buffer_size); + ret = sceAudioInInput(device->hidden->port, buffer); if (ret < 0) { return SDL_SetError("Failed to capture from device: %x", ret); } - return _this->spec.size; + return device->buffer_size; } -static void VITAAUD_ThreadInit(SDL_AudioDevice *_this) +static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device) { - /* Increase the priority of this audio thread by 1 to put it - ahead of other SDL threads. */ + // just grab the latest and dump it. + sceAudioInInput(device->hidden->port, device->work_buffer); +} + +static void VITAAUD_ThreadInit(SDL_AudioDevice *device) +{ + // Increase the priority of this audio thread by 1 to put it ahead of other SDL threads. SceUID thid; SceKernelThreadInfo info; thid = sceKernelGetThreadId(); @@ -192,26 +211,25 @@ static void VITAAUD_ThreadInit(SDL_AudioDevice *_this) static SDL_bool VITAAUD_Init(SDL_AudioDriverImpl *impl) { - /* Set the function pointers */ impl->OpenDevice = VITAAUD_OpenDevice; impl->PlayDevice = VITAAUD_PlayDevice; impl->WaitDevice = VITAAUD_WaitDevice; impl->GetDeviceBuf = VITAAUD_GetDeviceBuf; impl->CloseDevice = VITAAUD_CloseDevice; impl->ThreadInit = VITAAUD_ThreadInit; - + impl->WaitCaptureDevice = VITAAUD_WaitCaptureDevice; + impl->FlushCapture = VITAAUD_FlushCapture; impl->CaptureFromDevice = VITAAUD_CaptureFromDevice; - /* and the capabilities */ impl->HasCaptureSupport = SDL_TRUE; impl->OnlyHasDefaultOutputDevice = SDL_TRUE; impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; - return SDL_TRUE; /* this audio target is available. */ + return SDL_TRUE; } AudioBootStrap VITAAUD_bootstrap = { "vita", "VITA audio driver", VITAAUD_Init, SDL_FALSE }; -#endif /* SDL_AUDIO_DRIVER_VITA */ +#endif // SDL_AUDIO_DRIVER_VITA