#ifndef FFMPEG_AUDIO_H
#define FFMPEG_AUDIO_H

#include <stdint.h>

#ifdef _WIN32
#ifdef LIB_COMPILE
#define FFMPEG_EXTERN __declspec(dllexport)
#else
#define FFMPEG_EXTERN __declspec(dllimport)
#endif
#else
#define FFMPEG_EXTERN
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Audio-only FFmpeg wrapper.
 *
 * The implementation is C++, but the exported API is plain C. The caller never
 * sees FFmpeg objects, stream indices, packets, decoders, or C++ objects.
 *
 * Output audio format is fixed:
 *
 *   signed 32-bit integer PCM
 *   interleaved / packed
 *   native endian
 *
 * A sample frame means one sample moment across all channels. For stereo S32,
 * one sample frame is two int32_t values, therefore 8 bytes.
 */

typedef struct __fmpg_instance__ fmpg_instance;

/* ------------------------------------------------------------------------- */
/* Lifecycle                                                                 */
/* ------------------------------------------------------------------------- */

FFMPEG_EXTERN fmpg_instance *fmpg_init(void);
FFMPEG_EXTERN void fmpg_free(fmpg_instance *instance);

/*
 * Open a media file, select the best audio stream, and create the internal
 * decoder/resampler for that stream.
 *
 * After success, metadata, duration, sample rate and channel count are
 * available through the getters below.
 *
 * Return: 1 on success, 0 on failure.
 */
FFMPEG_EXTERN int fmpg_open_file(fmpg_instance *instance, const char *filename);

FFMPEG_EXTERN void fmpg_close(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_is_open(fmpg_instance *instance);

/* ------------------------------------------------------------------------- */
/* Audio information                                                         */
/* ------------------------------------------------------------------------- */

FFMPEG_EXTERN int fmpg_audio_stream_count(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_audio_sample_rate(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_audio_channels(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_audio_bits_per_sample(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_audio_bytes_per_sample(fmpg_instance *instance);

/* Duration in milliseconds, or -1 if unknown. */
FFMPEG_EXTERN int64_t fmpg_duration_ms(fmpg_instance *instance);

/* Duration in output sample frames, or -1 if unknown. */
FFMPEG_EXTERN int64_t fmpg_duration_samples(fmpg_instance *instance);

/* ------------------------------------------------------------------------- */
/* Metadata                                                                  */
/* ------------------------------------------------------------------------- */

FFMPEG_EXTERN const char *fmpg_file_title(fmpg_instance *instance);
FFMPEG_EXTERN const char *fmpg_file_author(fmpg_instance *instance);
FFMPEG_EXTERN const char *fmpg_file_album(fmpg_instance *instance);
FFMPEG_EXTERN const char *fmpg_file_genre(fmpg_instance *instance);
FFMPEG_EXTERN const char *fmpg_file_comment(fmpg_instance *instance);
FFMPEG_EXTERN const char *fmpg_file_copyright(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_file_year(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_file_track(fmpg_instance *instance);
FFMPEG_EXTERN int fmpg_file_bitrate(fmpg_instance *instance);

/* ------------------------------------------------------------------------- */
/* Decoding                                                                  */
/* ------------------------------------------------------------------------- */

/*
 * Decode the next block of audio.
 *
 * Internally this reads compressed packets from the selected audio stream,
 * feeds them to the FFmpeg decoder, receives all available decoded frames,
 * converts them to signed 32-bit interleaved PCM, and concatenates them in the
 * instance output buffer.
 *
 * Non-selected streams are skipped internally. The caller does not handle
 * stream_index, packets, or decoder objects.
 *
 * Return:
 *   1 if PCM data is available through fmpg_buffer()/fmpg_buffer_size()
 *   0 at EOF or on error
 */
FFMPEG_EXTERN int fmpg_decode_next(fmpg_instance *instance);

/*
 * Seek to an absolute position in milliseconds.
 *
 * FFmpeg may seek to a packet before the requested timestamp. This wrapper
 * decodes and discards pre-roll samples until the requested output sample is
 * reached, when timestamps are available. That makes the exposed sample
 * position match the music position as closely as FFmpeg's timestamps allow.
 *
 * Return: 1 on success, 0 on failure.
 */
FFMPEG_EXTERN int fmpg_seek_ms(fmpg_instance *instance, int64_t target_pos_ms);

/* ------------------------------------------------------------------------- */
/* Output buffer and sample positions                                        */
/* ------------------------------------------------------------------------- */

/* Pointer to the current decoded PCM buffer. Valid until next API call that
 * decodes, seeks, closes, or frees the instance. */
FFMPEG_EXTERN const uint8_t *fmpg_buffer(fmpg_instance *instance);

/* Size of the current decoded PCM buffer in bytes. */
FFMPEG_EXTERN int fmpg_buffer_size(fmpg_instance *instance);

/* Number of sample frames in the current decoded PCM buffer. */
FFMPEG_EXTERN int64_t fmpg_buffer_samples(fmpg_instance *instance);

/* Absolute sample-frame index of the first sample frame in the current buffer. */
FFMPEG_EXTERN int64_t fmpg_buffer_start_sample(fmpg_instance *instance);

/* Absolute sample-frame index just after the current buffer. */
FFMPEG_EXTERN int64_t fmpg_buffer_end_sample(fmpg_instance *instance);

/*
 * Current absolute sample position in the music stream.
 *
 * This is the same as fmpg_buffer_end_sample() after a successful
 * fmpg_decode_next(): it points just after the last produced sample frame.
 */
FFMPEG_EXTERN int64_t fmpg_sample_position(fmpg_instance *instance);

/* Approximate start time of the current decoded block in seconds. */
FFMPEG_EXTERN double fmpg_timecode(fmpg_instance *instance);

FFMPEG_EXTERN int fmpg_version();
FFMPEG_EXTERN const char *fmpg_ffmpeg_version();
FFMPEG_EXTERN const char *fmpg_int_version2string(int ver);
FFMPEG_EXTERN int fmpg_compatible_ffmpeg();

#ifdef __cplusplus
}
#endif

#endif
