Blame tests/check/elements/rawaudioparse.c

Packit 971217
/* GStreamer
Packit 971217
 *
Packit 971217
 * unit test for rawaudioparse
Packit 971217
 *
Packit 971217
 * Copyright (C) <2016> Carlos Rafael Giani <dv at pseudoterminal dot org>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
/* FIXME: GValueArray is deprecated, but there is currently no viable alternatives
Packit 971217
 * See https://bugzilla.gnome.org/show_bug.cgi?id=667228 */
Packit 971217
#define GLIB_DISABLE_DEPRECATION_WARNINGS
Packit 971217
Packit 971217
#include <gst/check/gstcheck.h>
Packit 971217
#include <gst/audio/audio.h>
Packit 971217
Packit 971217
/* Checks are hardcoded to expect stereo 16-bit data. The sample rate
Packit 971217
 * however varies from the default of 40 kHz in some tests to see the
Packit 971217
 * differences in calculated buffer durations. */
Packit 971217
#define NUM_TEST_SAMPLES 512
Packit 971217
#define NUM_TEST_CHANNELS 2
Packit 971217
#define TEST_SAMPLE_RATE 40000
Packit 971217
#define TEST_SAMPLE_FORMAT GST_AUDIO_FORMAT_S16
Packit 971217
Packit 971217
/* For ease of programming we use globals to keep refs for our floating
Packit 971217
 * src and sink pads we create; otherwise we always have to do get_pad,
Packit 971217
 * get_peer, and then remove references in every test function */
Packit 971217
static GstPad *mysrcpad, *mysinkpad;
Packit 971217
Packit 971217
typedef struct
Packit 971217
{
Packit 971217
  GstElement *rawaudioparse;
Packit 971217
  GstAdapter *test_data_adapter;
Packit 971217
}
Packit 971217
RawAudParseTestCtx;
Packit 971217
Packit 971217
/* Sets up a rawaudioparse element and a GstAdapter that contains 512 test
Packit 971217
 * audio samples. The samples a monotonically increasing set from the values
Packit 971217
 * 0 to 511 for the left and 512 to 1023 for the right channel. The result
Packit 971217
 * is a GstAdapter that contains the interleaved 16-bit integer values:
Packit 971217
 * 0,512,1,513,2,514, ... 511,1023 . This set is used in the checks to see
Packit 971217
 * if rawaudioparse's output buffers contain valid data. */
Packit 971217
static void
Packit 971217
setup_rawaudioparse (RawAudParseTestCtx * testctx, gboolean use_sink_caps,
Packit 971217
    gboolean set_properties, GstCaps * incaps, GstFormat format)
Packit 971217
{
Packit 971217
  GstElement *rawaudioparse;
Packit 971217
  GstAdapter *test_data_adapter;
Packit 971217
  GstBuffer *buffer;
Packit 971217
  guint i;
Packit 971217
  guint16 samples[NUM_TEST_SAMPLES * NUM_TEST_CHANNELS];
Packit 971217
Packit 971217
Packit 971217
  /* Setup the rawaudioparse element and the pads */
Packit 971217
Packit 971217
  static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
Packit 971217
      GST_PAD_SINK,
Packit 971217
      GST_PAD_ALWAYS,
Packit 971217
      GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL))
Packit 971217
      );
Packit 971217
  static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
Packit 971217
      GST_PAD_SRC,
Packit 971217
      GST_PAD_ALWAYS,
Packit 971217
      GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
  rawaudioparse = gst_check_setup_element ("rawaudioparse");
Packit 971217
Packit 971217
  g_object_set (G_OBJECT (rawaudioparse), "use-sink-caps", use_sink_caps, NULL);
Packit 971217
  if (set_properties)
Packit 971217
    g_object_set (G_OBJECT (rawaudioparse), "sample-rate", TEST_SAMPLE_RATE,
Packit 971217
        "num-channels", NUM_TEST_CHANNELS, "pcm-format", TEST_SAMPLE_FORMAT,
Packit 971217
        NULL);
