(Audio) Update audio drivers to make them more uniform
This commit is contained in:
parent
22b789cca6
commit
ee7051891b
|
@ -245,7 +245,7 @@ static void *coreaudio_init(const char *device,
|
||||||
#else
|
#else
|
||||||
comp = AudioComponentFindNext(NULL, &desc);
|
comp = AudioComponentFindNext(NULL, &desc);
|
||||||
#endif
|
#endif
|
||||||
if (comp == NULL)
|
if (!comp)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
|
#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
|
||||||
|
|
|
@ -260,22 +260,37 @@ static bool g_interrupted;
|
||||||
|
|
||||||
- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples {
|
- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples {
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
while (!g_interrupted && samples > 0)
|
|
||||||
|
if (_nonBlock)
|
||||||
{
|
{
|
||||||
size_t write_avail = rb_avail(&_rb);
|
if (!g_interrupted && samples > 0)
|
||||||
if (write_avail > samples)
|
{
|
||||||
write_avail = samples;
|
size_t write_avail = rb_avail(&_rb);
|
||||||
|
if (write_avail > samples)
|
||||||
|
write_avail = samples;
|
||||||
|
|
||||||
rb_write_data(&_rb, data, write_avail);
|
rb_write_data(&_rb, data, write_avail);
|
||||||
data += write_avail;
|
data += write_avail;
|
||||||
written += write_avail;
|
written += write_avail;
|
||||||
samples -= write_avail;
|
samples -= write_avail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (!g_interrupted && samples > 0)
|
||||||
|
{
|
||||||
|
size_t write_avail = rb_avail(&_rb);
|
||||||
|
if (write_avail > samples)
|
||||||
|
write_avail = samples;
|
||||||
|
|
||||||
if (_nonBlock)
|
rb_write_data(&_rb, data, write_avail);
|
||||||
break;
|
data += write_avail;
|
||||||
|
written += write_avail;
|
||||||
|
samples -= write_avail;
|
||||||
|
|
||||||
if (write_avail == 0)
|
if (write_avail == 0)
|
||||||
dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return written;
|
return written;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
bool playing;
|
bool playing;
|
||||||
int16_t* l;
|
int16_t* l;
|
||||||
int16_t* r;
|
int16_t* r;
|
||||||
|
@ -180,7 +180,7 @@ static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size)
|
||||||
(((ctr->pos - ctr->playpos ) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)) ||
|
(((ctr->pos - ctr->playpos ) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)) ||
|
||||||
(((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (size >> 2)))
|
(((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||||
{
|
{
|
||||||
if (ctr->nonblocking)
|
if (ctr->nonblock)
|
||||||
ctr->pos = (ctr->playpos + (CTR_CSND_AUDIO_COUNT >> 1)) & CTR_CSND_AUDIO_COUNT_MASK;
|
ctr->pos = (ctr->playpos + (CTR_CSND_AUDIO_COUNT >> 1)) & CTR_CSND_AUDIO_COUNT_MASK;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -189,7 +189,7 @@ static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size)
|
||||||
retro_sleep(1);
|
retro_sleep(1);
|
||||||
ctr_csnd_audio_update_playpos(ctr);
|
ctr_csnd_audio_update_playpos(ctr);
|
||||||
}while (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 1)
|
}while (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 1)
|
||||||
|| (((ctr->pos - ctr->playpos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)));
|
|| (((ctr->pos - ctr->playpos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ static void ctr_csnd_audio_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
ctr_csnd_audio_t* ctr = (ctr_csnd_audio_t*)data;
|
ctr_csnd_audio_t* ctr = (ctr_csnd_audio_t*)data;
|
||||||
if (ctr)
|
if (ctr)
|
||||||
ctr->nonblocking = state;
|
ctr->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ctr_csnd_audio_use_float(void *data)
|
static bool ctr_csnd_audio_use_float(void *data)
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
bool playing;
|
bool playing;
|
||||||
int channel;
|
int channel;
|
||||||
ndspWaveBuf dsp_buf;
|
ndspWaveBuf dsp_buf;
|
||||||
|
@ -102,7 +102,7 @@ static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size)
|
||||||
(((ctr->pos - sample_pos ) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4)) ||
|
(((ctr->pos - sample_pos ) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4)) ||
|
||||||
(((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (size >> 2)))
|
(((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||||
{
|
{
|
||||||
if (ctr->nonblocking)
|
if (ctr->nonblock)
|
||||||
ctr->pos = (sample_pos + (CTR_DSP_AUDIO_COUNT >> 1)) & CTR_DSP_AUDIO_COUNT_MASK;
|
ctr->pos = (sample_pos + (CTR_DSP_AUDIO_COUNT >> 1)) & CTR_DSP_AUDIO_COUNT_MASK;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -173,7 +173,7 @@ static void ctr_dsp_audio_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
ctr_dsp_audio_t* ctr = (ctr_dsp_audio_t*)data;
|
ctr_dsp_audio_t* ctr = (ctr_dsp_audio_t*)data;
|
||||||
if (ctr)
|
if (ctr)
|
||||||
ctr->nonblocking = state;
|
ctr->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ctr_dsp_audio_use_float(void *data)
|
static bool ctr_dsp_audio_use_float(void *data)
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
|
|
||||||
typedef struct ps2_audio
|
typedef struct ps2_audio
|
||||||
{
|
{
|
||||||
bool nonblocking;
|
/* TODO/FIXME - nonblock is not implemented */
|
||||||
|
bool nonblock;
|
||||||
bool running;
|
bool running;
|
||||||
|
|
||||||
} ps2_audio_t;
|
} ps2_audio_t;
|
||||||
|
@ -39,11 +40,11 @@ static void audioConfigure(ps2_audio_t *ps2, unsigned rate)
|
||||||
int err;
|
int err;
|
||||||
struct audsrv_fmt_t format;
|
struct audsrv_fmt_t format;
|
||||||
|
|
||||||
format.bits = AUDIO_BITS;
|
format.bits = AUDIO_BITS;
|
||||||
format.freq = rate;
|
format.freq = rate;
|
||||||
format.channels = AUDIO_CHANNELS;
|
format.channels = AUDIO_CHANNELS;
|
||||||
|
|
||||||
err = audsrv_set_format(&format);
|
err = audsrv_set_format(&format);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
@ -82,15 +83,12 @@ static void ps2_audio_free(void *data)
|
||||||
|
|
||||||
static ssize_t ps2_audio_write(void *data, const void *buf, size_t size)
|
static ssize_t ps2_audio_write(void *data, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
int bytes_sent;
|
|
||||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||||
|
|
||||||
if (!ps2->running)
|
if (!ps2->running)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
bytes_sent = audsrv_play_audio(buf, size);
|
return audsrv_play_audio(buf, size);
|
||||||
|
|
||||||
return bytes_sent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ps2_audio_alive(void *data)
|
static bool ps2_audio_alive(void *data)
|
||||||
|
@ -134,7 +132,7 @@ static void ps2_audio_set_nonblock_state(void *data, bool toggle)
|
||||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||||
|
|
||||||
if (ps2)
|
if (ps2)
|
||||||
ps2->nonblocking = toggle;
|
ps2->nonblock = toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ps2_audio_use_float(void *data)
|
static bool ps2_audio_use_float(void *data)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t audio_port;
|
uint32_t audio_port;
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
bool started;
|
bool started;
|
||||||
volatile bool quit_thread;
|
volatile bool quit_thread;
|
||||||
fifo_buffer_t *buffer;
|
fifo_buffer_t *buffer;
|
||||||
|
@ -150,7 +150,7 @@ static ssize_t ps3_audio_write(void *data, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
ps3_audio_t *aud = data;
|
ps3_audio_t *aud = data;
|
||||||
|
|
||||||
if (aud->nonblocking)
|
if (aud->nonblock)
|
||||||
{
|
{
|
||||||
if (fifo_write_avail(aud->buffer) < size)
|
if (fifo_write_avail(aud->buffer) < size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -200,7 +200,7 @@ static void ps3_audio_set_nonblock_state(void *data, bool toggle)
|
||||||
{
|
{
|
||||||
ps3_audio_t *aud = data;
|
ps3_audio_t *aud = data;
|
||||||
if (aud)
|
if (aud)
|
||||||
aud->nonblocking = toggle;
|
aud->nonblock = toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ps3_audio_free(void *data)
|
static void ps3_audio_free(void *data)
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
|
|
||||||
typedef struct psp_audio
|
typedef struct psp_audio
|
||||||
{
|
{
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
|
|
||||||
uint32_t* buffer;
|
uint32_t* buffer;
|
||||||
uint32_t* zeroBuffer;
|
uint32_t* zeroBuffer;
|
||||||
|
@ -167,7 +167,7 @@ static void *psp_audio_init(const char *device,
|
||||||
psp->cond_lock = slock_new();
|
psp->cond_lock = slock_new();
|
||||||
psp->cond = scond_new();
|
psp->cond = scond_new();
|
||||||
|
|
||||||
psp->nonblocking = false;
|
psp->nonblock = false;
|
||||||
psp->running = true;
|
psp->running = true;
|
||||||
psp->worker_thread = sthread_create(audioMainLoop, psp);
|
psp->worker_thread = sthread_create(audioMainLoop, psp);
|
||||||
|
|
||||||
|
@ -202,18 +202,18 @@ static void psp_audio_free(void *data)
|
||||||
|
|
||||||
static ssize_t psp_audio_write(void *data, const void *buf, size_t size)
|
static ssize_t psp_audio_write(void *data, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
psp_audio_t* psp = (psp_audio_t*)data;
|
psp_audio_t* psp = (psp_audio_t*)data;
|
||||||
uint16_t write_pos = psp->write_pos;
|
uint16_t write_pos = psp->write_pos;
|
||||||
uint16_t sampleCount = size / sizeof(uint32_t);
|
uint16_t sampleCount = size / sizeof(uint32_t);
|
||||||
|
|
||||||
if (!psp->running)
|
if (!psp->running)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (psp->nonblocking)
|
if (psp->nonblock)
|
||||||
{
|
{
|
||||||
if (AUDIO_BUFFER_SIZE - ((uint16_t)
|
if (AUDIO_BUFFER_SIZE - ((uint16_t)
|
||||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size)
|
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
slock_lock(psp->cond_lock);
|
slock_lock(psp->cond_lock);
|
||||||
|
@ -287,7 +287,7 @@ static void psp_audio_set_nonblock_state(void *data, bool toggle)
|
||||||
{
|
{
|
||||||
psp_audio_t* psp = (psp_audio_t*)data;
|
psp_audio_t* psp = (psp_audio_t*)data;
|
||||||
if (psp)
|
if (psp)
|
||||||
psp->nonblocking = toggle;
|
psp->nonblock = toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool psp_audio_use_float(void *data)
|
static bool psp_audio_use_float(void *data)
|
||||||
|
|
|
@ -165,7 +165,7 @@ static bool rs_stop(void *data)
|
||||||
|
|
||||||
static void rs_set_nonblock_state(void *data, bool state)
|
static void rs_set_nonblock_state(void *data, bool state)
|
||||||
{
|
{
|
||||||
rsd_t *rsd = (rsd_t*)data;
|
rsd_t *rsd = (rsd_t*)data;
|
||||||
rsd->nonblock = state;
|
rsd->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,27 +92,25 @@ static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
|
||||||
|
|
||||||
if (!swa->current_buffer)
|
if (!swa->current_buffer)
|
||||||
{
|
{
|
||||||
if (swa->blocking)
|
/* no buffer, nonblocking... */
|
||||||
|
if (!swa->blocking)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (!swa->current_buffer)
|
||||||
{
|
{
|
||||||
while(swa->current_buffer == NULL)
|
uint32_t handle_idx = 0;
|
||||||
{
|
num = 0;
|
||||||
uint32_t handle_idx = 0;
|
|
||||||
num = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBNX
|
#ifdef HAVE_LIBNX
|
||||||
if (audoutWaitPlayFinish(&swa->current_buffer, &num, U64_MAX) != 0) { }
|
if (audoutWaitPlayFinish(&swa->current_buffer, &num, U64_MAX) != 0) { }
|
||||||
#else
|
#else
|
||||||
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
||||||
svcResetSignal(swa->event);
|
svcResetSignal(swa->event);
|
||||||
|
|
||||||
if (switch_audio_ipc_output_get_released_buffer(swa, num) != 0)
|
if (switch_audio_ipc_output_get_released_buffer(swa, num) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
/* no buffer, nonblocking... */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
swa->current_buffer->data_size = 0;
|
swa->current_buffer->data_size = 0;
|
||||||
|
@ -297,7 +295,7 @@ static void *switch_audio_init(const char *device,
|
||||||
swa->buffers[i].data_offset = 0;
|
swa->buffers[i].data_offset = 0;
|
||||||
swa->buffers[i].buffer = memalign(0x1000, switch_audio_buffer_size(NULL));
|
swa->buffers[i].buffer = memalign(0x1000, switch_audio_buffer_size(NULL));
|
||||||
|
|
||||||
if (swa->buffers[i].buffer == NULL)
|
if (!swa->buffers[i].buffer)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
|
|
||||||
memset(swa->buffers[i].buffer, 0, switch_audio_buffer_size(NULL));
|
memset(swa->buffers[i].buffer, 0, switch_audio_buffer_size(NULL));
|
||||||
|
@ -306,7 +304,7 @@ static void *switch_audio_init(const char *device,
|
||||||
swa->buffers[i].unknown = 0;
|
swa->buffers[i].unknown = 0;
|
||||||
swa->buffers[i].sample_data = alloc_pages(sample_buffer_size, switch_audio_buffer_size(NULL), NULL);
|
swa->buffers[i].sample_data = alloc_pages(sample_buffer_size, switch_audio_buffer_size(NULL), NULL);
|
||||||
|
|
||||||
if (swa->buffers[i].sample_data == NULL)
|
if (!swa->buffers[i].sample_data)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ static const AudioRendererConfig audio_renderer_config =
|
||||||
.num_mix_buffers = 2,
|
.num_mix_buffers = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
AudioDriver drv;
|
AudioDriver drv;
|
||||||
void* mempool;
|
void* mempool;
|
||||||
AudioDriverWaveBuf wavebufs[BUFFER_COUNT];
|
AudioDriverWaveBuf wavebufs[BUFFER_COUNT];
|
||||||
|
@ -52,10 +53,11 @@ typedef struct {
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
size_t samples;
|
size_t samples;
|
||||||
Mutex update_lock;
|
Mutex update_lock;
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
} libnx_audren_t;
|
} libnx_audren_t;
|
||||||
|
|
||||||
static void *libnx_audren_audio_init(const char *device, unsigned rate, unsigned latency,
|
static void *libnx_audren_audio_init(
|
||||||
|
const char *device, unsigned rate, unsigned latency,
|
||||||
unsigned block_frames,
|
unsigned block_frames,
|
||||||
unsigned *new_rate)
|
unsigned *new_rate)
|
||||||
{
|
{
|
||||||
|
@ -79,14 +81,14 @@ static void *libnx_audren_audio_init(const char *device, unsigned rate, unsigned
|
||||||
real_latency = MAX(5, latency);
|
real_latency = MAX(5, latency);
|
||||||
RARCH_LOG("[Audio]: real_latency is %u\n", real_latency);
|
RARCH_LOG("[Audio]: real_latency is %u\n", real_latency);
|
||||||
|
|
||||||
aud->nonblocking = !block_frames;
|
aud->nonblock = !block_frames;
|
||||||
aud->buffer_size = (real_latency * sample_rate / 1000);
|
aud->buffer_size = (real_latency * sample_rate / 1000);
|
||||||
aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t));
|
aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t));
|
||||||
aud->current_size = 0;
|
aud->current_size = 0;
|
||||||
*new_rate = sample_rate;
|
*new_rate = sample_rate;
|
||||||
|
|
||||||
mempool_size = (aud->buffer_size * BUFFER_COUNT + (AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1);
|
mempool_size = (aud->buffer_size * BUFFER_COUNT + (AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1);
|
||||||
aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size);
|
aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size);
|
||||||
if (!aud->mempool)
|
if (!aud->mempool)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: mempool alloc failed\n");
|
RARCH_ERR("[Audio]: mempool alloc failed\n");
|
||||||
|
@ -94,14 +96,14 @@ static void *libnx_audren_audio_init(const char *device, unsigned rate, unsigned
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = audrenInitialize(&audio_renderer_config);
|
rc = audrenInitialize(&audio_renderer_config);
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrenInitialize: %x\n", rc);
|
RARCH_ERR("[Audio]: audrenInitialize: %x\n", rc);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = audrvCreate(&aud->drv, &audio_renderer_config, num_channels);
|
rc = audrvCreate(&aud->drv, &audio_renderer_config, num_channels);
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrvCreate: %x\n", rc);
|
RARCH_ERR("[Audio]: audrvCreate: %x\n", rc);
|
||||||
goto fail_init;
|
goto fail_init;
|
||||||
|
@ -123,7 +125,7 @@ static void *libnx_audren_audio_init(const char *device, unsigned rate, unsigned
|
||||||
audrvDeviceSinkAdd(&aud->drv, AUDREN_DEFAULT_DEVICE_NAME, num_channels, sink_channels);
|
audrvDeviceSinkAdd(&aud->drv, AUDREN_DEFAULT_DEVICE_NAME, num_channels, sink_channels);
|
||||||
|
|
||||||
rc = audrenStartAudioRenderer();
|
rc = audrenStartAudioRenderer();
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrenStartAudioRenderer: %x\n", rc);
|
RARCH_ERR("[Audio]: audrenStartAudioRenderer: %x\n", rc);
|
||||||
}
|
}
|
||||||
|
@ -150,9 +152,7 @@ fail:
|
||||||
if (aud)
|
if (aud)
|
||||||
{
|
{
|
||||||
if (aud->mempool)
|
if (aud->mempool)
|
||||||
{
|
|
||||||
free(aud->mempool);
|
free(aud->mempool);
|
||||||
}
|
|
||||||
|
|
||||||
free(aud);
|
free(aud);
|
||||||
}
|
}
|
||||||
|
@ -176,24 +176,25 @@ static ssize_t libnx_audren_audio_get_free_wavebuf_idx(libnx_audren_t* aud)
|
||||||
|
|
||||||
for (i = 0; i < BUFFER_COUNT; i++)
|
for (i = 0; i < BUFFER_COUNT; i++)
|
||||||
{
|
{
|
||||||
if (aud->wavebufs[i].state == AudioDriverWaveBufState_Free
|
if (
|
||||||
|
aud->wavebufs[i].state == AudioDriverWaveBufState_Free
|
||||||
|| aud->wavebufs[i].state == AudioDriverWaveBufState_Done)
|
|| aud->wavebufs[i].state == AudioDriverWaveBufState_Done)
|
||||||
{
|
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t libnx_audren_audio_append(libnx_audren_t* aud, const void *buf, size_t size)
|
static size_t libnx_audren_audio_append(
|
||||||
|
libnx_audren_t* aud, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
|
void *dstbuf = NULL;
|
||||||
ssize_t free_idx = -1;
|
ssize_t free_idx = -1;
|
||||||
|
|
||||||
if(!aud->current_wavebuf)
|
if (!aud->current_wavebuf)
|
||||||
{
|
{
|
||||||
free_idx = libnx_audren_audio_get_free_wavebuf_idx(aud);
|
free_idx = libnx_audren_audio_get_free_wavebuf_idx(aud);
|
||||||
if(free_idx == -1)
|
if (free_idx == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
aud->current_wavebuf = &aud->wavebufs[free_idx];
|
aud->current_wavebuf = &aud->wavebufs[free_idx];
|
||||||
|
@ -201,18 +202,16 @@ static size_t libnx_audren_audio_append(libnx_audren_t* aud, const void *buf, si
|
||||||
aud->current_size = 0;
|
aud->current_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(size > aud->buffer_size - aud->current_size)
|
if (size > aud->buffer_size - aud->current_size)
|
||||||
{
|
|
||||||
size = aud->buffer_size - aud->current_size;
|
size = aud->buffer_size - aud->current_size;
|
||||||
}
|
|
||||||
|
|
||||||
void *dstbuf = aud->current_pool_ptr + aud->current_size;
|
dstbuf = aud->current_pool_ptr + aud->current_size;
|
||||||
memcpy(dstbuf, buf, size);
|
memcpy(dstbuf, buf, size);
|
||||||
armDCacheFlush(dstbuf, size);
|
armDCacheFlush(dstbuf, size);
|
||||||
|
|
||||||
aud->current_size += size;
|
aud->current_size += size;
|
||||||
|
|
||||||
if(aud->current_size == aud->buffer_size)
|
if (aud->current_size == aud->buffer_size)
|
||||||
{
|
{
|
||||||
audrvVoiceAddWaveBuf(&aud->drv, 0, aud->current_wavebuf);
|
audrvVoiceAddWaveBuf(&aud->drv, 0, aud->current_wavebuf);
|
||||||
|
|
||||||
|
@ -231,24 +230,32 @@ static size_t libnx_audren_audio_append(libnx_audren_t* aud, const void *buf, si
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t libnx_audren_audio_write(void *data, const void *buf, size_t size)
|
static ssize_t libnx_audren_audio_write(void *data,
|
||||||
|
const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
libnx_audren_t *aud = (libnx_audren_t*)data;
|
libnx_audren_t *aud = (libnx_audren_t*)data;
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
if (!aud)
|
if (!aud)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while(written < size)
|
if (aud->nonblock)
|
||||||
{
|
{
|
||||||
written += libnx_audren_audio_append(aud, buf + written, size - written);
|
while(written < size)
|
||||||
if(written != size)
|
|
||||||
{
|
{
|
||||||
if(aud->nonblocking)
|
written += libnx_audren_audio_append(
|
||||||
{
|
aud, buf + written, size - written);
|
||||||
|
if (written != size)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(written < size)
|
||||||
|
{
|
||||||
|
written += libnx_audren_audio_append(
|
||||||
|
aud, buf + written, size - written);
|
||||||
|
if (written != size)
|
||||||
{
|
{
|
||||||
mutexLock(&aud->update_lock);
|
mutexLock(&aud->update_lock);
|
||||||
audrvUpdate(&aud->drv);
|
audrvUpdate(&aud->drv);
|
||||||
|
@ -341,7 +348,7 @@ static void libnx_audren_audio_set_nonblock_state(void *data, bool state)
|
||||||
if (!aud)
|
if (!aud)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
aud->nonblocking = state;
|
aud->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_driver_t audio_switch_libnx_audren = {
|
audio_driver_t audio_switch_libnx_audren = {
|
||||||
|
|
|
@ -43,13 +43,14 @@ static const AudioRendererConfig audio_renderer_config =
|
||||||
.num_mix_buffers = 2,
|
.num_mix_buffers = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
AudioDriver drv;
|
AudioDriver drv;
|
||||||
void* mempool;
|
void* mempool;
|
||||||
AudioDriverWaveBuf wavebufs[BUFFER_COUNT];
|
AudioDriverWaveBuf wavebufs[BUFFER_COUNT];
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
size_t samples;
|
size_t samples;
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
|
|
||||||
fifo_buffer_t* fifo;
|
fifo_buffer_t* fifo;
|
||||||
Mutex fifo_lock;
|
Mutex fifo_lock;
|
||||||
|
@ -63,21 +64,21 @@ typedef struct {
|
||||||
|
|
||||||
static void thread_job(void* data)
|
static void thread_job(void* data)
|
||||||
{
|
{
|
||||||
libnx_audren_thread_t *aud = (libnx_audren_thread_t*)data;
|
|
||||||
size_t available = 0;
|
|
||||||
size_t current_size = 0;
|
|
||||||
size_t written_tmp = 0;
|
|
||||||
AudioDriverWaveBuf* current_wavebuf = NULL;
|
|
||||||
void* current_pool_ptr = NULL;
|
|
||||||
void* dstbuf = NULL;
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
libnx_audren_thread_t *aud = (libnx_audren_thread_t*)data;
|
||||||
|
size_t available = 0;
|
||||||
|
size_t current_size = 0;
|
||||||
|
size_t written_tmp = 0;
|
||||||
|
AudioDriverWaveBuf* current_wavebuf = NULL;
|
||||||
|
void* current_pool_ptr = NULL;
|
||||||
|
void* dstbuf = NULL;
|
||||||
|
|
||||||
if (!aud)
|
if (!aud)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while(aud->running)
|
while (aud->running)
|
||||||
{
|
{
|
||||||
if(!current_wavebuf)
|
if (!current_wavebuf)
|
||||||
{
|
{
|
||||||
for (i = 0; i < BUFFER_COUNT; i++)
|
for (i = 0; i < BUFFER_COUNT; i++)
|
||||||
{
|
{
|
||||||
|
@ -92,19 +93,17 @@ static void thread_job(void* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current_wavebuf)
|
if (current_wavebuf)
|
||||||
{
|
{
|
||||||
mutexLock(&aud->fifo_lock);
|
mutexLock(&aud->fifo_lock);
|
||||||
available = aud->paused ? 0 : fifo_read_avail(aud->fifo);
|
available = aud->paused ? 0 : fifo_read_avail(aud->fifo);
|
||||||
written_tmp = MIN(available, aud->buffer_size - current_size);
|
written_tmp = MIN(available, aud->buffer_size - current_size);
|
||||||
dstbuf = current_pool_ptr + current_size;
|
dstbuf = current_pool_ptr + current_size;
|
||||||
if(written_tmp > 0)
|
if (written_tmp > 0)
|
||||||
{
|
|
||||||
fifo_read(aud->fifo, dstbuf, written_tmp);
|
fifo_read(aud->fifo, dstbuf, written_tmp);
|
||||||
}
|
|
||||||
mutexUnlock(&aud->fifo_lock);
|
mutexUnlock(&aud->fifo_lock);
|
||||||
|
|
||||||
if(written_tmp > 0)
|
if (written_tmp > 0)
|
||||||
{
|
{
|
||||||
condvarWakeAll(&aud->fifo_condvar);
|
condvarWakeAll(&aud->fifo_condvar);
|
||||||
|
|
||||||
|
@ -112,7 +111,7 @@ static void thread_job(void* data)
|
||||||
armDCacheFlush(dstbuf, written_tmp);
|
armDCacheFlush(dstbuf, written_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current_size == aud->buffer_size)
|
if (current_size == aud->buffer_size)
|
||||||
{
|
{
|
||||||
audrvVoiceAddWaveBuf(&aud->drv, 0, current_wavebuf);
|
audrvVoiceAddWaveBuf(&aud->drv, 0, current_wavebuf);
|
||||||
|
|
||||||
|
@ -157,17 +156,19 @@ static void *libnx_audren_thread_audio_init(const char *device, unsigned rate, u
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
real_latency = MAX(latency, 5);
|
real_latency = MAX(latency, 5);
|
||||||
RARCH_LOG("[Audio]: real_latency is %u\n", real_latency);
|
RARCH_LOG("[Audio]: real_latency is %u\n", real_latency);
|
||||||
|
|
||||||
aud->running = true;
|
aud->running = true;
|
||||||
aud->paused = false;
|
aud->paused = false;
|
||||||
aud->nonblocking = !block_frames;
|
aud->nonblock = !block_frames;
|
||||||
aud->buffer_size = (real_latency * sample_rate / 1000);
|
aud->buffer_size = (real_latency * sample_rate / 1000);
|
||||||
aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t));
|
aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t));
|
||||||
|
|
||||||
|
mempool_size = (aud->buffer_size * BUFFER_COUNT +
|
||||||
|
(AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1);
|
||||||
|
aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size);
|
||||||
|
|
||||||
mempool_size = (aud->buffer_size * BUFFER_COUNT + (AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1);
|
|
||||||
aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size);
|
|
||||||
if (!aud->mempool)
|
if (!aud->mempool)
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: mempool alloc failed\n");
|
RARCH_ERR("[Audio]: mempool alloc failed\n");
|
||||||
|
@ -175,43 +176,44 @@ static void *libnx_audren_thread_audio_init(const char *device, unsigned rate, u
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = audrenInitialize(&audio_renderer_config);
|
rc = audrenInitialize(&audio_renderer_config);
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrenInitialize: %x\n", rc);
|
RARCH_ERR("[Audio]: audrenInitialize: %x\n", rc);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = audrvCreate(&aud->drv, &audio_renderer_config, num_channels);
|
rc = audrvCreate(&aud->drv, &audio_renderer_config, num_channels);
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrvCreate: %x\n", rc);
|
RARCH_ERR("[Audio]: audrvCreate: %x\n", rc);
|
||||||
goto fail_init;
|
goto fail_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < BUFFER_COUNT; i++)
|
for (i = 0; i < BUFFER_COUNT; i++)
|
||||||
{
|
{
|
||||||
aud->wavebufs[i].data_raw = aud->mempool;
|
aud->wavebufs[i].data_raw = aud->mempool;
|
||||||
aud->wavebufs[i].size = mempool_size;
|
aud->wavebufs[i].size = mempool_size;
|
||||||
aud->wavebufs[i].start_sample_offset = i * aud->samples;
|
aud->wavebufs[i].start_sample_offset = i * aud->samples;
|
||||||
aud->wavebufs[i].end_sample_offset = aud->wavebufs[i].start_sample_offset + aud->samples;
|
aud->wavebufs[i].end_sample_offset = aud->wavebufs[i].start_sample_offset + aud->samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpid = audrvMemPoolAdd(&aud->drv, aud->mempool, mempool_size);
|
mpid = audrvMemPoolAdd(&aud->drv, aud->mempool, mempool_size);
|
||||||
audrvMemPoolAttach(&aud->drv, mpid);
|
audrvMemPoolAttach(&aud->drv, mpid);
|
||||||
|
|
||||||
audrvDeviceSinkAdd(&aud->drv, AUDREN_DEFAULT_DEVICE_NAME, num_channels, sink_channels);
|
audrvDeviceSinkAdd(&aud->drv, AUDREN_DEFAULT_DEVICE_NAME,
|
||||||
|
num_channels, sink_channels);
|
||||||
|
|
||||||
rc = audrenStartAudioRenderer();
|
rc = audrenStartAudioRenderer();
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: audrenStartAudioRenderer: %x\n", rc);
|
RARCH_ERR("[Audio]: audrenStartAudioRenderer: %x\n", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
audrvVoiceInit(&aud->drv, 0, num_channels, PcmFormat_Int16, sample_rate);
|
audrvVoiceInit(&aud->drv, 0, num_channels, PcmFormat_Int16, sample_rate);
|
||||||
audrvVoiceSetDestinationMix(&aud->drv, 0, AUDREN_FINAL_MIX_ID);
|
audrvVoiceSetDestinationMix(&aud->drv, 0, AUDREN_FINAL_MIX_ID);
|
||||||
for(i = 0; i < num_channels; i++)
|
for (i = 0; i < num_channels; i++)
|
||||||
{
|
{
|
||||||
for(j = 0; j < num_channels; j++)
|
for (j = 0; j < num_channels; j++)
|
||||||
{
|
{
|
||||||
audrvVoiceSetMixFactor(&aud->drv, 0, i == j ? 1.0f : 0.0f, i, j);
|
audrvVoiceSetMixFactor(&aud->drv, 0, i == j ? 1.0f : 0.0f, i, j);
|
||||||
}
|
}
|
||||||
|
@ -229,15 +231,17 @@ static void *libnx_audren_thread_audio_init(const char *device, unsigned rate, u
|
||||||
mutexInit(&aud->fifo_condlock);
|
mutexInit(&aud->fifo_condlock);
|
||||||
|
|
||||||
svcGetThreadPriority(&thread_priority, CUR_THREAD_HANDLE);
|
svcGetThreadPriority(&thread_priority, CUR_THREAD_HANDLE);
|
||||||
rc = threadCreate(&aud->thread, &thread_job, (void*)aud, thread_stack_size, thread_priority - 1, thread_preferred_cpu);
|
rc = threadCreate(&aud->thread, &thread_job,
|
||||||
if(R_FAILED(rc))
|
(void*)aud, thread_stack_size,
|
||||||
|
thread_priority - 1, thread_preferred_cpu);
|
||||||
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: threadCreate: %x\n", rc);
|
RARCH_ERR("[Audio]: threadCreate: %x\n", rc);
|
||||||
goto fail_drv;
|
goto fail_drv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = threadStart(&aud->thread);
|
rc = threadStart(&aud->thread);
|
||||||
if(R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
{
|
{
|
||||||
RARCH_ERR("[Audio]: threadStart: %x\n", rc);
|
RARCH_ERR("[Audio]: threadStart: %x\n", rc);
|
||||||
threadClose(&aud->thread);
|
threadClose(&aud->thread);
|
||||||
|
@ -258,9 +262,7 @@ fail:
|
||||||
if (aud)
|
if (aud)
|
||||||
{
|
{
|
||||||
if (aud->mempool)
|
if (aud->mempool)
|
||||||
{
|
|
||||||
free(aud->mempool);
|
free(aud->mempool);
|
||||||
}
|
|
||||||
|
|
||||||
free(aud);
|
free(aud);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +280,8 @@ static size_t libnx_audren_thread_audio_buffer_size(void *data)
|
||||||
return aud->buffer_size;
|
return aud->buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t libnx_audren_thread_audio_write(void *data, const void *buf, size_t size)
|
static ssize_t libnx_audren_thread_audio_write(void *data,
|
||||||
|
const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
libnx_audren_thread_t *aud = (libnx_audren_thread_t*)data;
|
libnx_audren_thread_t *aud = (libnx_audren_thread_t*)data;
|
||||||
size_t available, written, written_tmp;
|
size_t available, written, written_tmp;
|
||||||
|
@ -286,18 +289,16 @@ static ssize_t libnx_audren_thread_audio_write(void *data, const void *buf, size
|
||||||
if (!aud || !aud->running)
|
if (!aud || !aud->running)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(aud->paused)
|
if (aud->paused)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(aud->nonblocking)
|
if (aud->nonblock)
|
||||||
{
|
{
|
||||||
mutexLock(&aud->fifo_lock);
|
mutexLock(&aud->fifo_lock);
|
||||||
available = fifo_write_avail(aud->fifo);
|
available = fifo_write_avail(aud->fifo);
|
||||||
written = MIN(available, size);
|
written = MIN(available, size);
|
||||||
if(written > 0)
|
if (written > 0)
|
||||||
{
|
|
||||||
fifo_write(aud->fifo, buf, written);
|
fifo_write(aud->fifo, buf, written);
|
||||||
}
|
|
||||||
mutexUnlock(&aud->fifo_lock);
|
mutexUnlock(&aud->fifo_lock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -307,7 +308,7 @@ static ssize_t libnx_audren_thread_audio_write(void *data, const void *buf, size
|
||||||
{
|
{
|
||||||
mutexLock(&aud->fifo_lock);
|
mutexLock(&aud->fifo_lock);
|
||||||
available = fifo_write_avail(aud->fifo);
|
available = fifo_write_avail(aud->fifo);
|
||||||
if(available)
|
if (available)
|
||||||
{
|
{
|
||||||
written_tmp = MIN(size - written, available);
|
written_tmp = MIN(size - written, available);
|
||||||
fifo_write(aud->fifo, (const char*)buf + written, written_tmp);
|
fifo_write(aud->fifo, (const char*)buf + written, written_tmp);
|
||||||
|
@ -419,7 +420,7 @@ static void libnx_audren_thread_audio_set_nonblock_state(void *data, bool state)
|
||||||
if (!aud)
|
if (!aud)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
aud->nonblocking = state;
|
aud->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_driver_t audio_switch_libnx_audren_thread = {
|
audio_driver_t audio_switch_libnx_audren_thread = {
|
||||||
|
|
|
@ -53,7 +53,7 @@ typedef struct
|
||||||
size_t fifoSize;
|
size_t fifoSize;
|
||||||
|
|
||||||
volatile bool running;
|
volatile bool running;
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
|
|
||||||
compat_audio_out_buffer buffers[AUDIO_BUFFER_COUNT];
|
compat_audio_out_buffer buffers[AUDIO_BUFFER_COUNT];
|
||||||
|
@ -152,7 +152,7 @@ static void *switch_thread_audio_init(const char *device, unsigned rate, unsigne
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
swa->running = true;
|
swa->running = true;
|
||||||
swa->nonblocking = true;
|
swa->nonblock = true;
|
||||||
swa->is_paused = true;
|
swa->is_paused = true;
|
||||||
swa->latency = MAX(latency, 8);
|
swa->latency = MAX(latency, 8);
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ static void *switch_thread_audio_init(const char *device, unsigned rate, unsigne
|
||||||
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
||||||
swa->buffers[i].buffer = memalign(0x1000, swa->buffers[i].buffer_size);
|
swa->buffers[i].buffer = memalign(0x1000, swa->buffers[i].buffer_size);
|
||||||
|
|
||||||
if (swa->buffers[i].buffer == NULL)
|
if (!swa->buffers[i].buffer)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
memset(swa->buffers[i].buffer, 0, swa->buffers[i].buffer_size);
|
memset(swa->buffers[i].buffer, 0, swa->buffers[i].buffer_size);
|
||||||
|
@ -228,7 +228,7 @@ static void *switch_thread_audio_init(const char *device, unsigned rate, unsigne
|
||||||
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
swa->buffers[i].data_size = swa->buffers[i].buffer_size;
|
||||||
swa->buffers[i].sample_data = alloc_pages(swa->buffers[i].buffer_size, swa->buffers[i].buffer_size, NULL);
|
swa->buffers[i].sample_data = alloc_pages(swa->buffers[i].buffer_size, swa->buffers[i].buffer_size, NULL);
|
||||||
|
|
||||||
if (swa->buffers[i].sample_data == NULL)
|
if (!swa->buffers[i].sample_data)
|
||||||
goto fail_audio_output;
|
goto fail_audio_output;
|
||||||
|
|
||||||
memset(swa->buffers[i].sample_data, 0, swa->buffers[i].buffer_size);
|
memset(swa->buffers[i].sample_data, 0, swa->buffers[i].buffer_size);
|
||||||
|
@ -345,7 +345,7 @@ static ssize_t switch_thread_audio_write(void *data, const void *buf, size_t siz
|
||||||
if (!swa || !swa->running)
|
if (!swa || !swa->running)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (swa->nonblocking)
|
if (swa->nonblock)
|
||||||
{
|
{
|
||||||
compat_mutex_lock(&swa->fifoLock);
|
compat_mutex_lock(&swa->fifoLock);
|
||||||
avail = fifo_write_avail(swa->fifo);
|
avail = fifo_write_avail(swa->fifo);
|
||||||
|
@ -397,7 +397,7 @@ static void switch_thread_audio_set_nonblock_state(void *data, bool state)
|
||||||
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
switch_thread_audio_t *swa = (switch_thread_audio_t *)data;
|
||||||
|
|
||||||
if (swa)
|
if (swa)
|
||||||
swa->nonblocking = state;
|
swa->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool switch_thread_audio_use_float(void *data)
|
static bool switch_thread_audio_use_float(void *data)
|
||||||
|
|
|
@ -31,7 +31,7 @@ typedef struct
|
||||||
AXMVoice* mvoice;
|
AXMVoice* mvoice;
|
||||||
uint16_t* buffer_l;
|
uint16_t* buffer_l;
|
||||||
uint16_t* buffer_r;
|
uint16_t* buffer_r;
|
||||||
bool nonblocking;
|
bool nonblock;
|
||||||
|
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
uint32_t written;
|
uint32_t written;
|
||||||
|
@ -56,17 +56,19 @@ typedef struct
|
||||||
static volatile ax_audio_t *wiiu_cb_ax = NULL;
|
static volatile ax_audio_t *wiiu_cb_ax = NULL;
|
||||||
void wiiu_ax_callback(void)
|
void wiiu_ax_callback(void)
|
||||||
{
|
{
|
||||||
|
ax_audio_t *ax = NULL;
|
||||||
/*possibly called before unregister */
|
/*possibly called before unregister */
|
||||||
if(wiiu_cb_ax == NULL)
|
if (!wiiu_cb_ax)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ax_audio_t *ax = (ax_audio_t*)wiiu_cb_ax;
|
ax = (ax_audio_t*)wiiu_cb_ax;
|
||||||
if(AXIsMultiVoiceRunning(ax->mvoice))
|
|
||||||
|
if (AXIsMultiVoiceRunning(ax->mvoice))
|
||||||
{
|
{
|
||||||
if(OSUninterruptibleSpinLock_Acquire(&ax->spinlock))
|
if (OSUninterruptibleSpinLock_Acquire(&ax->spinlock))
|
||||||
{
|
{
|
||||||
/* Buffer underrun, stop playback to let it fill up */
|
/* Buffer underrun, stop playback to let it fill up */
|
||||||
if(ax->written < AX_AUDIO_SAMPLE_MIN)
|
if (ax->written < AX_AUDIO_SAMPLE_MIN)
|
||||||
AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_STOPPED);
|
AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_STOPPED);
|
||||||
ax->written -= AX_AUDIO_SAMPLE_COUNT;
|
ax->written -= AX_AUDIO_SAMPLE_COUNT;
|
||||||
OSUninterruptibleSpinLock_Release(&ax->spinlock);
|
OSUninterruptibleSpinLock_Release(&ax->spinlock);
|
||||||
|
@ -100,7 +102,7 @@ static void* ax_audio_init(const char* device, unsigned rate, unsigned latency,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ax->buffer_l = MEM1_alloc(AX_AUDIO_SIZE, 0x100);
|
ax->buffer_l = MEM1_alloc(AX_AUDIO_SIZE, 0x100);
|
||||||
ax->buffer_r = MEM1_alloc(AX_AUDIO_SIZE, 0x100);
|
ax->buffer_r = MEM1_alloc(AX_AUDIO_SIZE, 0x100);
|
||||||
memset(ax->buffer_l,0,AX_AUDIO_SIZE);
|
memset(ax->buffer_l,0,AX_AUDIO_SIZE);
|
||||||
memset(ax->buffer_r,0,AX_AUDIO_SIZE);
|
memset(ax->buffer_r,0,AX_AUDIO_SIZE);
|
||||||
|
@ -166,9 +168,9 @@ static bool ax_audio_stop(void* data)
|
||||||
|
|
||||||
static int ax_audio_limit(int in)
|
static int ax_audio_limit(int in)
|
||||||
{
|
{
|
||||||
if(in < 0)
|
if (in < 0)
|
||||||
in += AX_AUDIO_COUNT;
|
in += AX_AUDIO_COUNT;
|
||||||
else if(in >= AX_AUDIO_COUNT)
|
else if (in >= AX_AUDIO_COUNT)
|
||||||
in -= AX_AUDIO_COUNT;
|
in -= AX_AUDIO_COUNT;
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
@ -183,57 +185,58 @@ static bool ax_audio_start(void* data, bool is_shutdown)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Set back to playing on enough buffered data */
|
/* Set back to playing on enough buffered data */
|
||||||
if(ax->written > AX_AUDIO_SAMPLE_LOAD)
|
if (ax->written > AX_AUDIO_SAMPLE_LOAD)
|
||||||
{
|
{
|
||||||
AXSetMultiVoiceCurrentOffset(ax->mvoice, ax_audio_limit(ax->pos - ax->written));
|
AXSetMultiVoiceCurrentOffset(ax->mvoice, ax_audio_limit(ax->pos - ax->written));
|
||||||
AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_PLAYING);
|
AXSetMultiVoiceState(ax->mvoice, AX_VOICE_STATE_PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
|
static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
size_t countAvail = 0;
|
size_t count_avail = 0;
|
||||||
ax_audio_t* ax = (ax_audio_t*)data;
|
ax_audio_t* ax = (ax_audio_t*)data;
|
||||||
const uint16_t* src = buf;
|
const uint16_t* src = buf;
|
||||||
size_t count = size >> 2;
|
size_t count = size >> 2;
|
||||||
|
|
||||||
if(!size || (size & 0x3))
|
if (!size || (size & 0x3))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(count > AX_AUDIO_MAX_FREE)
|
if (count > AX_AUDIO_MAX_FREE)
|
||||||
count = AX_AUDIO_MAX_FREE;
|
count = AX_AUDIO_MAX_FREE;
|
||||||
|
|
||||||
countAvail = ((ax->written > AX_AUDIO_MAX_FREE) ? 0 : (AX_AUDIO_MAX_FREE - ax->written));
|
count_avail = ((ax->written > AX_AUDIO_MAX_FREE) ? 0 : (AX_AUDIO_MAX_FREE - ax->written));
|
||||||
|
|
||||||
if (ax->nonblocking)
|
if (ax->nonblock)
|
||||||
{
|
{
|
||||||
/* Not enough available for 3ms of data */
|
/* Not enough available for 3ms of data */
|
||||||
if(countAvail < AX_AUDIO_SAMPLE_COUNT)
|
if (count_avail < AX_AUDIO_SAMPLE_COUNT)
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
else if(countAvail < count)
|
else if (count_avail < count)
|
||||||
{
|
{
|
||||||
/* Sync, wait for free memory */
|
/* Sync, wait for free memory */
|
||||||
while(AXIsMultiVoiceRunning(ax->mvoice) && (countAvail < count))
|
while(AXIsMultiVoiceRunning(ax->mvoice) && (count_avail < count))
|
||||||
{
|
{
|
||||||
OSYieldThread(); /* Gives threads with same priority time to run */
|
OSYieldThread(); /* Gives threads with same priority time to run */
|
||||||
countAvail = (ax->written > AX_AUDIO_MAX_FREE ? 0 : (AX_AUDIO_MAX_FREE - ax->written));
|
count_avail = (ax->written > AX_AUDIO_MAX_FREE ? 0 : (AX_AUDIO_MAX_FREE - ax->written));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Over available space, do as much as possible */
|
/* Over available space, do as much as possible */
|
||||||
if(count > countAvail)
|
if (count > count_avail)
|
||||||
count = countAvail;
|
count = count_avail;
|
||||||
|
|
||||||
/* make sure we have input size */
|
/* make sure we have input size */
|
||||||
if(count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
/* write in new data */
|
/* write in new data */
|
||||||
size_t startPos = ax->pos;
|
size_t start_pos = ax->pos;
|
||||||
int flushP2needed = 0;
|
int flush_p2_needed = 0;
|
||||||
int flushP2 = 0;
|
int flush_p2 = 0;
|
||||||
|
|
||||||
for (i = 0; i < (count << 1); i += 2)
|
for (i = 0; i < (count << 1); i += 2)
|
||||||
{
|
{
|
||||||
|
@ -242,30 +245,31 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
|
||||||
ax->pos = ax_audio_limit(ax->pos + 1);
|
ax->pos = ax_audio_limit(ax->pos + 1);
|
||||||
|
|
||||||
/* wrapped around, make sure to store cache */
|
/* wrapped around, make sure to store cache */
|
||||||
if(ax->pos == 0)
|
if (ax->pos == 0)
|
||||||
{
|
{
|
||||||
flushP2needed = 1;
|
flush_p2_needed = 1;
|
||||||
flushP2 = ((count << 1) - i);
|
flush_p2 = ((count << 1) - i);
|
||||||
DCStoreRangeNoSync(ax->buffer_l+startPos, (AX_AUDIO_COUNT-startPos) << 1);
|
DCStoreRangeNoSync(ax->buffer_l + start_pos,
|
||||||
DCStoreRangeNoSync(ax->buffer_r+startPos, (AX_AUDIO_COUNT-startPos) << 1);
|
(AX_AUDIO_COUNT - start_pos) << 1);
|
||||||
|
DCStoreRangeNoSync(ax->buffer_r + start_pos, (AX_AUDIO_COUNT - start_pos) << 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* standard cache store case */
|
/* standard cache store case */
|
||||||
if(!flushP2needed)
|
if (!flush_p2_needed)
|
||||||
{
|
{
|
||||||
DCStoreRangeNoSync(ax->buffer_l+startPos, count << 1);
|
DCStoreRangeNoSync(ax->buffer_l + start_pos, count << 1);
|
||||||
DCStoreRange(ax->buffer_r+startPos, count << 1);
|
DCStoreRange(ax->buffer_r + start_pos, count << 1);
|
||||||
}
|
}
|
||||||
/* store the rest after wrap */
|
/* store the rest after wrap */
|
||||||
else if(flushP2 > 0)
|
else if (flush_p2 > 0)
|
||||||
{
|
{
|
||||||
DCStoreRangeNoSync(ax->buffer_l, flushP2);
|
DCStoreRangeNoSync(ax->buffer_l, flush_p2);
|
||||||
DCStoreRange(ax->buffer_r, flushP2);
|
DCStoreRange(ax->buffer_r, flush_p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add in new audio data */
|
/* add in new audio data */
|
||||||
if(OSUninterruptibleSpinLock_Acquire(&ax->spinlock))
|
if (OSUninterruptibleSpinLock_Acquire(&ax->spinlock))
|
||||||
{
|
{
|
||||||
ax->written += count;
|
ax->written += count;
|
||||||
OSUninterruptibleSpinLock_Release(&ax->spinlock);
|
OSUninterruptibleSpinLock_Release(&ax->spinlock);
|
||||||
|
@ -276,7 +280,7 @@ static ssize_t ax_audio_write(void* data, const void* buf, size_t size)
|
||||||
*
|
*
|
||||||
* checks if it can be started
|
* checks if it can be started
|
||||||
*/
|
*/
|
||||||
if(!AXIsMultiVoiceRunning(ax->mvoice))
|
if (!AXIsMultiVoiceRunning(ax->mvoice))
|
||||||
ax_audio_start(ax, false);
|
ax_audio_start(ax, false);
|
||||||
|
|
||||||
/* return what was actually copied */
|
/* return what was actually copied */
|
||||||
|
@ -294,7 +298,7 @@ static void ax_audio_set_nonblock_state(void* data, bool state)
|
||||||
ax_audio_t* ax = (ax_audio_t*)data;
|
ax_audio_t* ax = (ax_audio_t*)data;
|
||||||
|
|
||||||
if (ax)
|
if (ax)
|
||||||
ax->nonblocking = state;
|
ax->nonblock = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ax_audio_use_float(void* data)
|
static bool ax_audio_use_float(void* data)
|
||||||
|
|
Loading…
Reference in New Issue