diff options
Diffstat (limited to 'audio/out/ao_coreaudio.c')
-rw-r--r-- | audio/out/ao_coreaudio.c | 656 |
1 files changed, 267 insertions, 389 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, |