static gboolean
gst_openal_src_prepare (GstAudioSrc * audiosrc, GstAudioRingBufferSpec * spec)
{
  GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc);

  gst_openal_src_parse_spec (openalsrc, spec);
  if (openalsrc->format == AL_NONE) {
    GST_ELEMENT_ERROR (openalsrc, RESOURCE, SETTINGS, (NULL),
        ("Unable to get type %d, format %d, and %d channels", spec->type,
            GST_AUDIO_INFO_FORMAT (&spec->info),
            GST_AUDIO_INFO_CHANNELS (&spec->info)));
    return FALSE;
  }

  openalsrc->device =
      alcCaptureOpenDevice (openalsrc->default_device, openalsrc->rate,
      openalsrc->format, openalsrc->buffer_length);

  if (!openalsrc->device) {
    GST_ELEMENT_ERROR (openalsrc, RESOURCE, OPEN_READ,
        ("Could not open device."), GST_ALC_ERROR (openalsrc->device));
    return FALSE;
  }

  openalsrc->default_device_name =
      g_strdup (alcGetString (openalsrc->device, ALC_DEVICE_SPECIFIER));

  alcCaptureStart (openalsrc->device);

  return TRUE;
}
static void
gst_openal_src_finalize (GObject * object)
{
  GstOpenalSrc *osrc = GST_OPENAL_SRC (object);

  g_free (osrc->deviceName);
  g_free (osrc->device);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}
static guint
gst_openal_src_delay (GstAudioSrc * asrc)
{
  GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
  gint samples;

  alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples),
      &samples);

  return samples;
}
static void
gst_openal_src_dispose (GObject * object)
{
  GstOpenalSrc *openalsrc = GST_OPENAL_SRC (object);

  if (openalsrc->probed_caps)
    gst_caps_unref (openalsrc->probed_caps);
  openalsrc->probed_caps = NULL;

  G_OBJECT_CLASS (gst_openal_src_parent_class)->dispose (object);
}
static GstCaps *
gst_openal_src_getcaps (GstBaseSrc * basesrc, GstCaps * filter)
{
  GstOpenalSrc *openalsrc = GST_OPENAL_SRC (basesrc);
  GstCaps *caps;
  ALCdevice *device;

  device = alcOpenDevice (NULL);

  if (device == NULL) {
    GstPad *pad = GST_BASE_SRC_PAD (basesrc);
    GstCaps *tcaps = gst_pad_get_pad_template_caps (pad);

    GST_ELEMENT_WARNING (openalsrc, RESOURCE, OPEN_WRITE,
        ("Could not open temporary device."), GST_ALC_ERROR (device));
    caps = gst_caps_copy (tcaps);
    gst_caps_unref (tcaps);
  } else if (openalsrc->probed_caps)
    caps = gst_caps_copy (openalsrc->probed_caps);
  else {
    ALCcontext *context = alcCreateContext (device, NULL);
    if (context) {
      caps = gst_openal_helper_probe_caps (context);
      alcDestroyContext (context);
    } else {
      GST_ELEMENT_WARNING (openalsrc, RESOURCE, FAILED,
          ("Could not create temporary context."), GST_ALC_ERROR (device));
      caps = NULL;
    }

    if (caps && !gst_caps_is_empty (caps))
      openalsrc->probed_caps = gst_caps_copy (caps);
  }

  if (device != NULL) {
    if (alcCloseDevice (device) == ALC_FALSE) {
      GST_ELEMENT_WARNING (openalsrc, RESOURCE, CLOSE,
          ("Could not close temporary device."), GST_ALC_ERROR (device));
    }
  }

  if (filter) {
    GstCaps *intersection;

    intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    return intersection;
  } else {
    return caps;
  }
}
static gboolean
gst_openal_src_unprepare (GstAudioSrc * asrc)
{

  GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);

  GST_INFO_OBJECT (osrc, "Close device : %s", osrc->deviceName);
  if (osrc->deviceHandle) {
    alcCaptureStop (osrc->deviceHandle);
    alcCaptureCloseDevice (osrc->deviceHandle);
  }

  return TRUE;
}
static guint
gst_openal_src_delay (GstAudioSrc * audiosrc)
{
  GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc);
  ALint samples;

  alcGetIntegerv (openalsrc->device, ALC_CAPTURE_SAMPLES, sizeof (samples),
      &samples);

  if (G_UNLIKELY (samples < 0)) {
    /* make sure we never return a negative delay */
    GST_WARNING_OBJECT (openal_debug, "negative delay");
    samples = 0;
  }

  return samples;
}
static gboolean
gst_openal_src_unprepare (GstAudioSrc * audiosrc)
{
  GstOpenalSrc *openalsrc = GST_OPENAL_SRC (audiosrc);

  if (openalsrc->device) {
    alcCaptureStop (openalsrc->device);

    if (alcCaptureCloseDevice (openalsrc->device) == ALC_FALSE) {
      GST_ELEMENT_ERROR (openalsrc, RESOURCE, CLOSE,
          ("Could not close device."), GST_ALC_ERROR (openalsrc->device));
      return FALSE;
    }
  }

  return TRUE;
}
static gboolean
gst_openal_src_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
{

  GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
  ALenum format;
  guint64 bufferSize;

  switch (spec->width) {
    case 8:
      format = AL_FORMAT_STEREO8;
      break;
    case 16:
      format = AL_FORMAT_STEREO16;
      break;
    default:
      g_assert_not_reached ();
  }

  bufferSize =
      spec->buffer_time * spec->rate * spec->bytes_per_sample / 1000000;

  GST_INFO_OBJECT (osrc, "Open device : %s", osrc->deviceName);
  osrc->deviceHandle =
      alcCaptureOpenDevice (osrc->device, spec->rate, format, bufferSize);

  if (!osrc->deviceHandle) {
    GST_ELEMENT_ERROR (osrc,
        RESOURCE,
        FAILED,
        ("Can't open device \"%s\"", osrc->device),
        ("Can't open device \"%s\"", osrc->device)
        );
    return FALSE;
  }

  osrc->deviceName =
      g_strdup (alcGetString (osrc->deviceHandle, ALC_DEVICE_SPECIFIER));
  osrc->bytes_per_sample = spec->bytes_per_sample;

  GST_INFO_OBJECT (osrc, "Start capture");
  alcCaptureStart (osrc->deviceHandle);

  return TRUE;
}
static void
gst_openal_src_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
  GstOpenalSrc *osrc = GST_OPENAL_SRC (object);

  switch (prop_id) {
    case PROP_DEVICE:
      g_value_set_string (value, osrc->device);
      break;
    case PROP_DEVICE_NAME:
      g_value_set_string (value, osrc->deviceName);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static guint
gst_openal_src_read (GstAudioSrc * asrc, gpointer data, guint length)
{
  GstOpenalSrc *osrc = GST_OPENAL_SRC (asrc);
  gint samples;

  alcGetIntegerv (osrc->deviceHandle, ALC_CAPTURE_SAMPLES, sizeof (samples),
      &samples);

  if (samples * osrc->bytes_per_sample > length) {
    samples = length / osrc->bytes_per_sample;
  }

  if (samples) {
    GST_DEBUG_OBJECT (osrc, "Read samples : %d", samples);
    alcCaptureSamples (osrc->deviceHandle, data, samples);
  }

  return samples * osrc->bytes_per_sample;
}