#include <gst/base/gstbasesink.h>
#include <gst/audio/streamvolume.h>
#include "gstdirectsoundsink.h"
+#include <gst/audio/gstaudioiec61937.h>
#include <math.h>
static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink,
GstCaps * filter);
+static GstBuffer *gst_directsound_sink_payload (GstAudioBaseSink * sink,
+ GstBuffer * buf);
static gboolean gst_directsound_sink_prepare (GstAudioSink * asink,
GstAudioRingBufferSpec * spec);
static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink);
static void gst_directsound_sink_reset (GstAudioSink * asink);
static GstCaps *gst_directsound_probe_supported_formats (GstDirectSoundSink *
dsoundsink, const GstCaps * template_caps);
+static gboolean gst_directsound_sink_query (GstBaseSink * pad, GstQuery * query);
static void gst_directsound_sink_set_volume (GstDirectSoundSink * sink,
gdouble volume, gboolean store);
"format = (string) S8, "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];"
- "audio/x-iec958"));
+ "audio/x-ac3, framed = (boolean) true;"));
enum
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (klass);
+ GstAudioBaseSinkClass *gstaudiobasesink_class = GST_AUDIO_BASE_SINK_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0,
gstbasesink_class->get_caps =
GST_DEBUG_FUNCPTR (gst_directsound_sink_getcaps);
+ gstbasesink_class->query =
+ GST_DEBUG_FUNCPTR (gst_directsound_sink_query);
+
+ gstaudiobasesink_class->payload =
+ GST_DEBUG_FUNCPTR (gst_directsound_sink_payload);
+
gstaudiosink_class->prepare =
GST_DEBUG_FUNCPTR (gst_directsound_sink_prepare);
gstaudiosink_class->unprepare =
}
static gboolean
+gst_directsound_sink_acceptcaps (GstBaseSink * sink, GstQuery * query)
+{
+ GstDirectSoundSink *dsink = GST_DIRECTSOUND_SINK (sink);
+ GstAudioRingBuffer *rbuf = GST_AUDIO_BASE_SINK (dsink)->ringbuffer;
+ GstPad *pad;
+ GstCaps *caps;
+ GstCaps *pad_caps;
+ GstStructure *st;
+ gboolean ret = FALSE;
+
+ GstAudioRingBufferSpec spec = { 0 };
+
+ if (G_UNLIKELY (dsink == NULL))
+ return FALSE;
+
+ pad = sink->sinkpad;
+
+ gst_query_parse_accept_caps (query, &caps);
+ GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
+
+ pad_caps = gst_pad_query_caps (pad, NULL);
+ if (pad_caps) {
+ ret = gst_caps_can_intersect (pad_caps, caps);
+ gst_caps_unref (pad_caps);
+ if (!ret)
+ goto done;
+ }
+
+ /* If we've not got fixed caps, creating a stream might fail, so let's just
+ * return from here with default acceptcaps behaviour */
+ if (!gst_caps_is_fixed (caps))
+ goto done;
+
+ if (!gst_audio_ring_buffer_parse_caps (&rbuf->spec, caps))
+ goto done;
+
+ /* Make sure input is framed (one frame per buffer) and can be payloaded */
+ switch (rbuf->spec.type) {
+ case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
+ {
+ gboolean framed = FALSE, parsed = FALSE;
+ st = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_boolean (st, "framed", &framed);
+ gst_structure_get_boolean (st, "parsed", &parsed);
+ if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
+ goto done;
+ }
+ default:{
+ }
+ }
+ ret = TRUE;
+
+done:
+ gst_object_unref (dsink);
+ gst_query_set_accept_caps_result (query, ret);
+ return TRUE;
+}
+
+static gboolean
+gst_directsound_sink_query (GstBaseSink * sink, GstQuery * query)
+{
+ gboolean res = TRUE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_ACCEPT_CAPS:
+ res = gst_directsound_sink_acceptcaps (sink, query);
+ break;
+ default:
+ res = FALSE;
+ }
+
+ return res;
+}
+
+static gboolean
gst_directsound_sink_open (GstAudioSink * asink)
{
GstDirectSoundSink *dsoundsink;
return TRUE;
}
+static boolean
+gst_directsound_sink_is_spdif_format (GstDirectSoundSink * dsoundsink)
+{
+ GstAudioRingBufferFormatType type;
+ type = GST_AUDIO_BASE_SINK (dsoundsink)->ringbuffer->spec.type;
+ return type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3;
+}
+
static gboolean
gst_directsound_sink_prepare (GstAudioSink * asink,
GstAudioRingBufferSpec * spec)
/* fill the WAVEFORMATEX structure with spec params */
memset (&wfx, 0, sizeof (wfx));
- if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958) {
+ if (gst_directsound_sink_is_spdif_format (dsoundsink)) {
wfx.cbSize = sizeof (wfx);
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = spec->info.channels;
dsoundsink->buffer_size = spec->segsize * spec->segtotal;
GST_INFO_OBJECT (dsoundsink,
- "GstRingBufferSpec->channels: %d, GstRingBufferSpec->rate: %d, GstRingBufferSpec->bytes_per_sample: %d\n"
+ "GstAudioRingBufferSpec->channels: %d, GstAudioRingBufferSpec->rate: %d, GstAudioRingBufferSpec->bytes_per_sample: %d\n"
"WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d, WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n"
"Size of dsound circular buffer=>%d\n", spec->info.channels,
spec->info.rate, spec->info.bpf, wfx.nSamplesPerSec, wfx.wBitsPerSample,
memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
descSecondary.dwSize = sizeof (DSBUFFERDESC);
descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
- if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
+ if (!gst_directsound_sink_is_spdif_format (dsoundsink))
descSecondary.dwFlags |= DSBCAPS_CTRLVOLUME;
descSecondary.dwBufferBytes = dsoundsink->buffer_size;
dsoundsink = GST_DIRECTSOUND_SINK (asink);
- /* Fix endianness */
- if (dsoundsink->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
- _swab (data, data, length);
-
GST_DSOUND_LOCK (dsoundsink);
/* get current buffer status */
GST_INFO_OBJECT (dsoundsink, "AC3 passthrough not supported "
"(IDirectSound_CreateSoundBuffer returned: %s)\n",
DXGetErrorString9 (hRes));
- caps =
- gst_caps_subtract (caps, gst_caps_new_empty_simple ("audio/x-iec958"));
+ caps = gst_caps_subtract (caps, gst_caps_new_empty_simple ("audio/x-ac3"));
} else {
GST_INFO_OBJECT (dsoundsink, "AC3 passthrough supported");
hRes = IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary);
}
}
#else
- caps = gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
+ caps = gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-ac3", NULL));
#endif
return caps;
}
+static GstBuffer *
+gst_directsound_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf)
+{
+ switch (sink->ringbuffer->spec.type) {
+ case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
+ {
+ gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec);
+ GstBuffer *out;
+ GstMapInfo infobuf, infoout;
+ gboolean success;
+
+ if (framesize <= 0)
+ return NULL;
+
+ out = gst_buffer_new_and_alloc (framesize);
+
+ if (!gst_buffer_map (buf, &infobuf, GST_MAP_READWRITE))
+ {
+ gst_buffer_unref (out);
+ return NULL;
+ }
+ if (!gst_buffer_map (out, &infoout, GST_MAP_READWRITE))
+ {
+ gst_buffer_unmap (buf, &infobuf);
+ gst_buffer_unref (out);
+ return NULL;
+ }
+ success = gst_audio_iec61937_payload (infobuf.data, infobuf.size,
+ infoout.data, infoout.size, &sink->ringbuffer->spec);
+ if (!success) {
+ gst_buffer_unmap (out, &infoout);
+ gst_buffer_unmap (buf, &infobuf);
+ gst_buffer_unref (out);
+ return NULL;
+ }
+
+ gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_ALL, 0, -1);
+ /* Fix endianness */
+ _swab ((gchar *) infoout.data, (gchar *) infoout.data, infobuf.size);
+ gst_buffer_unmap (out, &infoout);
+ gst_buffer_unmap (buf, &infobuf);
+ return out;
+ }
+
+ default:
+ return gst_buffer_ref (buf);
+ }
+}
+
static void
gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink,
gdouble dvolume, gboolean store)