mirror of https://github.com/mpv-player/mpv
ao_coreaudio_exclusive: separate out stream selection
This commit is contained in:
parent
561416597e
commit
8a20e5306c
|
@ -160,6 +160,53 @@ static OSStatus render_cb_compressed(
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apparently, audio devices can have multiple sub-streams. It's not clear to
|
||||||
|
// me what devices with multiple streams actually do. So only select the first
|
||||||
|
// one that fulfills some minimum requirements.
|
||||||
|
// If this is not sufficient, we could duplicate the device list entries for
|
||||||
|
// each sub-stream, and make it explicit.
|
||||||
|
static int select_stream(struct ao *ao)
|
||||||
|
{
|
||||||
|
struct priv *p = ao->priv;
|
||||||
|
|
||||||
|
AudioStreamID *streams;
|
||||||
|
size_t n_streams;
|
||||||
|
OSStatus err;
|
||||||
|
|
||||||
|
/* Get a list of all the streams on this device. */
|
||||||
|
err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams,
|
||||||
|
&streams, &n_streams);
|
||||||
|
CHECK_CA_ERROR("could not get number of streams");
|
||||||
|
for (int i = 0; i < n_streams; i++) {
|
||||||
|
uint32_t direction;
|
||||||
|
err = CA_GET(streams[i], kAudioStreamPropertyDirection, &direction);
|
||||||
|
CHECK_CA_WARN("could not get stream direction");
|
||||||
|
if (err == noErr && direction != 0) {
|
||||||
|
MP_VERBOSE(ao, "Substream %d is not an output stream.\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca_stream_supports_compressed(ao, streams[i])) {
|
||||||
|
MP_VERBOSE(ao, "Using substream %d/%zd.\n", i, n_streams);
|
||||||
|
p->stream = streams[i];
|
||||||
|
p->stream_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
talloc_free(streams);
|
||||||
|
|
||||||
|
if (p->stream_idx < 0) {
|
||||||
|
MP_ERR(ao, "No useable substream found.\n");
|
||||||
|
goto coreaudio_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
coreaudio_error:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int init(struct ao *ao)
|
static int init(struct ao *ao)
|
||||||
{
|
{
|
||||||
struct priv *p = ao->priv;
|
struct priv *p = ao->priv;
|
||||||
|
@ -196,73 +243,41 @@ static int init(struct ao *ao)
|
||||||
err = ca_disable_mixing(ao, p->device, &p->changed_mixing);
|
err = ca_disable_mixing(ao, p->device, &p->changed_mixing);
|
||||||
CHECK_CA_WARN("failed to disable mixing");
|
CHECK_CA_WARN("failed to disable mixing");
|
||||||
|
|
||||||
AudioStreamID *streams;
|
if (select_stream(ao) < 0)
|
||||||
size_t n_streams;
|
|
||||||
|
|
||||||
/* Get a list of all the streams on this device. */
|
|
||||||
err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams,
|
|
||||||
&streams, &n_streams);
|
|
||||||
|
|
||||||
CHECK_CA_ERROR("could not get number of streams");
|
|
||||||
|
|
||||||
for (int i = 0; i < n_streams && p->stream_idx < 0; i++) {
|
|
||||||
uint32_t direction;
|
|
||||||
err = CA_GET(streams[i], kAudioStreamPropertyDirection, &direction);
|
|
||||||
CHECK_CA_ERROR("could not get stream direction");
|
|
||||||
if (direction != 0) {
|
|
||||||
MP_VERBOSE(ao, "Substream %d is not an output stream.\n", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compressed = ca_stream_supports_compressed(ao, streams[i]);
|
|
||||||
|
|
||||||
if (compressed) {
|
|
||||||
AudioStreamRangedDescription *formats;
|
|
||||||
size_t n_formats;
|
|
||||||
|
|
||||||
err = CA_GET_ARY(streams[i],
|
|
||||||
kAudioStreamPropertyAvailablePhysicalFormats,
|
|
||||||
&formats, &n_formats);
|
|
||||||
|
|
||||||
if (!CHECK_CA_WARN("could not get number of stream formats"))
|
|
||||||
continue; // try next one
|
|
||||||
|
|
||||||
int req_rate_format = -1;
|
|
||||||
int max_rate_format = -1;
|
|
||||||
|
|
||||||
p->stream = streams[i];
|
|
||||||
p->stream_idx = i;
|
|
||||||
|
|
||||||
for (int j = 0; j < n_formats; j++)
|
|
||||||
if (ca_formatid_is_compressed(formats[j].mFormat.mFormatID)) {
|
|
||||||
// select the compressed format that has exactly the same
|
|
||||||
// samplerate. If an exact match cannot be found, select
|
|
||||||
// the format with highest samplerate as backup.
|
|
||||||
if (formats[j].mFormat.mSampleRate == asbd.mSampleRate) {
|
|
||||||
req_rate_format = j;
|
|
||||||
break;
|
|
||||||
} else if (max_rate_format < 0 ||
|
|
||||||
formats[j].mFormat.mSampleRate >
|
|
||||||
formats[max_rate_format].mFormat.mSampleRate)
|
|
||||||
max_rate_format = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req_rate_format >= 0)
|
|
||||||
p->stream_asbd = formats[req_rate_format].mFormat;
|
|
||||||
else
|
|
||||||
p->stream_asbd = formats[max_rate_format].mFormat;
|
|
||||||
|
|
||||||
talloc_free(formats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
talloc_free(streams);
|
|
||||||
|
|
||||||
if (p->stream_idx < 0) {
|
|
||||||
MP_WARN(ao , "can't find any compressed output stream format\n");
|
|
||||||
goto coreaudio_error;
|
goto coreaudio_error;
|
||||||
|
|
||||||
|
AudioStreamRangedDescription *formats;
|
||||||
|
size_t n_formats;
|
||||||
|
|
||||||
|
err = CA_GET_ARY(p->stream, kAudioStreamPropertyAvailablePhysicalFormats,
|
||||||
|
&formats, &n_formats);
|
||||||
|
CHECK_CA_ERROR("could not get number of stream formats");
|
||||||
|
|
||||||
|
int req_rate_format = -1;
|
||||||
|
int max_rate_format = -1;
|
||||||
|
|
||||||
|
for (int j = 0; j < n_formats; j++) {
|
||||||
|
if (ca_formatid_is_compressed(formats[j].mFormat.mFormatID)) {
|
||||||
|
// select the compressed format that has exactly the same
|
||||||
|
// samplerate. If an exact match cannot be found, select
|
||||||
|
// the format with highest samplerate as backup.
|
||||||
|
if (formats[j].mFormat.mSampleRate == asbd.mSampleRate) {
|
||||||
|
req_rate_format = j;
|
||||||
|
break;
|
||||||
|
} else if (max_rate_format < 0 ||
|
||||||
|
formats[j].mFormat.mSampleRate >
|
||||||
|
formats[max_rate_format].mFormat.mSampleRate)
|
||||||
|
max_rate_format = j;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req_rate_format >= 0)
|
||||||
|
p->stream_asbd = formats[req_rate_format].mFormat;
|
||||||
|
else
|
||||||
|
p->stream_asbd = formats[max_rate_format].mFormat;
|
||||||
|
|
||||||
|
talloc_free(formats);
|
||||||
|
|
||||||
err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat,
|
err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat,
|
||||||
&p->original_asbd);
|
&p->original_asbd);
|
||||||
CHECK_CA_ERROR("could not get stream's original physical format");
|
CHECK_CA_ERROR("could not get stream's original physical format");
|
||||||
|
|
Loading…
Reference in New Issue