summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/out/ao_coreaudio.c656
-rw-r--r--audio/out/ao_coreaudio_common.c22
2 files changed, 282 insertions, 396 deletions
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index acab24799b..205078d2be 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -53,33 +53,31 @@ static void print_buffer(struct mp_ring *buffer)
talloc_free(tctx);
}
+struct priv_d {
+ AudioDeviceIOProcID renderCallback; /* Render callback used for SPDIF */
+ pid_t i_hog_pid; /* Keeps the pid of our hog status. */
+ AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
+ int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
+ AudioStreamBasicDescription stream_format; /* The format we changed the stream to */
+ int b_changed_mixing; /* Whether we need to set the mixing mode back */
+ int b_stream_format_changed; /* Flag for main thread to reset stream's format to digital and reset buffer */
+ int b_muted; /* Are we muted in digital mode? */
+};
+
struct priv
{
AudioDeviceID i_selected_dev; /* Keeps DeviceID of the selected device. */
int b_supports_digital; /* Does the currently selected device support digital mode? */
int b_digital; /* Are we running in digital mode? */
- int b_muted; /* Are we muted in digital mode? */
-
- AudioDeviceIOProcID renderCallback; /* Render callback used for SPDIF */
/* AudioUnit */
AudioUnit theOutputUnit;
- /* CoreAudio SPDIF mode specific */
- pid_t i_hog_pid; /* Keeps the pid of our hog status. */
- AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
- int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
- AudioStreamBasicDescription stream_format; /* The format we changed the stream to */
- AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */
- int b_revert; /* Whether we need to revert the stream format */
- int b_changed_mixing; /* Whether we need to set the mixing mode back */
- int b_stream_format_changed; /* Flag for main thread to reset stream's format to digital and reset buffer */
-
- /* Original common part */
int packetSize;
int paused;
struct mp_ring *buffer;
+ struct priv_d *digital;
};
static int get_ring_size(struct ao *ao)
@@ -107,12 +105,13 @@ static OSStatus render_cb_digital(
const void *in_data, const AudioTimeStamp *in_ts,
AudioBufferList *out_data, const AudioTimeStamp *out_ts, void *ctx)
{
- struct ao *ao = ctx;
- struct priv *p = ao->priv;
- AudioBuffer buf = out_data->mBuffers[p->i_stream_index];
- int requested = buf.mDataByteSize;
+ struct ao *ao = ctx;
+ struct priv *p = ao->priv;
+ struct priv_d *d = p->digital;
+ AudioBuffer buf = out_data->mBuffers[d->i_stream_index];
+ int requested = buf.mDataByteSize;
- if (p->b_muted)
+ if (d->b_muted)
mp_ring_drain(p->buffer, requested);
else
mp_ring_read(p->buffer, buf.mData, requested);
@@ -130,8 +129,9 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
case AOCONTROL_GET_VOLUME:
control_vol = (ao_control_vol_t *)arg;
if (p->b_digital) {
+ struct priv_d *d = p->digital;
// Digital output has no volume adjust.
- int vol = p->b_muted ? 0 : 100;
+ int vol = d->b_muted ? 0 : 100;
*control_vol = (ao_control_vol_t) {
.left = vol, .right = vol,
};
@@ -149,6 +149,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
control_vol = (ao_control_vol_t *)arg;
if (p->b_digital) {
+ struct priv_d *d = p->digital;
// Digital output can not set volume. Here we have to return true
// to make mixer forget it. Else mixer will add a soft filter,
// that's not we expected and the filter not support ac3 stream
@@ -157,9 +158,9 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
// Although not support set volume, but at least we support mute.
// MPlayer set mute by set volume to zero, we handle it.
if (control_vol->left == 0 && control_vol->right == 0)
- p->b_muted = 1;
+ d->b_muted = 1;
else
- p->b_muted = 0;
+ d->b_muted = 0;
return CONTROL_TRUE;
}
@@ -177,7 +178,6 @@ coreaudio_error:
return CONTROL_ERROR;
}
-static int OpenSPDIF(struct ao *ao);
static int AudioStreamChangeFormat(AudioStreamID i_stream_id,
AudioStreamBasicDescription change_format);
@@ -222,25 +222,17 @@ static void print_help(void)
free(devs);
}
+static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd);
+static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd);
+
static int init(struct ao *ao, char *params)
{
- // int rate, int channels, int format, int flags)
- struct priv *p = talloc_zero(ao, struct priv);
- ao->priv = p;
-
- AudioStreamBasicDescription inDesc;
- AudioComponentDescription desc;
- AudioComponent comp;
- AURenderCallbackStruct renderCallback;
OSStatus err;
- UInt32 size, maxFrames, b_alive;
- char *psz_name;
- AudioDeviceID devid_def = 0;
- int device_id = 0, display_help = 0;
+ int device_opt = -1, help_opt = 0;
const opt_t subopts[] = {
- {"device_id", OPT_ARG_INT, &device_id, NULL},
- {"help", OPT_ARG_BOOL, &display_help, NULL},
+ {"device_id", OPT_ARG_INT, &device_opt, NULL},
+ {"help", OPT_ARG_BOOL, &help_opt, NULL},
{NULL}
};
@@ -249,190 +241,147 @@ static int init(struct ao *ao, char *params)
return 0;
}
- if (display_help)
+ if (help_opt)
print_help();
- ca_msg(MSGL_V, "init([%dHz][%dch][%s][%d])\n",
- ao->samplerate, ao->channels.num, af_fmt2str_short(ao->format), 0);
+ struct priv *p = talloc_zero(ao, struct priv);
+ *p = (struct priv) {
+ .i_selected_dev = 0,
+ .b_supports_digital = 0,
+ .b_digital = 0,
+ };
+
+ struct priv_d *d= talloc_zero(p, struct priv_d);
+ *d = (struct priv_d) {
+ .b_muted = 0,
+ .b_stream_format_changed = 0,
+ .i_hog_pid = -1,
+ .i_stream_id = 0,
+ .i_stream_index = -1,
+ .b_changed_mixing = 0,
+ };
- p->i_selected_dev = 0;
- p->b_supports_digital = 0;
- p->b_digital = 0;
- p->b_muted = 0;
- p->b_stream_format_changed = 0;
- p->i_hog_pid = -1;
- p->i_stream_id = 0;
- p->i_stream_index = -1;
- p->b_revert = 0;
- p->b_changed_mixing = 0;
+ p->digital = d;
+ ao->priv = p;
ao->per_application_mixer = true;
ao->no_persistent_volume = true;
- if (device_id == 0) {
- /* Find the ID of the default Device. */
+ AudioDeviceID selected_device = 0;
+ if (device_opt < 0) {
+ // device not set by user, get the default one
err = GetAudioProperty(kAudioObjectSystemObject,
kAudioHardwarePropertyDefaultOutputDevice,
- sizeof(UInt32), &devid_def);
- if (err != noErr) {
- ca_msg(MSGL_WARN,
- "could not get default audio device: [%4.4s]\n",
- (char *)&err);
- goto err_out;
- }
+ sizeof(uint32_t), &selected_device);
+ CHECK_CA_ERROR("could not get default audio device");
} else {
- devid_def = device_id;
+ selected_device = device_opt;
}
- /* Retrieve the name of the device. */
- err = GetAudioPropertyString(devid_def,
+ char *device_name;
+ err = GetAudioPropertyString(selected_device,
kAudioObjectPropertyName,
- &psz_name);
- if (err != noErr) {
- ca_msg(MSGL_WARN,
- "could not get default audio device name: [%4.4s]\n",
- (char *)&err);
- goto err_out;
- }
+ &device_name);
- ca_msg(MSGL_V,
- "got audio output device ID: %" PRIu32 " Name: %s\n", devid_def,
- psz_name);
+ CHECK_CA_ERROR("could not get selected audio device name");
- /* Probe whether device support S/PDIF stream output if input is AC3 stream. */
- if (AF_FORMAT_IS_AC3(ao->format)) {
- if (AudioDeviceSupportsDigital(devid_def))
- p->b_supports_digital = 1;
- ca_msg(MSGL_V,
- "probe default audio output device about support for digital s/pdif output: %d\n",
- p->b_supports_digital);
- }
+ ca_msg(MSGL_V,
+ "selected audio output device: %s (%" PRIu32 ")\n",
+ device_name, selected_device);
- free(psz_name);
+ free(device_name);
// Save selected device id
- p->i_selected_dev = devid_def;
+ p->i_selected_dev = selected_device;
struct mp_chmap_sel chmap_sel = {0};
mp_chmap_sel_add_waveext(&chmap_sel);
if (!ao_chmap_sel_adjust(ao, &chmap_sel, &ao->channels))
- goto err_out;
-
- // Build Description for the input format
- inDesc.mSampleRate = ao->samplerate;
- inDesc.mFormatID =
- p->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM;
- inDesc.mChannelsPerFrame = ao->channels.num;
- inDesc.mBitsPerChannel = af_fmt2bits(ao->format);
-
- if ((ao->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F) {
- // float
- inDesc.mFormatFlags = kAudioFormatFlagIsFloat |
- kAudioFormatFlagIsPacked;
- } else if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI) {
- // signed int
- inDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger |
- kAudioFormatFlagIsPacked;
- } else {
- // unsigned int
- inDesc.mFormatFlags = kAudioFormatFlagIsPacked;
- }
+ goto coreaudio_error;
+
+ // Build ASBD for the input format
+ AudioStreamBasicDescription asbd;
+ asbd.mSampleRate = ao->samplerate;
+ asbd.mFormatID = p->b_supports_digital ?
+ kAudioFormat60958AC3 : kAudioFormatLinearPCM;
+ asbd.mChannelsPerFrame = ao->channels.num;
+ asbd.mBitsPerChannel = af_fmt2bits(ao->format);
+ asbd.mFormatFlags = kAudioFormatFlagIsPacked;
+
+ if ((ao->format & AF_FORMAT_POINT_MASK) == AF_FORMAT_F)
+ asbd.mFormatFlags |= kAudioFormatFlagIsFloat;
+
+ if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_SI)
+ asbd.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
+
if ((ao->format & AF_FORMAT_END_MASK) == AF_FORMAT_BE)
- inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
-
- inDesc.mFramesPerPacket = 1;
- p->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame =
- inDesc.mFramesPerPacket *
- ao->channels.num *
- (inDesc.mBitsPerChannel / 8);
- ca_print_asbd("source format:", &inDesc);
-
- if (p->b_supports_digital) {
- b_alive = 1;
- err = GetAudioProperty(p->i_selected_dev,
- kAudioDevicePropertyDeviceIsAlive,
- sizeof(UInt32), &b_alive);
- if (err != noErr)
- ca_msg(MSGL_WARN,
- "could not check whether device is alive: [%4.4s]\n",
- (char *)&err);
- if (!b_alive)
- ca_msg(MSGL_WARN, "device is not alive\n");
+ asbd.mFormatFlags |= kAudioFormatFlagIsBigEndian;
- /* S/PDIF output need device in HogMode. */
- err = GetAudioProperty(p->i_selected_dev,
- kAudioDevicePropertyHogMode,
- sizeof(pid_t), &p->i_hog_pid);
- if (err != noErr) {
- /* This is not a fatal error. Some drivers simply don't support this property. */
- ca_msg(MSGL_WARN,
- "could not check whether device is hogged: [%4.4s]\n",
- (char *)&err);
- p->i_hog_pid = -1;
- }
+ asbd.mFramesPerPacket = 1;
+ p->packetSize = asbd.mBytesPerPacket = asbd.mBytesPerFrame =
+ asbd.mFramesPerPacket * asbd.mChannelsPerFrame *
+ (asbd.mBitsPerChannel / 8);
- if (p->i_hog_pid != -1 && p->i_hog_pid != getpid()) {
- ca_msg(MSGL_WARN,
- "Selected audio device is exclusively in use by another program.\n");
- goto err_out;
- }
- p->stream_format = inDesc;
- return OpenSPDIF(ao);
+ ca_print_asbd("source format:", &asbd);
+
+ /* Probe whether device support S/PDIF stream output if input is AC3 stream. */
+ if (AF_FORMAT_IS_AC3(ao->format)) {
+ if (AudioDeviceSupportsDigital(selected_device))
+ p->b_supports_digital = 1;
}
- /* original analog output code */
- desc.componentType = kAudioUnitType_Output;
- desc.componentSubType =
- (device_id ==
- 0) ? kAudioUnitSubType_DefaultOutput : kAudioUnitSubType_HALOutput;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- desc.componentFlags = 0;
- desc.componentFlagsMask = 0;
+ if (p->b_supports_digital)
+ return init_digital(ao, asbd);
+ else
+ return init_lpcm(ao, asbd);
+
+coreaudio_error:
+ return CONTROL_FALSE;
+}
- comp = AudioComponentFindNext(NULL, &desc); //Finds an component that meets the desc spec's
+static int init_lpcm(struct ao *ao, AudioStreamBasicDescription asbd)
+{
+ OSStatus err;
+ uint32_t size;
+ struct priv *p = ao->priv;
+
+ AudioComponentDescription desc = (AudioComponentDescription) {
+ .componentType = kAudioUnitType_Output,
+ .componentSubType = kAudioUnitSubType_HALOutput,
+ .componentManufacturer = kAudioUnitManufacturer_Apple,
+ .componentFlags = 0,
+ .componentFlagsMask = 0,
+ };
+
+ AudioComponent comp = AudioComponentFindNext(NULL, &desc);
if (comp == NULL) {
- ca_msg(MSGL_WARN, "Unable to find Output Unit component\n");
- goto err_out;
+ ca_msg(MSGL_ERR, "unable to find audio component\n");
+ goto coreaudio_error;
}
- err = AudioComponentInstanceNew(comp, &(p->theOutputUnit)); //gains access to the services provided by the component
- if (err) {
- ca_msg(MSGL_WARN,
- "Unable to open Output Unit component: [%4.4s]\n", (char *)&err);
- goto err_out;
- }
+ err = AudioComponentInstanceNew(comp, &(p->theOutputUnit));
+ CHECK_CA_ERROR("unable to open audio component");
// Initialize AudioUnit
err = AudioUnitInitialize(p->theOutputUnit);
- if (err) {
- ca_msg(MSGL_WARN,
- "Unable to initialize Output Unit component: [%4.4s]\n",
- (char *)&err);
- goto err_out1;
- }
+ CHECK_CA_ERROR_L(coreaudio_error_component,
+ "unable to initialize audio unit");
- size = sizeof(AudioStreamBasicDescription);
+ size = sizeof(AudioStreamBasicDescription);
err = AudioUnitSetProperty(p->theOutputUnit,
kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input, 0, &inDesc, size);
+ kAudioUnitScope_Input, 0, &asbd, size);
- if (err) {
- ca_msg(MSGL_WARN, "Unable to set the input format: [%4.4s]\n",
- (char *)&err);
- goto err_out2;
- }
+ CHECK_CA_ERROR_L(coreaudio_error_audiounit,
+ "unable to set the input format on the audio unit");
- size = sizeof(UInt32);
+ size = sizeof(uint32_t);
err = AudioUnitGetProperty(p->theOutputUnit,
kAudioDevicePropertyBufferSize,
kAudioUnitScope_Input, 0, &maxFrames, &size);
- if (err) {
- ca_msg(MSGL_WARN,
- "AudioUnitGetProperty returned [%4.4s] when getting kAudioDevicePropertyBufferSize\n",
- (char *)&err);
- goto err_out2;
- }
+ CHECK_CA_ERROR_L(coreaudio_error_audiounit,
+ "unable to get buffersize from audio unit");
//Set the Current Device to the Default Output Unit.
err = AudioUnitSetProperty(p->theOutputUnit,
@@ -440,225 +389,176 @@ static int init(struct ao *ao, char *params)
kAudioUnitScope_Global, 0, &p->i_selected_dev,
sizeof(p->i_selected_dev));
- ao->samplerate = inDesc.mSampleRate;
-
- if (!ao_chmap_sel_get_def(ao, &chmap_sel, &ao->channels,
- inDesc.mChannelsPerFrame))
- goto err_out2;
-
- ao->bps = ao->samplerate * inDesc.mBytesPerFrame;
- p->buffer = mp_ring_new(p, get_ring_size(ao));
+ p->buffer = mp_ring_new(p, get_ring_size(ao));
print_buffer(p->buffer);
- renderCallback.inputProc = render_cb_lpcm;
- renderCallback.inputProcRefCon = ao;
+ AURenderCallbackStruct render_cb = (AURenderCallbackStruct) {
+ .inputProc = render_cb_lpcm,
+ .inputProcRefCon = ao,
+ };
+
err = AudioUnitSetProperty(p->theOutputUnit,
kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Input, 0, &renderCallback,
+ kAudioUnitScope_Input, 0, &render_cb,
sizeof(AURenderCallbackStruct));
- if (err) {
- ca_msg(MSGL_WARN,
- "Unable to set the render callback: [%4.4s]\n", (char *)&err);
- goto err_out2;
- }
- reset(ao);
+ CHECK_CA_ERROR_L(coreaudio_error_audiounit,
+ "unable to set render callback on audio unit");
+ reset(ao);
return CONTROL_OK;
-err_out2:
+coreaudio_error_audiounit:
AudioUnitUninitialize(p->theOutputUnit);
-err_out1:
+coreaudio_error_component:
AudioComponentInstanceDispose(p->theOutputUnit);
-err_out:
+coreaudio_error:
return CONTROL_FALSE;
}
-/*****************************************************************************
-* Setup a encoded digital stream (SPDIF)
-*****************************************************************************/
-static int OpenSPDIF(struct ao *ao)
+static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd)
{
struct priv *p = ao->priv;
+ struct priv_d *d = p->digital;
OSStatus err = noErr;
- UInt32 i_param_size, b_mix = 0;
- Boolean b_writeable = 0;
- AudioStreamID *p_streams = NULL;
- int i, i_streams = 0;
AudioObjectPropertyAddress p_addr;
+ uint32_t size;
+
+ uint32_t is_alive = 1;
+ err = GetAudioProperty(p->i_selected_dev,
+ kAudioDevicePropertyDeviceIsAlive,
+ sizeof(uint32_t), &is_alive);
+
+ CHECK_CA_WARN( "could not check whether device is alive");
+
+ if (!is_alive)
+ ca_msg(MSGL_WARN, "device is not alive\n");
+
+ d->stream_format = asbd;
- /* Start doing the SPDIF setup process. */
p->b_digital = 1;
- /* Hog the device. */
- p->i_hog_pid = getpid();
+ d->i_hog_pid = getpid();
err = SetAudioProperty(p->i_selected_dev,
kAudioDevicePropertyHogMode,
- sizeof(p->i_hog_pid), &p->i_hog_pid);
- if (err != noErr) {
- ca_msg(MSGL_WARN, "failed to set hogmode: [%4.4s]\n",
- (char *)&err);
- p->i_hog_pid = -1;
- goto err_out;
+ sizeof(d->i_hog_pid), &d->i_hog_pid);
+
+ if (! CHECK_CA_WARN("faild to set hogmode")) {
+ d->i_hog_pid = -1;
+ goto coreaudio_error;
}
- p_addr.mSelector = kAudioDevicePropertySupportsMixing;
- p_addr.mScope = kAudioObjectPropertyScopeGlobal;
- p_addr.mElement = kAudioObjectPropertyElementMaster;
+ p_addr = (AudioObjectPropertyAddress) {
+ .mSelector = kAudioDevicePropertySupportsMixing,
+ .mScope = kAudioObjectPropertyScopeGlobal,
+ .mElement = kAudioObjectPropertyElementMaster,
+ };
/* Set mixable to false if we are allowed to. */
if (AudioObjectHasProperty(p->i_selected_dev, &p_addr)) {
- /* Set mixable to false if we are allowed to. */
+ Boolean b_writeable = 0;
+
err = IsAudioPropertySettable(p->i_selected_dev,
kAudioDevicePropertySupportsMixing,
&b_writeable);
- err = GetAudioProperty(p->i_selected_dev,
- kAudioDevicePropertySupportsMixing,
- sizeof(UInt32), &b_mix);
- if (err == noErr && b_writeable) {
- b_mix = 0;
+
+ if (b_writeable) {
+ uint32_t mix = 0;
err = SetAudioProperty(p->i_selected_dev,
kAudioDevicePropertySupportsMixing,
- sizeof(UInt32), &b_mix);
- p->b_changed_mixing = 1;
- }
- if (err != noErr) {
- ca_msg(MSGL_WARN, "failed to set mixmode: [%4.4s]\n",
- (char *)&err);
- goto err_out;
+ sizeof(uint32_t), &mix);
+ CHECK_CA_ERROR("failed to set mixmode");
+ d->b_changed_mixing = 1;
}
}
+ AudioStreamID *streams = NULL;
/* Get a list of all the streams on this device. */
- i_param_size = GetAudioPropertyArray(p->i_selected_dev,
- kAudioDevicePropertyStreams,
- kAudioDevicePropertyScopeOutput,
- (void **)&p_streams);
-
- if (!i_param_size) {
- ca_msg(MSGL_WARN, "could not get number of streams.\n");
- goto err_out;
+ size = GetAudioPropertyArray(p->i_selected_dev,
+ kAudioDevicePropertyStreams,
+ kAudioDevicePropertyScopeOutput,
+ (void **)&streams);
+
+ if (!size) {
+ ca_msg(MSGL_WARN, "could not get number of streams.");
+ goto coreaudio_error;
}
- i_streams = i_param_size / sizeof(AudioStreamID);
-
- ca_msg(MSGL_V, "current device stream number: %d\n", i_streams);
+ int streams_n = size / sizeof(AudioStreamID);
- for (i = 0; i < i_streams && p->i_stream_index < 0; ++i) {
- /* Find a stream with a cac3 stream. */
- AudioStreamRangedDescription *p_format_list = NULL;
- int i_formats = 0, j = 0, b_digital = 0;
+ // TODO: ++i is quite fishy in here. Investigate!
+ for (int i = 0; i < streams_n && d->i_stream_index < 0; ++i) {
+ bool digital = AudioStreamSupportsDigital(streams[i]);
- i_param_size = GetGlobalAudioPropertyArray(p_streams[i],
- kAudioStreamPropertyAvailablePhysicalFormats,
- (void **)&p_format_list);
+ if (digital) {
+ /* Find a stream with a cac3 stream. */
+ AudioStreamRangedDescription *formats = NULL;
+ size = GetGlobalAudioPropertyArray(streams[i],
+ kAudioStreamPropertyAvailablePhysicalFormats,
+ (void **)&formats);
- if (!i_param_size) {
- ca_msg(MSGL_WARN,
- "Could not get number of stream formats.\n");
- continue;
- }
-
- i_formats = i_param_size / sizeof(AudioStreamRangedDescription);
-
- /* Check if one of the supported formats is a digital format. */
- for (j = 0; j < i_formats; ++j) {
- if (p_format_list[j].mFormat.mFormatID == 'IAC3' ||
- p_format_list[j].mFormat.mFormatID == 'iac3' ||
- p_format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 ||
- p_format_list[j].mFormat.mFormatID == kAudioFormatAC3) {
- b_digital = 1;
- break;
+ if (!size) {
+ ca_msg(MSGL_WARN, "could not get number of stream formats.\n");
+ continue; // try next one
}
- }
- if (b_digital) {
+ int formats_n = size / sizeof(AudioStreamRangedDescription);
/* If this stream supports a digital (cac3) format, then set it. */
- int i_requested_rate_format = -1;
- int i_current_rate_format = -1;
- int i_backup_rate_format = -1;
-
- p->i_stream_id = p_streams[i];
- p->i_stream_index = i;
-
- if (p->b_revert == 0) {
- /* Retrieve the original format of this stream first if not done so already. */
- err = GetAudioProperty(p->i_stream_id,
- kAudioStreamPropertyPhysicalFormat,
- sizeof(p->sfmt_revert),
- &p->sfmt_revert);
- if (err != noErr) {
- ca_msg(MSGL_WARN,
- "Could not retrieve the original stream format: [%4.4s]\n",
- (char *)&err);
- free(p_format_list);
- continue;
- }
- p->b_revert = 1;
- }
-
- for (j = 0; j < i_formats; ++j)
- if (p_format_list[j].mFormat.mFormatID == 'IAC3' ||
- p_format_list[j].mFormat.mFormatID == 'iac3' ||
- p_format_list[j].mFormat.mFormatID ==
- kAudioFormat60958AC3 ||
- p_format_list[j].mFormat.mFormatID == kAudioFormatAC3) {
- if (p_format_list[j].mFormat.mSampleRate ==
- p->stream_format.mSampleRate) {
- i_requested_rate_format = j;
+ int req_rate_format = -1;
+ int max_rate_format = -1;
+
+ d->i_stream_id = streams[i];
+ d->i_stream_index = i;
+
+ // TODO: ++j is fishy. was like this in the original code. Investigate!
+ for (int j = 0; j < formats_n; ++j)
+ if (AudioFormatIsDigital(asbd)) {
+ // select the digital 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 ==
+ d->stream_format.mSampleRate) {
+ req_rate_format = j;
break;
- }
- if (p_format_list[j].mFormat.mSampleRate ==
- p->sfmt_revert.mSampleRate)
- i_current_rate_format = j;
- else if (i_backup_rate_format < 0 ||
- p_format_list[j].mFormat.mSampleRate >
- p_format_list[i_backup_rate_format].mFormat.
- mSampleRate)
- i_backup_rate_format = j;
+ } else if (max_rate_format < 0 ||
+ formats[j].mFormat.mSampleRate >
+ formats[max_rate_format].mFormat.mSampleRate)
+ max_rate_format = j;
}
- if (i_requested_rate_format >= 0) /* We prefer to output at the samplerate of the original audio. */
- p->stream_format =
- p_format_list[i_requested_rate_format].mFormat;
- else if (i_current_rate_format >= 0) /* If not possible, we will try to use the current samplerate of the device. */
- p->stream_format =
- p_format_list[i_current_rate_format].mFormat;
+ if (req_rate_format >= 0)
+ d->stream_format = formats[req_rate_format].mFormat;
else
- p->stream_format = p_format_list[i_backup_rate_format].mFormat;
- /* And if we have to, any digital format will be just fine (highest rate possible). */
+ d->stream_format = formats[max_rate_format].mFormat;
+
+ free(formats);
}
- free(p_format_list);
}
- free(p_streams);
- if (p->i_stream_index < 0) {
- ca_msg(MSGL_WARN,
- "Cannot find any digital output stream format when OpenSPDIF().\n");
- goto err_out;
- }
+ free(streams);
- ca_print_asbd("original stream format:", &p->sfmt_revert);
+ if (d->i_stream_index < 0) {
+ ca_msg(MSGL_WARN, "can't find any digital output stream format");
+ goto coreaudio_error;
+ }
- if (!AudioStreamChangeFormat(p->i_stream_id, p->stream_format))
- goto err_out;
+ if (!AudioStreamChangeFormat(d->i_stream_id, d->stream_format))
+ goto coreaudio_error;
- p_addr.mSelector = kAudioDevicePropertyDeviceHasChanged;
- p_addr.mScope = kAudioObjectPropertyScopeGlobal;
- p_addr.mElement = kAudioObjectPropertyElementMaster;
+ p_addr = (AudioObjectPropertyAddress) {
+ .mSelector = kAudioDevicePropertyDeviceHasChanged,
+ .mScope = kAudioObjectPropertyScopeGlobal,
+ .mElement = kAudioObjectPropertyElementMaster,
+ };
- const int *stream_format_changed = &(p->b_stream_format_changed);
+ const int *stream_format_changed = &(d->b_stream_format_changed);
err = AudioObjectAddPropertyListener(p->i_selected_dev,
&p_addr,
ca_device_listener,
(void *)stream_format_changed);
- if (err != noErr)
- ca_msg(MSGL_WARN,
- "AudioDeviceAddPropertyListener for kAudioDevicePropertyDeviceHasChanged failed: [%4.4s]\n",
- (char *)&err);
-
+ CHECK_CA_ERROR("cannot install format change listener during init");
/* FIXME: If output stream is not native byte-order, we need change endian somewhere. */
/* Although there's no such case reported. */
@@ -666,60 +566,39 @@ static int OpenSPDIF(struct ao *ao)
if (!(p->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian))
#else
/* tell mplayer that we need a byteswap on AC3 streams, */
- if (p->stream_format.mFormatID & kAudioFormat60958AC3)
+ if (d->stream_format.mFormatID & kAudioFormat60958AC3)
ao->format = AF_FORMAT_AC3_LE;
-
- if (p->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
-#endif
+ else if (d->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
ca_msg(MSGL_WARN,
- "Output stream has non-native byte order, digital output may fail.\n");
-
+ "Stream has non-native byte order, digital output may fail");
+#endif
- ao->samplerate = p->stream_format.mSampleRate;
- mp_chmap_from_channels(&ao->channels, p->stream_format.mChannelsPerFrame);
+ ao->samplerate = d->stream_format.mSampleRate;
+ mp_chmap_from_channels(&ao->channels, d->stream_format.mChannelsPerFrame);
ao->bps = ao->samplerate *
- (p->stream_format.mBytesPerPacket /
- p->stream_format.mFramesPerPacket);
-
- p->buffer = mp_ring_new(p, get_ring_size(ao));
+ (d->stream_format.mBytesPerPacket /
+ d->stream_format.mFramesPerPacket);
+ p->buffer = mp_ring_new(p, get_ring_size(ao));
print_buffer(p->buffer);
- /* Create IOProc callback. */
err = AudioDeviceCreateIOProcID(p->i_selected_dev,
(AudioDeviceIOProc)render_cb_digital,
(void *)ao,
- &p->renderCallback);
+ &d->renderCallback);
- if (err != noErr || p->renderCallback == NULL) {
- ca_msg(MSGL_WARN, "AudioDeviceAddIOProc failed: [%4.4s]\n",
- (char *)&err);
- goto err_out1;
- }
+ CHECK_CA_ERROR("failed to register digital render callback");
reset(ao);
return CONTROL_TRUE;
-err_out1:
- if (p->b_revert)
- AudioStreamChangeFormat(p->i_stream_id, p->sfmt_revert);
-err_out:
- if (p->b_changed_mixing && p->sfmt_revert.mFormatID !=
- kAudioFormat60958AC3) {
- int b_mix = 1;
- err = SetAudioProperty(p->i_selected_dev,
- kAudioDevicePropertySupportsMixing,
- sizeof(int), &b_mix);
- if (err != noErr)
- ca_msg(MSGL_WARN, "failed to set mixmode: [%4.4s]\n",
- (char *)&err);
- }
- if (p->i_hog_pid == getpid()) {
- p->i_hog_pid = -1;
+coreaudio_error:
+ if (d->i_hog_pid == getpid()) {
+ d->i_hog_pid = -1;
err = SetAudioProperty(p->i_selected_dev,
kAudioDevicePropertyHogMode,
- sizeof(p->i_hog_pid), &p->i_hog_pid);
+ sizeof(d->i_hog_pid), &d->i_hog_pid);
if (err != noErr)
ca_msg(MSGL_WARN, "Could not release hogmode: [%4.4s]\n",
(char *)&err);
@@ -815,18 +694,18 @@ static int AudioStreamChangeFormat(AudioStreamID i_stream_id,
static int play(struct ao *ao, void *output_samples, int num_bytes, int flags)
{
struct priv *p = ao->priv;
- int wrote, b_digital;
+ struct priv_d *d = p->digital;
// Check whether we need to reset the digital output stream.
- if (p->b_digital && p->b_stream_format_changed) {
- p->b_stream_format_changed = 0;
- b_digital = AudioStreamSupportsDigital(p->i_stream_id);
+ if (p->b_digital && d->b_stream_format_changed) {
+ d->b_stream_format_changed = 0;
+ int b_digital = AudioStreamSupportsDigital(d->i_stream_id);
if (b_digital) {
/* Current stream supports digital format output, let's set it. */
ca_msg(MSGL_V,
"Detected current stream supports digital, try to restore digital output...\n");
- if (!AudioStreamChangeFormat(p->i_stream_id, p->stream_format))
+ if (!AudioStreamChangeFormat(d->i_stream_id, d->stream_format))
ca_msg(MSGL_WARN,
"Restoring digital output failed.\n");
else {
@@ -839,7 +718,7 @@ static int play(struct ao *ao, void *output_samples, int num_bytes, int flags)
"Detected current stream does not support digital.\n");
}
- wrote = mp_ring_write(p->buffer, output_samples, num_bytes);
+ int wrote = mp_ring_write(p->buffer, output_samples, num_bytes);
audio_resume(ao);
return wrote;
@@ -888,24 +767,21 @@ static void uninit(struct ao *ao, bool immed)
AudioUnitUninitialize(p->theOutputUnit);
AudioComponentInstanceDispose(p->theOutputUnit);
} else {
+ struct priv_d *d = p->digital;
/* Stop device. */
- err = AudioDeviceStop(p->i_selected_dev, p->renderCallback);
+ err = AudioDeviceStop(p->i_selected_dev, d->renderCallback);
if (err != noErr)
ca_msg(MSGL_WARN, "AudioDeviceStop failed: [%4.4s]\n",
(char *)&err);
/* Remove IOProc callback. */
err =
- AudioDeviceDestroyIOProcID(p->i_selected_dev, p->renderCallback);
+ AudioDeviceDestroyIOProcID(p->i_selected_dev, d->renderCallback);
if (err != noErr)
ca_msg(MSGL_WARN,
"AudioDeviceRemoveIOProc failed: [%4.4s]\n", (char *)&err);
- if (p->b_revert)
- AudioStreamChangeFormat(p->i_stream_id, p->sfmt_revert);
-
- if (p->b_changed_mixing && p->sfmt_revert.mFormatID !=
- kAudioFormat60958AC3) {
+ if (d->b_changed_mixing) {
UInt32 b_mix;
Boolean b_writeable = 0;
/* Revert mixable to true if we are allowed to. */
@@ -925,11 +801,11 @@ static void uninit(struct ao *ao, bool immed)
ca_msg(MSGL_WARN, "failed to set mixmode: [%4.4s]\n",
(char *)&err);
}
- if (p->i_hog_pid == getpid()) {
- p->i_hog_pid = -1;
+ if (d->i_hog_pid == getpid()) {
+ d->i_hog_pid = -1;
err = SetAudioProperty(p->i_selected_dev,
kAudioDevicePropertyHogMode,
- sizeof(p->i_hog_pid), &p->i_hog_pid);
+ sizeof(d->i_hog_pid), &d->i_hog_pid);
if (err != noErr)
ca_msg(MSGL_WARN,
"Could not release hogmode: [%4.4s]\n", (char *)&err);
@@ -950,7 +826,8 @@ static void audio_pause(struct ao *ao)
ca_msg(MSGL_WARN, "AudioOutputUnitStop returned [%4.4s]\n",
(char *)&err);
} else {
- err = AudioDeviceStop(p->i_selected_dev, p->renderCallback);
+ struct priv_d *d = p->digital;
+ err = AudioDeviceStop(p->i_selected_dev, d->renderCallback);
if (err != noErr)
ca_msg(MSGL_WARN, "AudioDeviceStop failed: [%4.4s]\n",
(char *)&err);
@@ -975,7 +852,8 @@ static void audio_resume(struct ao *ao)
ca_msg(MSGL_WARN,
"AudioOutputUnitStart returned [%4.4s]\n", (char *)&err);
} else {
- err = AudioDeviceStart(p->i_selected_dev, p->renderCallback);
+ struct priv_d *d = p->digital;
+ err = AudioDeviceStart(p->i_selected_dev, d->renderCallback);
if (err != noErr)
ca_msg(MSGL_WARN, "AudioDeviceStart failed: [%4.4s]\n",
(char *)&err);
diff --git a/audio/out/ao_coreaudio_common.c b/audio/out/ao_coreaudio_common.c
index 56bb99314f..1755004f3f 100644
--- a/audio/out/ao_coreaudio_common.c
+++ b/audio/out/ao_coreaudio_common.c
@@ -76,6 +76,7 @@ static bool check_ca_st(int level, OSStatus code, const char *message)
} while (0)
#define CHECK_CA_ERROR(message) CHECK_CA_ERROR_L(coreaudio_error, message)
+#define CHECK_CA_WARN(message) check_ca_st(MSGL_WARN, err, message)
static void ca_print_asbd(const char *description,
const AudioStreamBasicDescription *asbd)
@@ -206,6 +207,17 @@ static Boolean IsAudioPropertySettable(AudioObjectID id,
return AudioObjectIsPropertySettable(id, &p_addr, outData);
}
+static int AudioFormatIsDigital(AudioStreamBasicDescription asbd)
+{
+ switch (asbd.mFormatID)
+ case 'IAC3':
+ case 'iac3':
+ case kAudioFormat60958AC3:
+ case kAudioFormatAC3:
+ return CONTROL_OK;
+ return CONTROL_FALSE;
+}
+
static int AudioStreamSupportsDigital(AudioStreamID stream)
{
AudioStreamRangedDescription *formats = NULL;
@@ -225,14 +237,10 @@ static int AudioStreamSupportsDigital(AudioStreamID stream)
for (int i = 0; i < n_formats; ++i) {
AudioStreamBasicDescription asbd = formats[i].mFormat;
ca_print_asbd("supported format:", &(asbd));
-
- switch (asbd.mFormatID)
- case 'IAC3':
- case 'iac3':
- case kAudioFormat60958AC3:
- case kAudioFormatAC3:
+ if (AudioFormatIsDigital(asbd)) {
free(formats);
- return CONTROL_OK;
+ return CONTROL_TRUE;
+ }
}
free(formats);