pub const ext = @import("ext.zig");
const gstbadaudio = @This();

const std = @import("std");
const compat = @import("compat");
const gstbase = @import("gstbase1");
const gst = @import("gst1");
const gobject = @import("gobject2");
const glib = @import("glib2");
const gmodule = @import("gmodule2");
const gstaudio = @import("gstaudio1");
/// This base class is for decoders which do not operate on a streaming model.
/// That is: they load the encoded media at once, as part of an initialization,
/// and afterwards can decode samples (sometimes referred to as "rendering the
/// samples").
///
/// This sets it apart from GstAudioDecoder, which is a base class for
/// streaming audio decoders.
///
/// The base class is conceptually a mix between decoder and parser. This is
/// unavoidable, since virtually no format that isn't streaming based has a
/// clear distinction between parsing and decoding. As a result, this class
/// also handles seeking.
///
/// Non-streaming audio formats tend to have some characteristics unknown to
/// more "regular" bitstreams. These include subsongs and looping.
///
/// Subsongs are a set of songs-within-a-song. An analogy would be a multitrack
/// recording, where each track is its own song. The first subsong is typically
/// the "main" one. Subsongs were popular for video games to enable context-
/// aware music; for example, subsong ``@"0"`` would be the "main" song, ``@"1"`` would be
/// an alternate song playing when a fight started, ``@"2"`` would be heard during
/// conversations etc. The base class is designed to always have at least one
/// subsong. If the subclass doesn't provide any, the base class creates a
/// "pseudo" subsong, which is actually the whole song.
/// Downstream is informed about the subsong using a table of contents (TOC),
/// but only if there are at least 2 subsongs.
///
/// Looping refers to jumps within the song, typically backwards to the loop
/// start (although bi-directional looping is possible). The loop is defined
/// by a chronological start and end; once the playback position reaches the
/// loop end, it jumps back to the loop start.
/// Depending on the subclass, looping may not be possible at all, or it
/// may only be possible to enable/disable it (that is, either no looping, or
/// an infinite amount of loops), or it may allow for defining a finite number
/// of times the loop is repeated.
/// Looping can affect output in two ways. Either, the playback position is
/// reset to the start of the loop, similar to what happens after a seek event.
/// Or, it is not reset, so the pipeline sees playback steadily moving forwards,
/// the playback position monotonically increasing. However, seeking must
/// always happen within the confines of the defined subsong duration; for
/// example, if a subsong is 2 minutes long, steady playback is at 5 minutes
/// (because infinite looping is enabled), then seeking will still place the
/// position within the 2 minute period.
/// Loop count 0 means no looping. Loop count -1 means infinite looping.
/// Nonzero positive values indicate how often a loop shall occur.
///
/// If the initial subsong and loop count are set to values the subclass does
/// not support, the subclass has a chance to correct these values.
/// `get_property` then reports the corrected versions.
///
/// The base class operates as follows:
/// * Unloaded mode
///   - Initial values are set. If a current subsong has already been
///     defined (for example over the command line with gst-launch), then
///     the subsong index is copied over to current_subsong .
///     Same goes for the num-loops and output-mode properties.
///     Media is NOT loaded yet.
///   - Once the sinkpad is activated, the process continues. The sinkpad is
///     activated in push mode, and the class accumulates the incoming media
///     data in an adapter inside the sinkpad's chain function until either an
///     EOS event is received from upstream, or the number of bytes reported
///     by upstream is reached. Then it loads the media, and starts the decoder
///     output task.
///   - If upstream cannot respond to the size query (in bytes) of `load_from_buffer`
///     fails, an error is reported, and the pipeline stops.
///   - If there are no errors, `load_from_buffer` is called to load the media. The
///     subclass must at least call `gstbadaudio.NonstreamAudioDecoder.setOutputFormat`
///     there, and is free to make use of the initial subsong, output mode, and
///     position. If the actual output mode or position differs from the initial
///     value,it must set the initial value to the actual one (for example, if
///     the actual starting position is always 0, set *initial_position to 0).
///     If loading is unsuccessful, an error is reported, and the pipeline
///     stops. Otherwise, the base class calls `get_current_subsong` to retrieve
///     the actual current subsong, `get_subsong_duration` to report the current
///     subsong's duration in a duration event and message, and `get_subsong_tags`
///     to send tags downstream in an event (these functions are optional; if
///     set to NULL, the associated operation is skipped). Afterwards, the base
///     class switches to loaded mode, and starts the decoder output task.
///
/// * Loaded mode</title>
///   - Inside the decoder output task, the base class repeatedly calls `decode`,
///     which returns a buffer with decoded, ready-to-play samples. If the
///     subclass reached the end of playback, `decode` returns FALSE, otherwise
///     TRUE.
///   - Upon reaching a loop end, subclass either ignores that, or loops back
///     to the beginning of the loop. In the latter case, if the output mode is set
///     to LOOPING, the subclass must call `gstbadaudio.NonstreamAudioDecoder.handleLoop`
///     *after* the playback position moved to the start of the loop. In
///     STEADY mode, the subclass must *not* call this function.
///     Since many decoders only provide a callback for when the looping occurs,
///     and that looping occurs inside the decoding operation itself, the following
///     mechanism for subclass is suggested: set a flag inside such a callback.
///     Then, in the next `decode` call, before doing the decoding, check this flag.
///     If it is set, `gstbadaudio.NonstreamAudioDecoder.handleLoop` is called, and the
///     flag is cleared.
///     (This function call is necessary in LOOPING mode because it updates the
///     current segment and makes sure the next buffer that is sent downstream
///     has its DISCONT flag set.)
///   - When the current subsong is switched, `set_current_subsong` is called.
///     If it fails, a warning is reported, and nothing else is done. Otherwise,
///     it calls `get_subsong_duration` to get the new current subsongs's
///     duration, `get_subsong_tags` to get its tags, reports a new duration
///     (i.e. it sends a duration event downstream and generates a duration
///     message), updates the current segment, and sends the subsong's tags in
///     an event downstream. (If `set_current_subsong` has been set to NULL by
///     the subclass, attempts to set a current subsong are ignored; likewise,
///     if `get_subsong_duration` is NULL, no duration is reported, and if
///     `get_subsong_tags` is NULL, no tags are sent downstream.)
///   - When an attempt is made to switch the output mode, it is checked against
///     the bitmask returned by `get_supported_output_modes`. If the proposed
///     new output mode is supported, the current segment is updated
///     (it is open-ended in STEADY mode, and covers the (sub)song length in
///     LOOPING mode), and the subclass' `set_output_mode` function is called
///     unless it is set to NULL. Subclasses should reset internal loop counters
///     in this function.
///
/// The relationship between (sub)song duration, output mode, and number of loops
/// is defined this way (this is all done by the base class automatically):
///
/// * Segments have their duration and stop values set to GST_CLOCK_TIME_NONE in
///   STEADY mode, and to the duration of the (sub)song in LOOPING mode.
///
/// * The duration that is returned to a DURATION query is always the duration
///   of the (sub)song, regardless of number of loops or output mode. The same
///   goes for DURATION messages and tags.
///
/// * If the number of loops is >0 or -1, durations of TOC entries are set to
///   the duration of the respective subsong in LOOPING mode and to G_MAXINT64 in
///   STEADY mode. If the number of loops is 0, entry durations are set to the
///   subsong duration regardless of the output mode.
pub const NonstreamAudioDecoder = extern struct {
    pub const Parent = gst.Element;
    pub const Implements = [_]type{};
    pub const Class = gstbadaudio.NonstreamAudioDecoderClass;
    f_element: gst.Element,
    f_sinkpad: ?*gst.Pad,
    f_srcpad: ?*gst.Pad,
    f_upstream_size: i64,
    f_loaded_mode: c_int,
    f_input_data_adapter: ?*gstbase.Adapter,
    f_current_subsong: c_uint,
    f_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode,
    f_subsong_duration: gst.ClockTime,
    f_output_mode: gstbadaudio.NonstreamAudioOutputMode,
    f_num_loops: c_int,
    f_output_format_changed: c_int,
    f_output_audio_info: gstaudio.AudioInfo,
    f_cur_pos_in_samples: u64,
    f_num_decoded_samples: u64,
    f_cur_segment: gst.Segment,
    f_discont: c_int,
    f_toc: ?*gst.Toc,
    f_allocator: ?*gst.Allocator,
    f_allocation_params: gst.AllocationParams,
    f_mutex: glib.Mutex,

    pub const virtual_methods = struct {
        /// Optional.
        ///                              Sets up the allocation parameters for allocating output
        ///                              buffers. The passed in query contains the result of the
        ///                              downstream allocation query.
        ///                              Subclasses should chain up to the parent implementation to
        ///                              invoke the default handler.
        pub const decide_allocation = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_query: *gst.Query) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_decide_allocation.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_query);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_query: *gst.Query) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_decide_allocation = @ptrCast(p_implementation);
            }
        };

        /// Always required.
        ///                              Allocates an output buffer, fills it with decoded audio samples, and must be passed on to
        ///                              *buffer . The number of decoded samples must be passed on to *num_samples.
        ///                              If decoding finishes or the decoding is no longer possible (for example, due to an
        ///                              unrecoverable error), this function returns FALSE, otherwise TRUE.
        pub const decode = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_buffer: **gst.Buffer, p_num_samples: *c_uint) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_decode.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_buffer, p_num_samples);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_buffer: **gst.Buffer, p_num_samples: *c_uint) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_decode = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns the current subsong.
        ///                              If the current subsong mode is not GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, this
        ///                              function's return value is undefined.
        ///                              If this function is implemented by the subclass,
        ///                              `get_num_subsongs` should be implemented as well.
        pub const get_current_subsong = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) c_uint {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_current_subsong.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) c_uint) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_current_subsong = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns a tag list containing the main song tags, or NULL if there are
        ///                              no such tags. Returned tags will be unref'd. Use this vfunc instead of
        ///                              manually pushing a tag event downstream to avoid edge cases where not yet
        ///                              pushed sticky tag events get overwritten before they are pushed (can for
        ///                              example happen with decodebin if tags are pushed downstream before the
        ///                              decodebin pads are linked).
        pub const get_main_tags = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) *gst.TagList {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_main_tags.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) *gst.TagList) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_main_tags = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns the number of loops for playback.
        pub const get_num_loops = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_num_loops.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_num_loops = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns the number of subsongs available.
        ///                              The return values 0 and 1 have a similar, but distinct, meaning.
        ///                              If this function returns 0, then this decoder does not support subsongs at all.
        ///                              `get_current_subsong` must then also always return 0. In other words, this function
        ///                              either never returns 0, or never returns anything else than 0.
        ///                              A return value of 1 means that the media contains either only one or no subsongs
        ///                              (the entire song is then considered to be one single subsong). 1 also means that only
        ///                              this very media has no or just one subsong, and the decoder itself can
        ///                              support multiple subsongs.
        pub const get_num_subsongs = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) c_uint {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_num_subsongs.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) c_uint) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_num_subsongs = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns the duration of a subsong. Returns GST_CLOCK_TIME_NONE if duration is unknown.
        pub const get_subsong_duration = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint) gst.ClockTime {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_subsong_duration.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_subsong);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint) callconv(.c) gst.ClockTime) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_subsong_duration = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Returns tags for a subsong, or NULL if there are no tags.
        ///                              Returned tags will be unref'd.
        pub const get_subsong_tags = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint) *gst.TagList {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_subsong_tags.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_subsong);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint) callconv(.c) *gst.TagList) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_subsong_tags = @ptrCast(p_implementation);
            }
        };

        /// Always required.
        ///                              Returns a bitmask containing the output modes the subclass supports.
        ///                              The mask is formed by a bitwise OR combination of integers, which can be calculated
        ///                              this way:  1 << GST_NONSTREAM_AUDIO_OUTPUT_MODE_<mode> , where mode is either STEADY or LOOPING
        pub const get_supported_output_modes = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) c_uint {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_supported_output_modes.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) c_uint) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_get_supported_output_modes = @ptrCast(p_implementation);
            }
        };

        /// Required if loads_from_sinkpad is set to TRUE (the default value).
        ///                              Loads the media from the given buffer. The entire media is supplied at once,
        ///                              so after this call, loading should be finished. This function
        ///                              can also make use of a suggested initial subsong & subsong mode and initial
        ///                              playback position (but isn't required to). In case it chooses a different starting
        ///                              position, the function must pass this position to *initial_position.
        ///                              The subclass does not have to unref the input buffer; the base class does that
        ///                              already.
        pub const load_from_buffer = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_source_data: *gst.Buffer, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_load_from_buffer.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_source_data, p_initial_subsong, p_initial_subsong_mode, p_initial_position, p_initial_output_mode, p_initial_num_loops);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_source_data: *gst.Buffer, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_load_from_buffer = @ptrCast(p_implementation);
            }
        };

        /// Required if loads_from_sinkpad is set to FALSE.
        ///                              Loads the media in a way defined by the custom sink. Data is not supplied;
        ///                              the derived class has to handle this on its own. Otherwise, this function is
        ///                              identical to `load_from_buffer`.
        pub const load_from_custom = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_load_from_custom.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_initial_subsong, p_initial_subsong_mode, p_initial_position, p_initial_output_mode, p_initial_num_loops);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_load_from_custom = @ptrCast(p_implementation);
            }
        };

        pub const negotiate = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_negotiate.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_negotiate = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Proposes buffer allocation parameters for upstream elements.
        ///                              Subclasses should chain up to the parent implementation to
        ///                              invoke the default handler.
        pub const propose_allocation = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_query: *gst.Query) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_propose_allocation.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_query);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_query: *gst.Query) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_propose_allocation = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Called when a seek event is received by the parent class.
        ///                              new_position is a pointer to a GstClockTime integer which
        ///                              contains a position relative to the current subsong.
        ///                              Minimum is 0, maximum is the subsong length.
        ///                              After this function finishes, new_position is set to the
        ///                              actual new position (which may differ from the request
        ///                              position, depending on the decoder).
        pub const seek = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_new_position: *gst.ClockTime) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_seek.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_new_position);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_new_position: *gst.ClockTime) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_seek = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Sets the current subsong. This function is allowed to switch to a different
        ///                              subsong than the required one, and can optionally make use of the suggested initial
        ///                              position. In case it chooses a different starting position, the function must pass
        ///                              this position to *initial_position.
        ///                              This function switches the subsong mode to GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE
        ///                              automatically.
        ///                              If this function is implemented by the subclass, `get_current_subsong` and
        ///                              `get_num_subsongs` should be implemented as well.
        pub const set_current_subsong = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint, p_initial_position: *gst.ClockTime) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_current_subsong.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_subsong, p_initial_position);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_subsong: c_uint, p_initial_position: *gst.ClockTime) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_current_subsong = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Sets the number of loops for playback. If this is called during playback,
        ///                              the subclass must set any internal loop counters to zero. A loop value of -1
        ///                              means infinite looping; 0 means no looping; and when the num_loops is greater than 0,
        ///                              playback should loop exactly num_loops times. If this function is implemented,
        ///                              `get_num_loops` should be implemented as well. The function can ignore the given values
        ///                              and choose another; however, `get_num_loops` should return this other value afterwards.
        ///                              It is up to the subclass to define where the loop starts and ends. It can mean that only
        ///                              a subset at the end or in the middle of a song is repeated, for example.
        ///                              If the current subsong mode is GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, then the subsong
        ///                              is repeated this many times. If it is GST_NONSTREAM_AUDIO_SUBSONG_MODE_ALL, then all
        ///                              subsongs are repeated this many times. With GST_NONSTREAM_AUDIO_SUBSONG_MODE_DECODER_DEFAULT,
        ///                              the behavior is decoder specific.
        pub const set_num_loops = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_num_loops: c_int) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_num_loops.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_num_loops);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_num_loops: c_int) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_num_loops = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Sets the output mode the subclass has to use. Unlike with most other functions, the subclass
        ///                              cannot choose a different mode; it must use the requested one.
        ///                              If the output mode is set to LOOPING, `gst_nonstream_audio_decoder_handle_loop`
        ///                              must be called after playback moved back to the start of a loop.
        pub const set_output_mode = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mode: gstbadaudio.NonstreamAudioOutputMode, p_current_position: *gst.ClockTime) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_output_mode.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_mode, p_current_position);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mode: gstbadaudio.NonstreamAudioOutputMode, p_current_position: *gst.ClockTime) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_output_mode = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Sets the current subsong mode. Since this might influence the current playback position,
        ///                              this function must set the initial_position integer argument to a defined value.
        ///                              If the playback position is not affected at all, it must be set to GST_CLOCK_TIME_NONE.
        ///                              If the subsong is restarted after the mode switch, it is recommended to set the value
        ///                              to the position in the playback right after the switch (or 0 if the subsongs are always
        ///                              reset back to the beginning).
        pub const set_subsong_mode = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime) c_int {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_subsong_mode.?(gobject.ext.as(NonstreamAudioDecoder, p_dec), p_mode, p_initial_position);
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance, p_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime) callconv(.c) c_int) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_set_subsong_mode = @ptrCast(p_implementation);
            }
        };

        /// Optional.
        ///                              Called when a position query is received by the parent class.
        ///                              The position that this function returns must be relative to
        ///                              the current subsong. Thus, the minimum is 0, and the maximum
        ///                              is the subsong length.
        pub const tell = struct {
            pub fn call(p_class: anytype, p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) gst.ClockTime {
                return gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_tell.?(gobject.ext.as(NonstreamAudioDecoder, p_dec));
            }

            pub fn implement(p_class: anytype, p_implementation: *const fn (p_dec: *@typeInfo(@TypeOf(p_class)).pointer.child.Instance) callconv(.c) gst.ClockTime) void {
                gobject.ext.as(NonstreamAudioDecoder.Class, p_class).f_tell = @ptrCast(p_implementation);
            }
        };
    };

    pub const properties = struct {
        pub const current_subsong = struct {
            pub const name = "current-subsong";

            pub const Type = c_uint;
        };

        pub const num_loops = struct {
            pub const name = "num-loops";

            pub const Type = c_int;
        };

        pub const output_mode = struct {
            pub const name = "output-mode";

            pub const Type = @compileError("no type information available");
        };

        pub const subsong_mode = struct {
            pub const name = "subsong-mode";

            pub const Type = @compileError("no type information available");
        };
    };

    pub const signals = struct {};

    /// Allocates an output buffer with the internally configured buffer pool.
    ///
    /// This function may only be called from within `load_from_buffer`,
    /// `load_from_custom`, and `decode`.
    extern fn gst_nonstream_audio_decoder_allocate_output_buffer(p_dec: *NonstreamAudioDecoder, p_size: usize) ?*gst.Buffer;
    pub const allocateOutputBuffer = gst_nonstream_audio_decoder_allocate_output_buffer;

    /// Gets sample format, sample rate, channel count from the allowed srcpad caps.
    ///
    /// This is useful for when the subclass wishes to adjust one or more output
    /// parameters to whatever downstream is supporting. For example, the output
    /// sample rate is often a freely adjustable value in module players.
    ///
    /// This function tries to find a value inside the srcpad peer's caps for
    /// `format`, `sample_rate`, `num_chnanels` . Any of these can be NULL; they
    /// (and the corresponding downstream caps) are then skipped while retrieving
    /// information. Non-fixated caps are fixated first; the value closest to
    /// their present value is then chosen. For example, if the variables pointed
    /// to by the arguments are GST_AUDIO_FORMAT_16, 48000 Hz, and 2 channels,
    /// and the downstream caps are:
    ///
    /// "audio/x-raw, format={S16LE,S32LE}, rate=[1,32000], channels=[1,MAX]"
    ///
    /// Then `format` and `channels` stay the same, while `sample_rate` is set to 32000 Hz.
    /// This way, the initial values the the variables pointed to by the arguments
    /// are set to can be used as default output values. Note that if no downstream
    /// caps can be retrieved, then this function does nothing, therefore it is
    /// necessary to ensure that `format`, `sample_rate`, and `channels` have valid
    /// initial values.
    ///
    /// Decoder lock is not held by this function, so it can be called from within
    /// any of the class vfuncs.
    extern fn gst_nonstream_audio_decoder_get_downstream_info(p_dec: *NonstreamAudioDecoder, p_format: *gstaudio.AudioFormat, p_sample_rate: *c_int, p_num_channels: *c_int) void;
    pub const getDownstreamInfo = gst_nonstream_audio_decoder_get_downstream_info;

    /// Reports that a loop has been completed and creates a new appropriate
    /// segment for the next loop.
    ///
    /// `new_position` exists because a loop may not start at the beginning.
    ///
    /// This function is only useful for subclasses which can be in the
    /// GST_NONSTREAM_AUDIO_OUTPUT_MODE_LOOPING output mode, since in the
    /// GST_NONSTREAM_AUDIO_OUTPUT_MODE_STEADY output mode, this function
    /// does nothing. See `gstbadaudio.NonstreamAudioOutputMode` for more details.
    ///
    /// The subclass calls this during playback when it loops. It produces
    /// a new segment with updated base time and internal time values, to allow
    /// for seamless looping. It does *not* check the number of elapsed loops;
    /// this is up the subclass.
    ///
    /// Note that if this function is called, then it must be done after the
    /// last samples of the loop have been decoded and pushed downstream.
    ///
    /// This function must be called with the decoder mutex lock held, since it
    /// is typically called from within `decode` (which in turn are called with
    /// the lock already held).
    extern fn gst_nonstream_audio_decoder_handle_loop(p_dec: *NonstreamAudioDecoder, p_new_position: gst.ClockTime) void;
    pub const handleLoop = gst_nonstream_audio_decoder_handle_loop;

    /// Sets the output caps by means of a GstAudioInfo structure.
    ///
    /// This must be called latest in the first `decode` call, to ensure src caps are
    /// set before decoded samples are sent downstream. Typically, this is called
    /// from inside `load_from_buffer` or `load_from_custom`.
    ///
    /// This function must be called with the decoder mutex lock held, since it
    /// is typically called from within the aforementioned vfuncs (which in turn
    /// are called with the lock already held).
    extern fn gst_nonstream_audio_decoder_set_output_format(p_dec: *NonstreamAudioDecoder, p_audio_info: *const gstaudio.AudioInfo) c_int;
    pub const setOutputFormat = gst_nonstream_audio_decoder_set_output_format;

    /// Convenience function; sets the output caps by means of common parameters.
    ///
    /// Internally, this fills a GstAudioInfo structure and calls
    /// `gstbadaudio.NonstreamAudioDecoder.setOutputFormat`.
    extern fn gst_nonstream_audio_decoder_set_output_format_simple(p_dec: *NonstreamAudioDecoder, p_sample_rate: c_uint, p_sample_format: gstaudio.AudioFormat, p_num_channels: c_uint) c_int;
    pub const setOutputFormatSimple = gst_nonstream_audio_decoder_set_output_format_simple;

    extern fn gst_nonstream_audio_decoder_get_type() usize;
    pub const getGObjectType = gst_nonstream_audio_decoder_get_type;

    extern fn g_object_ref(p_self: *gstbadaudio.NonstreamAudioDecoder) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstbadaudio.NonstreamAudioDecoder) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *NonstreamAudioDecoder, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// This class is similar to GstAdapter, but it is made to work with
