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);
}
Пример #2
0
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;
}
Пример #3
0
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;
}