Packit 971217
Packit 971217
  fail_unless (gst_element_set_state (rawaudioparse,
Packit 971217
          GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS,
Packit 971217
      "could not set to paused");
Packit 971217
Packit 971217
  mysrcpad = gst_check_setup_src_pad (rawaudioparse, &srctemplate);
Packit 971217
  mysinkpad = gst_check_setup_sink_pad (rawaudioparse, &sinktemplate);
Packit 971217
Packit 971217
  gst_pad_set_active (mysrcpad, TRUE);
Packit 971217
  gst_pad_set_active (mysinkpad, TRUE);
Packit 971217
Packit 971217
  gst_check_setup_events (mysrcpad, rawaudioparse, incaps, format);
Packit 971217
  if (incaps)
Packit 971217
    gst_caps_unref (incaps);
Packit 971217
Packit 971217
Packit 971217
  /* Fill the adapter with the interleaved 0..511 and
Packit 971217
   * 512..1023 samples */
Packit 971217
  for (i = 0; i < NUM_TEST_SAMPLES; ++i) {
Packit 971217
    guint c;
Packit 971217
    for (c = 0; c < NUM_TEST_CHANNELS; ++c)
Packit 971217
      samples[i * NUM_TEST_CHANNELS + c] = c * NUM_TEST_SAMPLES + i;
Packit 971217
  }
Packit 971217
Packit 971217
  test_data_adapter = gst_adapter_new ();
Packit 971217
  buffer = gst_buffer_new_allocate (NULL, sizeof (samples), NULL);
Packit 971217
  gst_buffer_fill (buffer, 0, samples, sizeof (samples));
Packit 971217
  gst_adapter_push (test_data_adapter, buffer);
Packit 971217
Packit 971217
Packit 971217
  testctx->rawaudioparse = rawaudioparse;
Packit 971217
  testctx->test_data_adapter = test_data_adapter;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
cleanup_rawaudioparse (RawAudParseTestCtx * testctx)
Packit 971217
{
Packit 971217
  int num_buffers, i;
Packit 971217
Packit 971217
  gst_pad_set_active (mysrcpad, FALSE);
Packit 971217
  gst_pad_set_active (mysinkpad, FALSE);
Packit 971217
  gst_check_teardown_src_pad (testctx->rawaudioparse);
Packit 971217
  gst_check_teardown_sink_pad (testctx->rawaudioparse);
Packit 971217
  gst_check_teardown_element (testctx->rawaudioparse);
Packit 971217
Packit 971217
  g_object_unref (G_OBJECT (testctx->test_data_adapter));
Packit 971217
Packit 971217
  if (buffers != NULL) {
Packit 971217
    num_buffers = g_list_length (buffers);
Packit 971217
    for (i = 0; i < num_buffers; ++i) {
Packit 971217
      GstBuffer *buf = GST_BUFFER (buffers->data);
Packit 971217
      buffers = g_list_remove (buffers, buf);
Packit 971217
      gst_buffer_unref (buf);
Packit 971217
    }
Packit 971217
Packit 971217
    g_list_free (buffers);
Packit 971217
    buffers = NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
static void
Packit 971217
push_data_and_check_output (RawAudParseTestCtx * testctx, gsize num_in_bytes,
Packit 971217
    gsize expected_num_out_bytes, gint64 expected_pts, gint64 expected_dur,
Packit 971217
    guint expected_num_buffers_in_list, guint bpf, guint16 channel0_start,
Packit 971217
    guint16 channel1_start)
Packit 971217
{
Packit 971217
  GstBuffer *inbuf, *outbuf;
Packit 971217
  guint num_buffers;
Packit 971217
Packit 971217
  /* Simulate upstream input by taking num_in_bytes bytes from the adapter */
Packit 971217
  inbuf = gst_adapter_take_buffer (testctx->test_data_adapter, num_in_bytes);
Packit 971217
  fail_unless (inbuf != NULL);
Packit 971217
Packit 971217
  /* Push the input data and check that the output buffers list grew as
Packit 971217
   * expected */
Packit 971217
  fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
Packit 971217
  num_buffers = g_list_length (buffers);
Packit 971217
  fail_unless_equals_int (num_buffers, expected_num_buffers_in_list);
Packit 971217
Packit 971217
  /* Take the latest output buffer */
Packit 971217
  outbuf = g_list_nth_data (buffers, num_buffers - 1);
Packit 971217
  fail_unless (outbuf != NULL);
Packit 971217
Packit 971217
  /* Verify size, PTS, duration of the output buffer */
Packit 971217
  fail_unless_equals_uint64 (expected_num_out_bytes,
Packit 971217
      gst_buffer_get_size (outbuf));
Packit 971217
  fail_unless_equals_uint64 (expected_pts, GST_BUFFER_PTS (outbuf));
Packit 971217
  fail_unless_equals_uint64 (expected_dur, GST_BUFFER_DURATION (outbuf));
Packit 971217
Packit 971217
  /* Go through all of the samples in the output buffer and check that they are
Packit 971217
   * valid. The samples are interleaved. The offsets specified by channel0_start
Packit 971217
   * and channel1_start are the expected values of the first sample for each
Packit 971217
   * channel in the buffer. So, if channel0_start is 512, then sample #0 in the
Packit 971217
   * buffer must have value 512, and if channel1_start is 700, then sample #1
Packit 971217
   * in the buffer must have value 700 etc. */
Packit 971217
  {
Packit 971217
    guint i, num_frames;
Packit 971217
    guint16 *s;
Packit 971217
    GstMapInfo map_info;
Packit 971217
    guint channel_starts[2] = { channel0_start, channel1_start };
Packit 971217
Packit 971217
    gst_buffer_map (outbuf, &map_info, GST_MAP_READ);
Packit 971217
    num_frames = map_info.size / bpf;
Packit 971217
    s = (guint16 *) (map_info.data);
Packit 971217
Packit 971217
    for (i = 0; i < num_frames; ++i) {
Packit 971217
      guint c;
Packit 971217
Packit 971217
      for (c = 0; i < NUM_TEST_CHANNELS; ++i) {
Packit 971217
        guint16 expected = channel_starts[c] + i;
Packit 971217
        guint16 actual = s[i * NUM_TEST_CHANNELS + c];
Packit 971217
Packit 971217
        fail_unless_equals_int (expected, actual);
Packit 971217
      }
Packit 971217
    }
Packit 971217
Packit 971217
    gst_buffer_unmap (outbuf, &map_info);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
GST_START_TEST (test_push_unaligned_data_properties_config)
Packit 971217
{
Packit 971217
  RawAudParseTestCtx testctx;
Packit 971217
Packit 971217
  setup_rawaudioparse (&testctx, FALSE, TRUE, NULL, GST_FORMAT_BYTES);
Packit 971217
Packit 971217
  /* Send in data buffers that are not aligned to multiples of the
Packit 971217
   * frame size (= sample size * num_channels). This tests if rawaudioparse
Packit 971217
   * aligns output data properly.
Packit 971217
   *
Packit 971217
   * The second line sends in 99 bytes, and expects 100 bytes in the
Packit 971217
   * output buffer. This is because the first buffer contains 45 bytes,
Packit 971217
   * and rawaudioparse is expected to output 44 bytes (which is an integer
Packit 971217
   * multiple of the frame size). The leftover 1 byte then gets prepended
Packit 971217
   * to the input buffer with 99 bytes, resulting in 100 bytes, which is
Packit 971217
   * an integer multiple of the frame size.
Packit 971217
   */
Packit 971217
Packit 971217
  push_data_and_check_output (&testctx, 45, 44, GST_USECOND * 0,
Packit 971217
      GST_USECOND * 275, 1, 4, 0, 512);
Packit 971217
  push_data_and_check_output (&testctx, 99, 100, GST_USECOND * 275,
Packit 971217
      GST_USECOND * 625, 2, 4, 11, 523);
Packit 971217
  push_data_and_check_output (&testctx, 18, 16, GST_USECOND * 900,
Packit 971217
      GST_USECOND * 100, 3, 4, 36, 548);
Packit 971217
Packit 971217
  cleanup_rawaudioparse (&testctx);
Packit 971217
}
Packit 971217
Packit 971217
GST_END_TEST;
Packit 971217
Packit 971217
GST_START_TEST (test_push_unaligned_data_sink_caps_config)
Packit 971217
{
Packit 971217
  RawAudParseTestCtx testctx;
Packit 971217
  GstAudioInfo ainfo;
Packit 971217
  GstCaps *caps;
Packit 971217
Packit 971217
  /* This test is essentially the same as test_push_unaligned_data_properties_config,
Packit 971217
   * except that rawaudioparse uses the sink caps config instead of the property config. */
Packit 971217
Packit 971217
  gst_audio_info_set_format (&ainfo, TEST_SAMPLE_FORMAT, TEST_SAMPLE_RATE,
Packit 971217
      NUM_TEST_CHANNELS, NULL);
Packit 971217
  caps = gst_audio_info_to_caps (&ainfo);
Packit 971217
Packit 971217
  setup_rawaudioparse (&testctx, TRUE, FALSE, caps, GST_FORMAT_BYTES);
Packit 971217
Packit 971217
  push_data_and_check_output (&testctx, 45, 44, GST_USECOND * 0,
Packit 971217
      GST_USECOND * 275, 1, 4, 0, 512);
Packit 971217
  push_data_and_check_output (&testctx, 99, 100, GST_USECOND * 275,
Packit 971217
      GST_USECOND * 625, 2, 4, 11, 523);
Packit 971217
  push_data_and_check_output (&testctx, 18, 16, GST_USECOND * 900,
Packit 971217
      GST_USECOND * 100, 3, 4, 36, 548);
Packit 971217
Packit 971217
  cleanup_rawaudioparse (&testctx);
Packit 971217
}
Packit 971217
Packit 971217
GST_END_TEST;
Packit 971217
Packit 971217
GST_START_TEST (test_push_swapped_channels)
Packit 971217
{
Packit 971217
  RawAudParseTestCtx testctx;
Packit 971217
  GValueArray *valarray;
Packit 971217
  GValue val = G_VALUE_INIT;
Packit 971217
Packit 971217
  /* Send in 40 bytes and use a nonstandard channel order (left and right channels
Packit 971217
   * swapped). Expected behavior is for rawaudioparse to reorder the samples inside
Packit 971217
   * output buffers to conform to the GStreamer channel order. For this reason,
Packit 971217
   * channel0 offset is 512 and channel1 offset is 0 in the check below. */
Packit 971217
Packit 971217
  setup_rawaudioparse (&testctx, FALSE, TRUE, NULL, GST_FORMAT_BYTES);
Packit 971217
Packit 971217
  valarray = g_value_array_new (2);
Packit 971217
  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
Packit 971217
  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT);
Packit 971217
  g_value_array_insert (valarray, 0, &val;;
Packit 971217
  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT);
Packit 971217
  g_value_array_insert (valarray, 1, &val;;
Packit 971217
  g_object_set (G_OBJECT (testctx.rawaudioparse), "channel-positions",
Packit 971217
      valarray, NULL);
Packit 971217
  g_value_array_free (valarray);
Packit 971217
  g_value_unset (&val;;
Packit 971217
Packit 971217
  push_data_and_check_output (&testctx, 40, 40, GST_USECOND * 0,
Packit 971217
      GST_USECOND * 250, 1, 4, 512, 0);
Packit 971217
Packit 971217
  cleanup_rawaudioparse (&testctx);
Packit 971217
}
Packit 971217
Packit 971217
GST_END_TEST;
Packit 971217
Packit 971217
GST_START_TEST (test_config_switch)
Packit 971217
{
Packit 971217
  RawAudParseTestCtx testctx;
Packit 971217
  GstAudioInfo ainfo;
Packit 971217
  GstCaps *caps;
Packit 971217
Packit 971217
  /* Start processing with the properties config active, then mid-stream switch to
Packit 971217
   * the sink caps config. The properties config is altered to have a different
Packit 971217
   * sample rate than the sink caps to be able to detect the switch. The net effect
Packit 971217
   * is that output buffer durations are altered. For example, 40 bytes equal
Packit 971217
   * 10 samples, and this equals 500 us with 20 kHz or 250 us with 40 kHz. */
Packit 971217
Packit 971217
  gst_audio_info_set_format (&ainfo, TEST_SAMPLE_FORMAT, TEST_SAMPLE_RATE,
Packit 971217
      NUM_TEST_CHANNELS, NULL);
Packit 971217
  caps = gst_audio_info_to_caps (&ainfo);
Packit 971217
Packit 971217
  setup_rawaudioparse (&testctx, FALSE, TRUE, caps, GST_FORMAT_BYTES);
Packit 971217
Packit 971217
  g_object_set (G_OBJECT (testctx.rawaudioparse), "sample-rate", 20000, NULL);
Packit 971217
Packit 971217
  /* Push in data with properties config active, expecting duration calculations
Packit 971217
   * to be based on the 20 kHz sample rate */
Packit 971217
  push_data_and_check_output (&testctx, 40, 40, GST_USECOND * 0,
Packit 971217
      GST_USECOND * 500, 1, 4, 0, 512);
Packit 971217
  push_data_and_check_output (&testctx, 20, 20, GST_USECOND * 500,
Packit 971217
      GST_USECOND * 250, 2, 4, 10, 522);
Packit 971217
Packit 971217
  /* Perform the switch */
Packit 971217
  g_object_set (G_OBJECT (testctx.rawaudioparse), "use-sink-caps", TRUE, NULL);
Packit 971217
Packit 971217
  /* Push in data with sink caps config active, expecting duration calculations
Packit 971217
   * to be based on the 40 kHz sample rate */
Packit 971217
  push_data_and_check_output (&testctx, 40, 40, GST_USECOND * 750,
Packit 971217
      GST_USECOND * 250, 3, 4, 15, 527);
Packit 971217
Packit 971217
  cleanup_rawaudioparse (&testctx);
Packit 971217
}
Packit 971217
Packit 971217
GST_END_TEST;
Packit 971217
Packit 971217
GST_START_TEST (test_change_caps)
Packit 971217
{
Packit 971217
  RawAudParseTestCtx testctx;
Packit 971217
  GstAudioInfo ainfo;
Packit 971217
  GstCaps *caps;
Packit 971217
Packit 971217
  /* Start processing with the sink caps config active, using the
Packit 971217
   * default channel count and sample format and 20 kHz sample rate
Packit 971217
   * for the caps. Push some data, then change caps (20 kHz -> 40 kHz).
Packit 971217
   * Check that the changed caps are handled properly. */
Packit 971217
Packit 971217
  gst_audio_info_set_format (&ainfo, TEST_SAMPLE_FORMAT, 20000,
Packit 971217
      NUM_TEST_CHANNELS, NULL);
Packit 971217
  caps = gst_audio_info_to_caps (&ainfo);
Packit 971217
Packit 971217
  setup_rawaudioparse (&testctx, TRUE, FALSE, caps, GST_FORMAT_BYTES);
Packit 971217
Packit 971217
  /* Push in data with caps sink config active, expecting duration calculations
Packit 971217
   * to be based on the 20 kHz sample rate */
Packit 971217
  push_data_and_check_output (&testctx, 40, 40, GST_USECOND * 0,
Packit 971217
      GST_USECOND * 500, 1, 4, 0, 512);
Packit 971217
  push_data_and_check_output (&testctx, 20, 20, GST_USECOND * 500,
Packit 971217
      GST_USECOND * 250, 2, 4, 10, 522);
Packit 971217
Packit 971217
  /* Change caps */
Packit 971217
  gst_audio_info_set_format (&ainfo, TEST_SAMPLE_FORMAT, 40000,
Packit 971217
      NUM_TEST_CHANNELS, NULL);
Packit 971217
  caps = gst_audio_info_to_caps (&ainfo);
Packit 971217
  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps)));
Packit 971217
  gst_caps_unref (caps);
Packit 971217
Packit 971217
  /* Push in data with the new caps, expecting duration calculations
Packit 971217
   * to be based on the 40 kHz sample rate */
Packit 971217
  push_data_and_check_output (&testctx, 40, 40, GST_USECOND * 750,
Packit 971217
      GST_USECOND * 250, 3, 4, 15, 527);
Packit 971217
Packit 971217
  cleanup_rawaudioparse (&testctx);
Packit 971217
}
Packit 971217
Packit 971217
GST_END_TEST;
Packit 971217
Packit 971217
Packit 971217
static Suite *
Packit 971217
rawaudioparse_suite (void)
Packit 971217
{
Packit 971217
  Suite *s = suite_create ("rawaudioparse");
Packit 971217
  TCase *tc_chain = tcase_create ("general");
Packit 971217
Packit 971217
  suite_add_tcase (s, tc_chain);
Packit 971217
  tcase_add_test (tc_chain, test_push_unaligned_data_properties_config);
Packit 971217
  tcase_add_test (tc_chain, test_push_unaligned_data_sink_caps_config);
Packit 971217
  tcase_add_test (tc_chain, test_push_swapped_channels);
Packit 971217
  tcase_add_test (tc_chain, test_config_switch);
Packit 971217
  tcase_add_test (tc_chain, test_change_caps);
Packit 971217
Packit 971217
  return s;
Packit 971217
}
Packit 971217
Packit 971217
GST_CHECK_MAIN (rawaudioparse);