/// non-interleaved (planar) audio buffers. Before using, an audio format
/// must be configured with `gstbadaudio.PlanarAudioAdapter.configure`
pub const PlanarAudioAdapter = opaque {
    pub const Parent = gobject.Object;
    pub const Implements = [_]type{};
    pub const Class = gstbadaudio.PlanarAudioAdapterClass;
    pub const virtual_methods = struct {};

    pub const properties = struct {};

    pub const signals = struct {};

    /// Creates a new `gstbadaudio.PlanarAudioAdapter`. Free with `gobject.Object.unref`.
    extern fn gst_planar_audio_adapter_new() *gstbadaudio.PlanarAudioAdapter;
    pub const new = gst_planar_audio_adapter_new;

    /// Gets the maximum amount of samples available, that is it returns the maximum
    /// value that can be supplied to `gstbadaudio.PlanarAudioAdapter.getBuffer` without
    /// that function returning `NULL`.
    extern fn gst_planar_audio_adapter_available(p_adapter: *PlanarAudioAdapter) usize;
    pub const available = gst_planar_audio_adapter_available;

    /// Removes all buffers from `adapter`.
    extern fn gst_planar_audio_adapter_clear(p_adapter: *PlanarAudioAdapter) void;
    pub const clear = gst_planar_audio_adapter_clear;

    /// Sets up the `adapter` to handle audio data of the specified audio format.
    /// Note that this will internally clear the adapter and re-initialize it.
    extern fn gst_planar_audio_adapter_configure(p_adapter: *PlanarAudioAdapter, p_info: *const gstaudio.AudioInfo) void;
    pub const configure = gst_planar_audio_adapter_configure;

    extern fn gst_planar_audio_adapter_distance_from_discont(p_adapter: *PlanarAudioAdapter) u64;
    pub const distanceFromDiscont = gst_planar_audio_adapter_distance_from_discont;

    /// Get the DTS that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
    /// flag, or GST_CLOCK_TIME_NONE.
    extern fn gst_planar_audio_adapter_dts_at_discont(p_adapter: *PlanarAudioAdapter) gst.ClockTime;
    pub const dtsAtDiscont = gst_planar_audio_adapter_dts_at_discont;

    /// Flushes the first `to_flush` samples in the `adapter`. The caller must ensure
    /// that at least this many samples are available.
    extern fn gst_planar_audio_adapter_flush(p_adapter: *PlanarAudioAdapter, p_to_flush: usize) void;
    pub const flush = gst_planar_audio_adapter_flush;

    /// Returns a `gst.Buffer` containing the first `nsamples` of the `adapter`, but
    /// does not flush them from the adapter.
    /// Use `gstbadaudio.PlanarAudioAdapter.takeBuffer` for flushing at the same time.
    ///
    /// The map `flags` can be used to give an optimization hint to this function.
    /// When the requested buffer is meant to be mapped only for reading, it might
    /// be possible to avoid copying memory in some cases.
    ///
    /// Caller owns a reference to the returned buffer. `gst.Buffer.unref` after
    /// usage.
    ///
    /// Free-function: gst_buffer_unref
    extern fn gst_planar_audio_adapter_get_buffer(p_adapter: *PlanarAudioAdapter, p_nsamples: usize, p_flags: gst.MapFlags) ?*gst.Buffer;
    pub const getBuffer = gst_planar_audio_adapter_get_buffer;

    /// Get the offset that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
    /// flag, or GST_BUFFER_OFFSET_NONE.
    extern fn gst_planar_audio_adapter_offset_at_discont(p_adapter: *PlanarAudioAdapter) u64;
    pub const offsetAtDiscont = gst_planar_audio_adapter_offset_at_discont;

    /// Get the dts that was before the current sample in the adapter. When
    /// `distance` is given, the amount of bytes between the dts and the current
    /// position is returned.
    ///
    /// The dts is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
    /// the adapter is first created or when it is cleared. This also means that
    /// before the first sample with a dts is removed from the adapter, the dts
    /// and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
    extern fn gst_planar_audio_adapter_prev_dts(p_adapter: *PlanarAudioAdapter, p_distance: ?*u64) gst.ClockTime;
    pub const prevDts = gst_planar_audio_adapter_prev_dts;

    /// Get the offset that was before the current sample in the adapter. When
    /// `distance` is given, the amount of samples between the offset and the current
    /// position is returned.
    ///
    /// The offset is reset to GST_BUFFER_OFFSET_NONE and the distance is set to 0
    /// when the adapter is first created or when it is cleared. This also means that
    /// before the first sample with an offset is removed from the adapter, the
    /// offset and distance returned are GST_BUFFER_OFFSET_NONE and 0 respectively.
    extern fn gst_planar_audio_adapter_prev_offset(p_adapter: *PlanarAudioAdapter, p_distance: ?*u64) u64;
    pub const prevOffset = gst_planar_audio_adapter_prev_offset;

    /// Get the pts that was before the current sample in the adapter. When
    /// `distance` is given, the amount of samples between the pts and the current
    /// position is returned.
    ///
    /// The pts is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
    /// the adapter is first created or when it is cleared. This also means that before
    /// the first sample with a pts is removed from the adapter, the pts
    /// and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
    extern fn gst_planar_audio_adapter_prev_pts(p_adapter: *PlanarAudioAdapter, p_distance: ?*u64) gst.ClockTime;
    pub const prevPts = gst_planar_audio_adapter_prev_pts;

    /// Get the PTS that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
    /// flag, or GST_CLOCK_TIME_NONE.
    extern fn gst_planar_audio_adapter_pts_at_discont(p_adapter: *PlanarAudioAdapter) gst.ClockTime;
    pub const ptsAtDiscont = gst_planar_audio_adapter_pts_at_discont;

    /// Adds the data from `buf` to the data stored inside `adapter` and takes
    /// ownership of the buffer.
    extern fn gst_planar_audio_adapter_push(p_adapter: *PlanarAudioAdapter, p_buf: *gst.Buffer) void;
    pub const push = gst_planar_audio_adapter_push;

    /// Returns a `gst.Buffer` containing the first `nsamples` bytes of the
    /// `adapter`. The returned bytes will be flushed from the adapter.
    ///
    /// See `gstbadaudio.PlanarAudioAdapter.getBuffer` for more details.
    ///
    /// Caller owns a reference to the returned buffer. `gst.Buffer.unref` after
    /// usage.
    ///
    /// Free-function: gst_buffer_unref
    extern fn gst_planar_audio_adapter_take_buffer(p_adapter: *PlanarAudioAdapter, p_nsamples: usize, p_flags: gst.MapFlags) ?*gst.Buffer;
    pub const takeBuffer = gst_planar_audio_adapter_take_buffer;

    extern fn gst_planar_audio_adapter_get_type() usize;
    pub const getGObjectType = gst_planar_audio_adapter_get_type;

    extern fn g_object_ref(p_self: *gstbadaudio.PlanarAudioAdapter) void;
    pub const ref = g_object_ref;

    extern fn g_object_unref(p_self: *gstbadaudio.PlanarAudioAdapter) void;
    pub const unref = g_object_unref;

    pub fn as(p_instance: *PlanarAudioAdapter, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// Subclasses can override any of the available optional virtual methods or not, as
/// needed. At minimum, `load_from_buffer` (or `load_from_custom`), `get_supported_output_modes`,
/// and `decode` need to be overridden.
///
/// All functions are called with a locked decoder mutex.
///
/// > If GST_ELEMENT_ERROR, GST_ELEMENT_WARNING, or GST_ELEMENT_INFO are called from
/// > inside one of these functions, it is strongly recommended to unlock the decoder mutex
/// > before and re-lock it after these macros to prevent potential deadlocks in case the
/// > application does something with the element when it receives an ERROR/WARNING/INFO
/// > message. Same goes for `gst.Element.postMessage` calls and non-serialized events.
///
/// By default, this class works by reading media data from the sinkpad, and then commencing
/// playback. Some decoders cannot be given data from a memory block, so the usual way of
/// reading all upstream data and passing it to `load_from_buffer` doesn't work then. In this case,
/// set the value of loads_from_sinkpad to FALSE. This changes the way this class operates;
/// it does not require a sinkpad to exist anymore, and will call `load_from_custom` instead.
/// One example of a decoder where this makes sense is UADE (Unix Amiga Delitracker Emulator).
/// For some formats (such as TFMX), it needs to do the file loading by itself.
/// Since most decoders can read input data from a memory block, the default value of
/// loads_from_sinkpad is TRUE.
pub const NonstreamAudioDecoderClass = extern struct {
    pub const Instance = gstbadaudio.NonstreamAudioDecoder;

    /// The parent class structure
    f_element_class: gst.ElementClass,
    f_loads_from_sinkpad: c_int,
    /// Optional.
    ///                              Called when a seek event is received by the parent class.
    ///                              new_position is a pointer to a GstClockTime integer which
    ///                              contains a position relative to the current subsong.
    ///                              Minimum is 0, maximum is the subsong length.
    ///                              After this function finishes, new_position is set to the
    ///                              actual new position (which may differ from the request
    ///                              position, depending on the decoder).
    f_seek: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_new_position: *gst.ClockTime) callconv(.c) c_int,
    /// Optional.
    ///                              Called when a position query is received by the parent class.
    ///                              The position that this function returns must be relative to
    ///                              the current subsong. Thus, the minimum is 0, and the maximum
    ///                              is the subsong length.
    f_tell: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) gst.ClockTime,
    /// Required if loads_from_sinkpad is set to TRUE (the default value).
    ///                              Loads the media from the given buffer. The entire media is supplied at once,
    ///                              so after this call, loading should be finished. This function
    ///                              can also make use of a suggested initial subsong & subsong mode and initial
    ///                              playback position (but isn't required to). In case it chooses a different starting
    ///                              position, the function must pass this position to *initial_position.
    ///                              The subclass does not have to unref the input buffer; the base class does that
    ///                              already.
    f_load_from_buffer: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_source_data: *gst.Buffer, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) callconv(.c) c_int,
    /// Required if loads_from_sinkpad is set to FALSE.
    ///                              Loads the media in a way defined by the custom sink. Data is not supplied;
    ///                              the derived class has to handle this on its own. Otherwise, this function is
    ///                              identical to `load_from_buffer`.
    f_load_from_custom: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_initial_subsong: c_uint, p_initial_subsong_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime, p_initial_output_mode: *gstbadaudio.NonstreamAudioOutputMode, p_initial_num_loops: *c_int) callconv(.c) c_int,
    /// Optional.
    ///                              Returns a tag list containing the main song tags, or NULL if there are
    ///                              no such tags. Returned tags will be unref'd. Use this vfunc instead of
    ///                              manually pushing a tag event downstream to avoid edge cases where not yet
    ///                              pushed sticky tag events get overwritten before they are pushed (can for
    ///                              example happen with decodebin if tags are pushed downstream before the
    ///                              decodebin pads are linked).
    f_get_main_tags: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) *gst.TagList,
    /// Optional.
    ///                              Sets the current subsong. This function is allowed to switch to a different
    ///                              subsong than the required one, and can optionally make use of the suggested initial
    ///                              position. In case it chooses a different starting position, the function must pass
    ///                              this position to *initial_position.
    ///                              This function switches the subsong mode to GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE
    ///                              automatically.
    ///                              If this function is implemented by the subclass, `get_current_subsong` and
    ///                              `get_num_subsongs` should be implemented as well.
    f_set_current_subsong: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_subsong: c_uint, p_initial_position: *gst.ClockTime) callconv(.c) c_int,
    /// Optional.
    ///                              Returns the current subsong.
    ///                              If the current subsong mode is not GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, this
    ///                              function's return value is undefined.
    ///                              If this function is implemented by the subclass,
    ///                              `get_num_subsongs` should be implemented as well.
    f_get_current_subsong: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) c_uint,
    /// Optional.
    ///                              Returns the number of subsongs available.
    ///                              The return values 0 and 1 have a similar, but distinct, meaning.
    ///                              If this function returns 0, then this decoder does not support subsongs at all.
    ///                              `get_current_subsong` must then also always return 0. In other words, this function
    ///                              either never returns 0, or never returns anything else than 0.
    ///                              A return value of 1 means that the media contains either only one or no subsongs
    ///                              (the entire song is then considered to be one single subsong). 1 also means that only
    ///                              this very media has no or just one subsong, and the decoder itself can
    ///                              support multiple subsongs.
    f_get_num_subsongs: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) c_uint,
    /// Optional.
    ///                              Returns the duration of a subsong. Returns GST_CLOCK_TIME_NONE if duration is unknown.
    f_get_subsong_duration: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_subsong: c_uint) callconv(.c) gst.ClockTime,
    /// Optional.
    ///                              Returns tags for a subsong, or NULL if there are no tags.
    ///                              Returned tags will be unref'd.
    f_get_subsong_tags: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_subsong: c_uint) callconv(.c) *gst.TagList,
    /// Optional.
    ///                              Sets the current subsong mode. Since this might influence the current playback position,
    ///                              this function must set the initial_position integer argument to a defined value.
    ///                              If the playback position is not affected at all, it must be set to GST_CLOCK_TIME_NONE.
    ///                              If the subsong is restarted after the mode switch, it is recommended to set the value
    ///                              to the position in the playback right after the switch (or 0 if the subsongs are always
    ///                              reset back to the beginning).
    f_set_subsong_mode: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_mode: gstbadaudio.NonstreamAudioSubsongMode, p_initial_position: *gst.ClockTime) callconv(.c) c_int,
    /// Optional.
    ///                              Sets the number of loops for playback. If this is called during playback,
    ///                              the subclass must set any internal loop counters to zero. A loop value of -1
    ///                              means infinite looping; 0 means no looping; and when the num_loops is greater than 0,
    ///                              playback should loop exactly num_loops times. If this function is implemented,
    ///                              `get_num_loops` should be implemented as well. The function can ignore the given values
    ///                              and choose another; however, `get_num_loops` should return this other value afterwards.
    ///                              It is up to the subclass to define where the loop starts and ends. It can mean that only
    ///                              a subset at the end or in the middle of a song is repeated, for example.
    ///                              If the current subsong mode is GST_NONSTREAM_AUDIO_SUBSONG_MODE_SINGLE, then the subsong
    ///                              is repeated this many times. If it is GST_NONSTREAM_AUDIO_SUBSONG_MODE_ALL, then all
    ///                              subsongs are repeated this many times. With GST_NONSTREAM_AUDIO_SUBSONG_MODE_DECODER_DEFAULT,
    ///                              the behavior is decoder specific.
    f_set_num_loops: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_num_loops: c_int) callconv(.c) c_int,
    /// Optional.
    ///                              Returns the number of loops for playback.
    f_get_num_loops: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) c_int,
    /// Always required.
    ///                              Returns a bitmask containing the output modes the subclass supports.
    ///                              The mask is formed by a bitwise OR combination of integers, which can be calculated
    ///                              this way:  1 << GST_NONSTREAM_AUDIO_OUTPUT_MODE_<mode> , where mode is either STEADY or LOOPING
    f_get_supported_output_modes: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) c_uint,
    /// Optional.
    ///                              Sets the output mode the subclass has to use. Unlike with most other functions, the subclass
    ///                              cannot choose a different mode; it must use the requested one.
    ///                              If the output mode is set to LOOPING, `gst_nonstream_audio_decoder_handle_loop`
    ///                              must be called after playback moved back to the start of a loop.
    f_set_output_mode: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_mode: gstbadaudio.NonstreamAudioOutputMode, p_current_position: *gst.ClockTime) callconv(.c) c_int,
    /// Always required.
    ///                              Allocates an output buffer, fills it with decoded audio samples, and must be passed on to
    ///                              *buffer . The number of decoded samples must be passed on to *num_samples.
    ///                              If decoding finishes or the decoding is no longer possible (for example, due to an
    ///                              unrecoverable error), this function returns FALSE, otherwise TRUE.
    f_decode: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_buffer: **gst.Buffer, p_num_samples: *c_uint) callconv(.c) c_int,
    f_negotiate: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder) callconv(.c) c_int,
    /// Optional.
    ///                              Sets up the allocation parameters for allocating output
    ///                              buffers. The passed in query contains the result of the
    ///                              downstream allocation query.
    ///                              Subclasses should chain up to the parent implementation to
    ///                              invoke the default handler.
    f_decide_allocation: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_query: *gst.Query) callconv(.c) c_int,
    /// Optional.
    ///                              Proposes buffer allocation parameters for upstream elements.
    ///                              Subclasses should chain up to the parent implementation to
    ///                              invoke the default handler.
    f_propose_allocation: ?*const fn (p_dec: *gstbadaudio.NonstreamAudioDecoder, p_query: *gst.Query) callconv(.c) c_int,
    f__gst_reserved: [20]*anyopaque,

    pub fn as(p_instance: *NonstreamAudioDecoderClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

pub const PlanarAudioAdapterClass = opaque {
    pub const Instance = gstbadaudio.PlanarAudioAdapter;

    pub fn as(p_instance: *PlanarAudioAdapterClass, comptime P_T: type) *P_T {
        return gobject.ext.as(P_T, p_instance);
    }

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// The output mode defines how the output behaves with regards to looping. Either the playback position is
/// moved back to the beginning of the loop, acting like a backwards seek, or it increases steadily, as if
/// loop were "unrolled".
pub const NonstreamAudioOutputMode = enum(c_int) {
    looping = 0,
    steady = 1,
    _,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// The subsong mode defines how the decoder shall handle subsongs.
pub const NonstreamAudioSubsongMode = enum(c_int) {
    single = 0,
    all = 1,
    decoder_default = 2,
    _,

    test {
        @setEvalBranchQuota(100_000);
        std.testing.refAllDecls(@This());
    }
};

/// The name of the template for the sink pad.
pub const NONSTREAM_AUDIO_DECODER_SINK_NAME = "sink";
/// The name of the template for the source pad.
pub const NONSTREAM_AUDIO_DECODER_SRC_NAME = "src";

test {
    @setEvalBranchQuota(100_000);
    std.testing.refAllDecls(@This());
    std.testing.refAllDecls(ext);
}
