Skip to content

Commit a3621b9

Browse files
committed
apple: use coreaudio resampling, add coreaudio3 driver to ios/tvos
1 parent 1ad1552 commit a3621b9

38 files changed

Lines changed: 667 additions & 52 deletions

audio/audio_driver.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ audio_driver_t audio_null = {
9999
NULL,
100100
NULL,
101101
NULL, /* write_avail */
102-
NULL /* buffer_size */
102+
NULL, /* buffer_size */
103+
NULL /* write_raw */
103104
};
104105

105106
audio_driver_t *audio_drivers[] = {
@@ -456,6 +457,45 @@ static void audio_driver_flush(audio_driver_state_t *audio_st,
456457
? 0.0f
457458
: audio_st->volume_gain;
458459

460+
/* Fast path: if driver handles resampling and no DSP/mixer is active,
461+
* bypass software resampling entirely. */
462+
if (audio_st->current_audio->write_raw
463+
#ifdef HAVE_DSP_FILTER
464+
&& !audio_st->dsp
465+
#endif
466+
#ifdef HAVE_AUDIOMIXER
467+
&& audio_st->mixer_streams_playing == 0
468+
#endif
469+
)
470+
{
471+
size_t frames = samples >> 1;
472+
double rate_adjust = 1.0;
473+
unsigned input_rate = (unsigned)audio_st->input;
474+
475+
/* Rate control for A/V sync */
476+
if (audio_st->flags & AUDIO_FLAG_CONTROL)
477+
{
478+
unsigned write_idx =
479+
audio_st->free_samples_count++ & (AUDIO_BUFFER_FREE_SAMPLES_COUNT - 1);
480+
int avail = (int)audio_st->current_audio->write_avail(
481+
audio_st->context_audio_data);
482+
int half_size = (int)(audio_st->buffer_size / 2);
483+
int delta_mid = avail - half_size;
484+
double direction = (double)delta_mid / half_size;
485+
486+
audio_st->free_samples_buf[write_idx] = avail;
487+
rate_adjust = 1.0 + audio_st->rate_control_delta * direction;
488+
}
489+
490+
if (is_slowmotion)
491+
rate_adjust *= slowmotion_ratio;
492+
493+
/* Note: mute/volume is not applied here - driver must handle or ignore */
494+
audio_st->current_audio->write_raw(audio_st->context_audio_data,
495+
data, frames, input_rate, rate_adjust);
496+
return;
497+
}
498+
459499
src_data.data_out = NULL;
460500
src_data.output_frames = 0;
461501
/* We'll assign a proper output to the resampler later in this function */
@@ -1121,6 +1161,8 @@ static void audio_mixer_play_stop_cb(
11211161
audio_driver_st.mixer_streams[i].stop_cb = NULL;
11221162
audio_driver_st.mixer_streams[i].handle = NULL;
11231163
audio_driver_st.mixer_streams[i].voice = NULL;
1164+
if (audio_driver_st.mixer_streams_playing > 0)
1165+
audio_driver_st.mixer_streams_playing--;
11241166
}
11251167
break;
11261168
case AUDIO_MIXER_SOUND_STOPPED:
@@ -1143,6 +1185,8 @@ static void audio_mixer_menu_stop_cb(
11431185
unsigned i = (unsigned)idx;
11441186
audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
11451187
audio_driver_st.mixer_streams[i].volume = 0.0f;
1188+
if (audio_driver_st.mixer_streams_playing > 0)
1189+
audio_driver_st.mixer_streams_playing--;
11461190
}
11471191
break;
11481192
case AUDIO_MIXER_SOUND_STOPPED:
@@ -1180,6 +1224,8 @@ static void audio_mixer_play_stop_sequential_cb(
11801224
audio_driver_st.mixer_streams[i].stop_cb = NULL;
11811225
audio_driver_st.mixer_streams[i].handle = NULL;
11821226
audio_driver_st.mixer_streams[i].voice = NULL;
1227+
if (audio_driver_st.mixer_streams_playing > 0)
1228+
audio_driver_st.mixer_streams_playing--;
11831229

11841230
i++;
11851231

@@ -1330,6 +1376,11 @@ bool audio_driver_mixer_add_stream(audio_mixer_stream_params_t *params)
13301376
audio_driver_st.mixer_streams[free_slot].volume = params->volume;
13311377
audio_driver_st.mixer_streams[free_slot].stop_cb = stop_cb;
13321378

1379+
if ( params->state == AUDIO_STREAM_STATE_PLAYING
1380+
|| params->state == AUDIO_STREAM_STATE_PLAYING_LOOPED
1381+
|| params->state == AUDIO_STREAM_STATE_PLAYING_SEQUENTIAL)
1382+
audio_driver_st.mixer_streams_playing++;
1383+
13331384
return true;
13341385
}
13351386

@@ -1357,6 +1408,7 @@ static void audio_driver_mixer_play_stream_internal(
13571408
audio_driver_st.resampler_quality,
13581409
audio_driver_st.mixer_streams[i].stop_cb);
13591410
audio_driver_st.mixer_streams[i].state = (enum audio_mixer_state)type;
1411+
audio_driver_st.mixer_streams_playing++;
13601412
break;
13611413
case AUDIO_STREAM_STATE_PLAYING:
13621414
case AUDIO_STREAM_STATE_PLAYING_LOOPED:
@@ -1591,6 +1643,8 @@ void audio_driver_mixer_stop_stream(unsigned i)
15911643
audio_mixer_stop(voice);
15921644
audio_driver_st.mixer_streams[i].state = AUDIO_STREAM_STATE_STOPPED;
15931645
audio_driver_st.mixer_streams[i].volume = 1.0f;
1646+
if (audio_driver_st.mixer_streams_playing > 0)
1647+
audio_driver_st.mixer_streams_playing--;
15941648
}
15951649
break;
15961650
case AUDIO_STREAM_STATE_STOPPED:

audio/audio_driver.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ typedef struct audio_driver
165165
size_t (*write_avail)(void *data);
166166

167167
size_t (*buffer_size)(void *data);
168+
169+
/**
170+
* Optional. Write raw int16 samples with resampling handled by driver.
171+
* If non-NULL, audio_driver will call this instead of doing software
172+
* resampling. The driver is responsible for resampling from input_rate
173+
* to its output rate, applying the rate_adjust factor for A/V sync.
174+
*
175+
* @param data Driver context
176+
* @param samples Interleaved int16 stereo samples (LRLRLR...)
177+
* @param frames Number of frames (pairs of samples)
178+
* @param input_rate Source sample rate in Hz
179+
* @param rate_adjust Rate adjustment multiplier for A/V sync (1.0 = normal)
180+
* @return Number of frames written, or -1 on error
181+
*/
182+
ssize_t (*write_raw)(void *data, const int16_t *samples, size_t frames,
183+
unsigned input_rate, double rate_adjust);
168184
} audio_driver_t;
169185

