ao_coreaudio_exclusive: separate out stream selection

This commit is contained in:
wm4 2015-07-03 17:53:20 +02:00
parent 561416597e
commit 8a20e5306c
1 changed files with 79 additions and 64 deletions

View File

@ -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");