static OSStatus _audio_stream_hardware_changed_listener (AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void *inClientData) { OSStatus status = noErr; guint i; GstCoreAudio *core_audio = inClientData; for (i = 0; i < inNumberAddresses; i++) { if (inAddresses[i].mSelector == kAudioDevicePropertyDeviceHasChanged) { if (!gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id)) { GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (core_audio->osxbuf)); GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, ("SPDIF output no longer available"), ("Audio device is reporting that SPDIF output isn't available")); } break; } } return (status); }
GstCaps * gst_core_audio_probe_caps (GstCoreAudio * core_audio, GstCaps * in_caps) { guint i, channels; gboolean spdif_allowed; AudioChannelLayout *layout; AudioStreamBasicDescription outer_asbd; gboolean got_outer_asbd; GstCaps *caps = NULL; guint64 channel_mask; /* Get the ASBD of the outer scope (i.e. input scope of Input, * output scope of Output). * This ASBD indicates the hardware format. */ got_outer_asbd = _core_audio_get_stream_format (core_audio, &outer_asbd, TRUE); /* Collect info about the HW capabilites and preferences */ spdif_allowed = gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id); if (!core_audio->is_src) layout = gst_core_audio_get_channel_layout (core_audio, TRUE); else layout = NULL; /* no supported for sources */ GST_DEBUG_OBJECT (core_audio, "Selected device ID: %u SPDIF allowed: %d", (unsigned) core_audio->device_id, spdif_allowed); if (layout) { if (!gst_core_audio_parse_channel_layout (layout, &channels, &channel_mask, NULL)) { GST_WARNING_OBJECT (core_audio, "Failed to parse channel layout"); channel_mask = 0; } /* If available, start with the preferred caps. */ if (got_outer_asbd) caps = gst_core_audio_asbd_to_caps (&outer_asbd, layout); g_free (layout); } else if (got_outer_asbd) { channels = outer_asbd.mChannelsPerFrame; channel_mask = 0; /* If available, start with the preferred caps */ caps = gst_core_audio_asbd_to_caps (&outer_asbd, NULL); } else { GST_ERROR_OBJECT (core_audio, "Unable to get any information about hardware"); return NULL; } /* Append the allowed subset based on the template caps */ if (!caps) caps = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (in_caps); i++) { GstStructure *in_s; in_s = gst_caps_get_structure (in_caps, i); if (gst_structure_has_name (in_s, "audio/x-ac3") || gst_structure_has_name (in_s, "audio/x-dts")) { if (spdif_allowed) { gst_caps_append_structure (caps, gst_structure_copy (in_s)); } } else { GstStructure *out_s; out_s = gst_structure_copy (in_s); gst_structure_set (out_s, "channels", G_TYPE_INT, channels, NULL); if (channel_mask != 0) { /* positioned layout */ gst_structure_set (out_s, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL); } else { /* unpositioned layout */ gst_structure_remove_field (out_s, "channel-mask"); } #ifndef HAVE_IOS if (core_audio->is_src && got_outer_asbd && outer_asbd.mSampleRate != kAudioStreamAnyRate) { /* According to Core Audio engineer, AUHAL does not support sample rate conversion. * on sources. Therefore, we fixate the sample rate. * * "You definitely cannot do rate conversion as part of getting input from AUHAL. * That's the most common cause of those "cannot do in current context" errors." * http://lists.apple.com/archives/coreaudio-api/2006/Sep/msg00088.html */ gst_structure_set (out_s, "rate", G_TYPE_INT, (gint) outer_asbd.mSampleRate, NULL); } #endif /* Special cases for upmixing and downmixing. * Other than that, the AUs don't upmix or downmix multi-channel audio, * e.g. if you push 5.1-surround audio to a stereo configuration, * the left and right channels will be played accordingly, * and the rest will be dropped. */ if (channels == 1) { /* If have mono, then also offer stereo since CoreAudio downmixes to it */ GstStructure *stereo = gst_structure_copy (out_s); gst_structure_remove_field (out_s, "channel-mask"); gst_structure_set (stereo, "channels", G_TYPE_INT, 2, "channel-mask", GST_TYPE_BITMASK, STEREO_CHANNEL_MASK, NULL); gst_caps_append_structure (caps, stereo); gst_caps_append_structure (caps, out_s); } else if (channels == 2 && (channel_mask == 0 || channel_mask == STEREO_CHANNEL_MASK)) { /* If have stereo channels, then also offer mono since CoreAudio * upmixes it. */ GstStructure *mono = gst_structure_copy (out_s); gst_structure_set (mono, "channels", G_TYPE_INT, 1, NULL); gst_structure_remove_field (mono, "channel-mask"); gst_structure_set (out_s, "channel-mask", GST_TYPE_BITMASK, STEREO_CHANNEL_MASK, NULL); gst_caps_append_structure (caps, out_s); gst_caps_append_structure (caps, mono); } else { /* Otherwhise just add the caps */ gst_caps_append_structure (caps, out_s); } } } GST_DEBUG_OBJECT (core_audio, "Probed caps:%" GST_PTR_FORMAT, caps); return caps; }
static gboolean gst_osx_audio_sink_allowed_caps (GstOsxAudioSink * osxsink) { gint i, channels; gboolean spdif_allowed; AudioChannelLayout *layout; GstElementClass *element_class; GstPadTemplate *pad_template; GstCaps *caps, *in_caps; guint64 channel_mask = 0; GstAudioChannelPosition *pos = osxsink->channel_positions; /* First collect info about the HW capabilites and preferences */ spdif_allowed = gst_core_audio_audio_device_is_spdif_avail (osxsink->device_id); layout = gst_core_audio_audio_device_get_channel_layout (osxsink->device_id); GST_DEBUG_OBJECT (osxsink, "Selected device ID: %u SPDIF allowed: %d", (unsigned) osxsink->device_id, spdif_allowed); if (layout) { channels = MIN (layout->mNumberChannelDescriptions, GST_OSX_AUDIO_MAX_CHANNEL); } else { GST_WARNING_OBJECT (osxsink, "This driver does not support " "kAudioDevicePropertyPreferredChannelLayout."); channels = 2; } switch (channels) { case 0: pos[0] = GST_AUDIO_CHANNEL_POSITION_NONE; break; case 1: pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO; break; case 2: pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; channel_mask |= GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT); channel_mask |= GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT); break; default: channels = MIN (layout->mNumberChannelDescriptions, GST_OSX_AUDIO_MAX_CHANNEL); for (i = 0; i < channels; i++) { switch (layout->mChannelDescriptions[i].mChannelLabel) { case kAudioChannelLabel_Left: pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; break; case kAudioChannelLabel_Right: pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; break; case kAudioChannelLabel_Center: pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER; break; case kAudioChannelLabel_LFEScreen: pos[i] = GST_AUDIO_CHANNEL_POSITION_LFE1; break; case kAudioChannelLabel_LeftSurround: pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT; break; case kAudioChannelLabel_RightSurround: pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT; break; case kAudioChannelLabel_RearSurroundLeft: pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT; break; case kAudioChannelLabel_RearSurroundRight: pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT; break; case kAudioChannelLabel_CenterSurround: pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER; break; default: GST_WARNING_OBJECT (osxsink, "unrecognized channel: %d", (int) layout->mChannelDescriptions[i].mChannelLabel); channel_mask = 0; channels = 2; break; } } } g_free (layout); /* Recover the template caps */ element_class = GST_ELEMENT_GET_CLASS (osxsink); pad_template = gst_element_class_get_pad_template (element_class, "sink"); in_caps = gst_pad_template_get_caps (pad_template); /* Create the allowed subset */ caps = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (in_caps); i++) { GstStructure *in_s, *out_s; in_s = gst_caps_get_structure (in_caps, i); if (gst_structure_has_name (in_s, "audio/x-ac3") || gst_structure_has_name (in_s, "audio/x-dts")) { if (spdif_allowed) { gst_caps_append_structure (caps, gst_structure_copy (in_s)); } } gst_audio_channel_positions_to_mask (pos, channels, false, &channel_mask); out_s = gst_structure_copy (in_s); gst_structure_remove_fields (out_s, "channels", "channel-mask", NULL); gst_structure_set (out_s, "channels", G_TYPE_INT, channels, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL); gst_caps_append_structure (caps, out_s); } if (osxsink->cached_caps) { gst_caps_unref (osxsink->cached_caps); } osxsink->cached_caps = caps; osxsink->channels = channels; return TRUE; }