170186
typedef struct
@@ -247,6 +263,7 @@ typedef struct
247263
bool mute_enable;
248264
#ifdef HAVE_AUDIOMIXER
249265
bool mixer_mute_enable;
266+
uint8_t mixer_streams_playing; /* Count of currently playing mixer streams */
250267
#endif
251268

252269
/* Sample the flush delta-time when fast forwarding to find the correct ratio. */

audio/drivers/alsa.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,4 +539,5 @@ audio_driver_t audio_alsa = {
539539
alsa_device_list_free,
540540
alsa_write_avail,
541541
alsa_buffer_size,
542+
NULL /* write_raw */
542543
};

audio/drivers/alsa_qsa.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,4 +377,5 @@ audio_driver_t audio_alsa = {
377377
NULL,
378378
alsa_qsa_write_avail,
379379
alsa_qsa_buffer_size,
380+
NULL /* write_raw */
380381
};

audio/drivers/alsathread.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,5 +673,6 @@ audio_driver_t audio_alsathread = {
673673
alsa_device_list_new, /* Reusing these functions from alsa.c */
674674
alsa_device_list_free, /* because they don't use the driver context */
675675
alsa_thread_write_avail,
676-
alsa_thread_buffer_size
676+
alsa_thread_buffer_size,
677+
NULL /* write_raw */
677678
};

audio/drivers/audioio.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,5 @@ audio_driver_t audio_audioio = {
205205
NULL,
206206
audioio_write_avail,
207207
audioio_buffer_size,
208+
NULL /* write_raw */
208209
};

audio/drivers/audioworklet.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,5 +533,6 @@ audio_driver_t audio_audioworklet = {
533533
NULL,
534534
NULL,
535535
audioworklet_write_avail,
536-
audioworklet_buffer_size
536+
audioworklet_buffer_size,
537+
NULL /* write_raw */
537538
};

0 commit comments

Comments
 (0)