From a9c12c3e16ef4fae9eab809aa80d565d5d36e288 Mon Sep 17 00:00:00 2001
From: IllusionMan1212
Date: Thu, 8 Aug 2024 12:27:09 +0200
Subject: [PATCH] amidi, aaudio, and mediandk done
---
aaudio/AAudio.odin | 1750 +++++++++++++++++++++++++++++++++
amidi/AMidi.odin | 329 +++++++
android_native_app_glue.odin | 1 -
media/NdkImage.odin | 784 +++++++++++++++
media/NdkImageReader.odin | 443 +++++++++
media/NdkMediaCodec.odin | 560 +++++++++++
media/NdkMediaCrypto.odin | 29 +
media/NdkMediaDataSource.odin | 164 +++
media/NdkMediaDrm.odin | 658 +++++++++++++
media/NdkMediaError.odin | 81 ++
media/NdkMediaExtractor.odin | 213 ++++
media/NdkMediaFormat.odin | 306 ++++++
media/NdkMediaMuxer.odin | 146 +++
sensor.odin | 12 +-
14 files changed, 5473 insertions(+), 3 deletions(-)
create mode 100644 aaudio/AAudio.odin
create mode 100644 amidi/AMidi.odin
create mode 100644 media/NdkImage.odin
create mode 100644 media/NdkImageReader.odin
create mode 100644 media/NdkMediaCodec.odin
create mode 100644 media/NdkMediaCrypto.odin
create mode 100644 media/NdkMediaDataSource.odin
create mode 100644 media/NdkMediaDrm.odin
create mode 100644 media/NdkMediaError.odin
create mode 100644 media/NdkMediaExtractor.odin
create mode 100644 media/NdkMediaFormat.odin
create mode 100644 media/NdkMediaMuxer.odin
diff --git a/aaudio/AAudio.odin b/aaudio/AAudio.odin
new file mode 100644
index 0000000..ede6568
--- /dev/null
+++ b/aaudio/AAudio.odin
@@ -0,0 +1,1750 @@
+//+build android
+package aaudio
+
+foreign import aaudio "system:aaudio"
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use {@link #AAUDIO_UNSPECIFIED} to indicate
+ * that it did not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+AAUDIO_UNSPECIFIED :: 0
+AAUDIO_SYSTEM_USAGE_OFFSET :: 1000
+
+// TODO: doesn't belong here. move to sys/android or something.
+clockid_t :: i32
+
+AAudioDirection :: enum i32 {
+ /**
+ * Audio data will travel out of the device, for example through a speaker.
+ */
+ OUTPUT,
+
+
+ /**
+ * Audio data will travel into the device, for example from a microphone.
+ */
+ INPUT
+}
+
+AAudioFormat :: enum i32 {
+ INVALID = -1,
+ UNSPECIFIED = 0,
+
+ /**
+ * This format uses the int16_t data type.
+ * The maximum range of the data is -32768 (0x8000) to 32767 (0x7FFF).
+ */
+ PCM_I16,
+
+ /**
+ * This format uses the float data type.
+ * The nominal range of the data is [-1.0f, 1.0f).
+ * Values outside that range may be clipped.
+ *
+ * See also the float Data in
+ *
+ * write(float[], int, int, int).
+ */
+ PCM_FLOAT,
+
+ /**
+ * This format uses 24-bit samples packed into 3 bytes.
+ * The bytes are in little-endian order, so the least significant byte
+ * comes first in the byte array.
+ *
+ * The maximum range of the data is -8388608 (0x800000)
+ * to 8388607 (0x7FFFFF).
+ *
+ * Note that the lower precision bits may be ignored by the device.
+ *
+ * Available since API level 31.
+ */
+ PCM_I24_PACKED,
+
+ /**
+ * This format uses 32-bit samples stored in an int32_t data type.
+ * The maximum range of the data is -2147483648 (0x80000000)
+ * to 2147483647 (0x7FFFFFFF).
+ *
+ * Note that the lower precision bits may be ignored by the device.
+ *
+ * Available since API level 31.
+ */
+ PCM_I32
+}
+
+/**
+ * These result codes are returned from AAudio functions to indicate success or failure.
+ * Note that error return codes may change in the future so applications should generally
+ * not rely on specific return codes.
+ */
+AAudioResult :: enum i32 {
+ /**
+ * The call was successful.
+ */
+ OK,
+ ERROR_BASE = -900,
+
+ /**
+ * The audio device was disconnected. This could occur, for example, when headphones
+ * are plugged in or unplugged. The stream cannot be used after the device is disconnected.
+ * Applications should stop and close the stream.
+ * If this error is received in an error callback then another thread should be
+ * used to stop and close the stream.
+ */
+ ERROR_DISCONNECTED,
+
+ /**
+ * An invalid parameter was passed to AAudio.
+ */
+ ERROR_ILLEGAL_ARGUMENT,
+ // reserved
+ ERROR_INTERNAL = ERROR_ILLEGAL_ARGUMENT + 2,
+
+ /**
+ * The requested operation is not appropriate for the current state of AAudio.
+ */
+ ERROR_INVALID_STATE,
+ // reserved
+ // reserved
+ /* The server rejected the handle used to identify the stream.
+ */
+ ERROR_INVALID_HANDLE = ERROR_INVALID_STATE + 3,
+ // reserved
+
+ /**
+ * The function is not implemented for this stream.
+ */
+ ERROR_UNIMPLEMENTED = ERROR_INVALID_HANDLE + 2,
+
+ /**
+ * A resource or information is unavailable.
+ * This could occur when an application tries to open too many streams,
+ * or a timestamp is not available.
+ */
+ ERROR_UNAVAILABLE,
+ ERROR_NO_FREE_HANDLES,
+
+ /**
+ * Memory could not be allocated.
+ */
+ ERROR_NO_MEMORY,
+
+ /**
+ * A NULL pointer was passed to AAudio.
+ * Or a NULL pointer was detected internally.
+ */
+ ERROR_NULL,
+
+ /**
+ * An operation took longer than expected.
+ */
+ ERROR_TIMEOUT,
+ ERROR_WOULD_BLOCK,
+
+ /**
+ * The requested data format is not supported.
+ */
+ ERROR_INVALID_FORMAT,
+
+ /**
+ * A requested was out of range.
+ */
+ ERROR_OUT_OF_RANGE,
+
+ /**
+ * The audio service was not available.
+ */
+ ERROR_NO_SERVICE,
+
+ /**
+ * The requested sample rate was not supported.
+ */
+ ERROR_INVALID_RATE
+}
+
+/**
+ * AAudio Stream states, for details, refer to
+ * Using an Audio Stream
+ */
+AAudioStreamState :: enum i32 {
+ /**
+ * The stream is created but not initialized yet.
+ */
+ UNINITIALIZED = 0,
+ /**
+ * The stream is in an unrecognized state.
+ */
+ UNKNOWN,
+
+ /**
+ * The stream is open and ready to use.
+ */
+ OPEN,
+ /**
+ * The stream is just starting up.
+ */
+ STARTING,
+ /**
+ * The stream has started.
+ */
+ STARTED,
+ /**
+ * The stream is pausing.
+ */
+ PAUSING,
+ /**
+ * The stream has paused, could be restarted or flushed.
+ */
+ PAUSED,
+ /**
+ * The stream is being flushed.
+ */
+ FLUSHING,
+ /**
+ * The stream is flushed, ready to be restarted.
+ */
+ FLUSHED,
+ /**
+ * The stream is stopping.
+ */
+ STOPPING,
+ /**
+ * The stream has been stopped.
+ */
+ STOPPED,
+ /**
+ * The stream is closing.
+ */
+ CLOSING,
+ /**
+ * The stream has been closed.
+ */
+ CLOSED,
+ /**
+ * The stream is disconnected from audio device.
+ */
+ DISCONNECTED
+}
+
+
+AAudioSharingMode :: enum i32 {
+ /**
+ * This will be the only stream using a particular source or sink.
+ * This mode will provide the lowest possible latency.
+ * You should close EXCLUSIVE streams immediately when you are not using them.
+ */
+ EXCLUSIVE,
+ /**
+ * Multiple applications will be mixed by the AAudio Server.
+ * This will have higher latency than the EXCLUSIVE mode.
+ */
+ SHARED
+}
+
+
+AAudioPerformanceMode :: enum i32 {
+ /**
+ * No particular performance needs. Default.
+ */
+ NONE = 10,
+
+ /**
+ * Extending battery life is more important than low latency.
+ *
+ * This mode is not supported in input streams.
+ * For input, mode NONE will be used if this is requested.
+ */
+ POWER_SAVING,
+
+ /**
+ * Reducing latency is more important than battery life.
+ */
+ LOW_LATENCY
+}
+
+/**
+ * The USAGE attribute expresses "why" you are playing a sound, what is this sound used for.
+ * This information is used by certain platforms or routing policies
+ * to make more refined volume or routing decisions.
+ *
+ * Note that these match the equivalent values in
+ * AudioAttributes
+ * in the Android Java API.
+ *
+ * Added in API level 28.
+ */
+AAudioUsage :: enum i32 {
+ /**
+ * Use this for streaming media, music performance, video, podcasts, etcetera.
+ */
+ MEDIA = 1,
+
+ /**
+ * Use this for voice over IP, telephony, etcetera.
+ */
+ VOICE_COMMUNICATION = 2,
+
+ /**
+ * Use this for sounds associated with telephony such as busy tones, DTMF, etcetera.
+ */
+ VOICE_COMMUNICATION_SIGNALLING = 3,
+
+ /**
+ * Use this to demand the users attention.
+ */
+ ALARM = 4,
+
+ /**
+ * Use this for notifying the user when a message has arrived or some
+ * other background event has occured.
+ */
+ NOTIFICATION = 5,
+
+ /**
+ * Use this when the phone rings.
+ */
+ NOTIFICATION_RINGTONE = 6,
+
+ /**
+ * Use this to attract the users attention when, for example, the battery is low.
+ */
+ NOTIFICATION_EVENT = 10,
+
+ /**
+ * Use this for screen readers, etcetera.
+ */
+ ASSISTANCE_ACCESSIBILITY = 11,
+
+ /**
+ * Use this for driving or navigation directions.
+ */
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+
+ /**
+ * Use this for user interface sounds, beeps, etcetera.
+ */
+ ASSISTANCE_SONIFICATION = 13,
+
+ /**
+ * Use this for game audio and sound effects.
+ */
+ GAME = 14,
+
+ /**
+ * Use this for audio responses to user queries, audio instructions or help utterances.
+ */
+ ASSISTANT = 16,
+
+ /**
+ * Use this in case of playing sounds in an emergency.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ EMERGENCY = AAUDIO_SYSTEM_USAGE_OFFSET,
+
+ /**
+ * Use this for safety sounds and alerts, for example backup camera obstacle detection.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ SAFETY = AAUDIO_SYSTEM_USAGE_OFFSET + 1,
+
+ /**
+ * Use this for vehicle status alerts and information, for example the check engine light.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ VEHICLE_STATUS = AAUDIO_SYSTEM_USAGE_OFFSET + 2,
+
+ /**
+ * Use this for traffic announcements, etc.
+ * Privileged MODIFY_AUDIO_ROUTING permission required.
+ */
+ ANNOUNCEMENT = AAUDIO_SYSTEM_USAGE_OFFSET + 3,
+}
+
+/**
+ * The CONTENT_TYPE attribute describes "what" you are playing.
+ * It expresses the general category of the content. This information is optional.
+ * But in case it is known (for instance AAUDIO_CONTENT_TYPE_MOVIE for a
+ * movie streaming service or AAUDIO_CONTENT_TYPE_SPEECH for
+ * an audio book application) this information might be used by the audio framework to
+ * enforce audio focus.
+ *
+ * Note that these match the equivalent values in
+ * AudioAttributes
+ * in the Android Java API.
+ *
+ * Added in API level 28.
+ */
+AAudioContentType :: enum i32 {
+
+ /**
+ * Use this for spoken voice, audio books, etcetera.
+ */
+ SPEECH = 1,
+
+ /**
+ * Use this for pre-recorded or live music.
+ */
+ MUSIC = 2,
+
+ /**
+ * Use this for a movie or video soundtrack.
+ */
+ MOVIE = 3,
+
+ /**
+ * Use this for sound is designed to accompany a user action,
+ * such as a click or beep sound made when the user presses a button.
+ */
+ SONIFICATION = 4
+}
+
+AAudioSpatializationBehavior :: enum i32 {
+
+ /**
+ * Constant indicating the audio content associated with these attributes will follow the
+ * default platform behavior with regards to which content will be spatialized or not.
+ */
+ AUTO = 1,
+
+ /**
+ * Constant indicating the audio content associated with these attributes should never
+ * be spatialized.
+ */
+ NEVER = 2,
+}
+
+/**
+ * Defines the audio source.
+ * An audio source defines both a default physical source of audio signal, and a recording
+ * configuration.
+ *
+ * Note that these match the equivalent values in MediaRecorder.AudioSource in the Android Java API.
+ *
+ * Added in API level 28.
+ */
+AAudioInputPreset :: enum i32 {
+ /**
+ * Use this preset when other presets do not apply.
+ */
+ GENERIC = 1,
+
+ /**
+ * Use this preset when recording video.
+ */
+ CAMCORDER = 5,
+
+ /**
+ * Use this preset when doing speech recognition.
+ */
+ VOICE_RECOGNITION = 6,
+
+ /**
+ * Use this preset when doing telephony or voice messaging.
+ */
+ VOICE_COMMUNICATION = 7,
+
+ /**
+ * Use this preset to obtain an input with no effects.
+ * Note that this input will not have automatic gain control
+ * so the recorded volume may be very low.
+ */
+ UNPROCESSED = 9,
+
+ /**
+ * Use this preset for capturing audio meant to be processed in real time
+ * and played back for live performance (e.g karaoke).
+ * The capture path will minimize latency and coupling with playback path.
+ * Available since API level 29.
+ */
+ VOICE_PERFORMANCE = 10,
+}
+
+/**
+ * Specifying if audio may or may not be captured by other apps or the system.
+ *
+ * Note that these match the equivalent values in
+ * AudioAttributes
+ * in the Android Java API.
+ *
+ * Added in API level 29.
+ */
+AAudioAllowedCapturePolicy :: enum i32 {
+ /**
+ * Indicates that the audio may be captured by any app.
+ *
+ * For privacy, the following usages can not be recorded: AAUDIO_VOICE_COMMUNICATION*,
+ * AAUDIO_USAGE_NOTIFICATION*, AAUDIO_USAGE_ASSISTANCE* and {@link #AAUDIO_USAGE_ASSISTANT}.
+ *
+ * On Build.VERSION_CODES,
+ * this means only {@link #AAUDIO_USAGE_MEDIA} and {@link #AAUDIO_USAGE_GAME} may be captured.
+ *
+ * See
+ * ALLOW_CAPTURE_BY_ALL.
+ */
+ ALLOW_CAPTURE_BY_ALL = 1,
+ /**
+ * Indicates that the audio may only be captured by system apps.
+ *
+ * System apps can capture for many purposes like accessibility, user guidance...
+ * but have strong restriction. See
+ *
+ * ALLOW_CAPTURE_BY_SYSTEM
+ * for what the system apps can do with the capture audio.
+ */
+ ALLOW_CAPTURE_BY_SYSTEM = 2,
+ /**
+ * Indicates that the audio may not be recorded by any app, even if it is a system app.
+ *
+ * It is encouraged to use {@link #AAUDIO_ALLOW_CAPTURE_BY_SYSTEM} instead of this value as system apps
+ * provide significant and useful features for the user (eg. accessibility).
+ * See
+ * ALLOW_CAPTURE_BY_NONE.
+ */
+ ALLOW_CAPTURE_BY_NONE = 3,
+}
+
+/**
+ * These may be used with AAudioStreamBuilder_setSessionId().
+ *
+ * Added in API level 28.
+ */
+AAudioSessionId :: enum i32 {
+ /**
+ * Do not allocate a session ID.
+ * Effects cannot be used with this stream.
+ * Default.
+ *
+ * Added in API level 28.
+ */
+ NONE = -1,
+
+ /**
+ * Allocate a session ID that can be used to attach and control
+ * effects using the Java AudioEffects API.
+ * Note that using this may result in higher latency.
+ *
+ * Note that this matches the value of AudioManager.AUDIO_SESSION_ID_GENERATE.
+ *
+ * Added in API level 28.
+ */
+ ALLOCATE = 0,
+}
+
+/**
+ * Defines the audio channel mask.
+ * Channel masks are used to describe the samples and their
+ * arrangement in the audio frame. They are also used in the endpoint
+ * (e.g. a USB audio interface, a DAC connected to headphones) to
+ * specify allowable configurations of a particular device.
+ *
+ * Added in API level 32.
+ */
+AAudioChannelMask :: enum u32 {
+ /**
+ * Invalid channel mask
+ */
+ INVALID = 0xFFFFFFFF, // -1
+
+ /**
+ * Output audio channel mask
+ */
+ FRONT_LEFT = 1 << 0,
+ FRONT_RIGHT = 1 << 1,
+ FRONT_CENTER = 1 << 2,
+ LOW_FREQUENCY = 1 << 3,
+ BACK_LEFT = 1 << 4,
+ BACK_RIGHT = 1 << 5,
+ FRONT_LEFT_OF_CENTER = 1 << 6,
+ FRONT_RIGHT_OF_CENTER = 1 << 7,
+ BACK_CENTER = 1 << 8,
+ SIDE_LEFT = 1 << 9,
+ SIDE_RIGHT = 1 << 10,
+ TOP_CENTER = 1 << 11,
+ TOP_FRONT_LEFT = 1 << 12,
+ TOP_FRONT_CENTER = 1 << 13,
+ TOP_FRONT_RIGHT = 1 << 14,
+ TOP_BACK_LEFT = 1 << 15,
+ TOP_BACK_CENTER = 1 << 16,
+ TOP_BACK_RIGHT = 1 << 17,
+ TOP_SIDE_LEFT = 1 << 18,
+ TOP_SIDE_RIGHT = 1 << 19,
+ BOTTOM_FRONT_LEFT = 1 << 20,
+ BOTTOM_FRONT_CENTER = 1 << 21,
+ BOTTOM_FRONT_RIGHT = 1 << 22,
+ LOW_FREQUENCY_2 = 1 << 23,
+ FRONT_WIDE_LEFT = 1 << 24,
+ FRONT_WIDE_RIGHT = 1 << 25,
+
+ MONO = FRONT_LEFT,
+ STEREO = FRONT_LEFT | FRONT_RIGHT,
+ _2POINT1 = FRONT_LEFT | FRONT_RIGHT | LOW_FREQUENCY,
+ TRI = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER,
+ TRI_BACK = FRONT_LEFT | FRONT_RIGHT | BACK_CENTER,
+ _3POINT1 = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY,
+ _2POINT0POINT2 = FRONT_LEFT | FRONT_RIGHT | TOP_SIDE_LEFT | TOP_SIDE_RIGHT,
+ _2POINT1POINT2 = _2POINT0POINT2 | LOW_FREQUENCY,
+ _3POINT0POINT2 = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | TOP_SIDE_LEFT | TOP_SIDE_RIGHT,
+ _3POINT1POINT2 = _3POINT0POINT2 | LOW_FREQUENCY,
+ QUAD = FRONT_LEFT | FRONT_RIGHT | BACK_LEFT | BACK_RIGHT,
+ QUAD_SIDE = FRONT_LEFT | FRONT_RIGHT | SIDE_LEFT | SIDE_RIGHT,
+ SURROUND = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | BACK_CENTER,
+ PENTA = QUAD | FRONT_CENTER,
+ // aka 5POINT1_BACK
+ _5POINT1 = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | BACK_LEFT | BACK_RIGHT,
+ _5POINT1_SIDE = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | SIDE_LEFT | SIDE_RIGHT,
+ _6POINT1 = FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY | BACK_LEFT | BACK_RIGHT | BACK_CENTER,
+ _7POINT1 = _5POINT1 | SIDE_LEFT | SIDE_RIGHT,
+ _5POINT1POINT2 = _5POINT1 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT,
+ _5POINT1POINT4 = _5POINT1 | TOP_FRONT_LEFT | TOP_FRONT_RIGHT | TOP_BACK_LEFT | TOP_BACK_RIGHT,
+ _7POINT1POINT2 = _7POINT1 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT,
+ _7POINT1POINT4 = _7POINT1 | TOP_FRONT_LEFT | TOP_FRONT_RIGHT | TOP_BACK_LEFT | TOP_BACK_RIGHT,
+ _9POINT1POINT4 = _7POINT1POINT4 | FRONT_WIDE_LEFT | FRONT_WIDE_RIGHT,
+ _9POINT1POINT6 = _9POINT1POINT4 | TOP_SIDE_LEFT | TOP_SIDE_RIGHT,
+
+ FRONT_BACK = FRONT_CENTER | BACK_CENTER,
+}
+
+/**
+* Return one of these values from the data callback function.
+*/
+AAudioDataCallbackResult :: enum i32 {
+ /**
+ * Continue calling the callback.
+ */
+ CONTINUE = 0,
+ /**
+ *
+ Stop calling the callback.
+ *
+ * The application will still need to call AAudioStream_requestPause()
+ * or AAudioStream_requestStop().
+ */
+ STOP,
+}
+
+AAudioStream :: struct{}
+AAudioStreamBuilder :: struct{}
+
+/**
+* Prototype for the data function that is passed to AAudioStreamBuilder_setDataCallback :: proc().
+*
+* For an output stream, this function should render and write numFrames of data
+* in the streams current data format to the audioData buffer.
+*
+* For an input stream, this function should read and process numFrames of data
+* from the audioData buffer.
+*
+* The audio data is passed through the buffer. So do NOT call AAudioStream_read :: proc() or
+* AAudioStream_write :: proc() on the stream that is making the callback.
+*
+* Note that numFrames can vary unless AAudioStreamBuilder_setFramesPerDataCallback :: proc()
+* is called.
+*
+* Also note that this callback function should be considered a "real-time" function.
+* It must not do anything that could cause an unbounded delay because that can cause the
+* audio to glitch or pop.
+*
+* These are things the function should NOT do:
+*
+* - allocate memory using, for example, malloc :: proc() or new
+* - any file operations such as opening, closing, reading or writing
+* - any network operations such as streaming
+* - use any mutexes or other synchronization primitives
+* - sleep
+* - stop or close the stream
+* - AAudioStream_read :: proc()
+* - AAudioStream_write :: proc()
+*
+*
+* The following are OK to call from the data callback:
+*
+* - AAudioStream_get*()
+* - AAudio_convertResultToText :: proc()
+*
+*
+* If you need to move data, eg. MIDI commands, in or out of the callback function then
+* we recommend the use of non-blocking techniques such as an atomic FIFO.
+*
+* @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+* @param userData the same address that was passed to AAudioStreamBuilder_setCallback :: proc()
+* @param audioData a pointer to the audio data
+* @param numFrames the number of frames to be processed, which can vary
+* @return AAUDIO_CALLBACK_RESULT_*
+*/
+AAudioStream_dataCallback :: #type proc "c" (stream: ^AAudioStream, userData: rawptr, audioData: rawptr, numFrames: i32) -> AAudioDataCallbackResult
+
+/**
+* Prototype for the callback function that is passed to
+* AAudioStreamBuilder_setErrorCallback :: proc().
+*
+* The following may NOT be called from the error callback:
+*
+* - AAudioStream_requestStop :: proc()
+* - AAudioStream_requestPause :: proc()
+* - AAudioStream_close :: proc()
+* - AAudioStream_waitForStateChange :: proc()
+* - AAudioStream_read :: proc()
+* - AAudioStream_write :: proc()
+*
+*
+* The following are OK to call from the error callback:
+*
+* - AAudioStream_get*()
+* - AAudio_convertResultToText :: proc()
+*
+*
+* @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+* @param userData the same address that was passed to AAudioStreamBuilder_setErrorCallback :: proc()
+* @param error an AAUDIO_ERROR_* value.
+*/
+AAudioStream_errorCallback :: #type proc "c" (stream: ^AAudioStream, userData: rawptr, error: AAudioResult)
+
+foreign aaudio {
+ /**
+ * The text is the ASCII symbol corresponding to the returnCode,
+ * or an English message saying the returnCode is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * Available since API level 26.
+ *
+ * @return pointer to a text representation of an AAudio result code.
+ */
+ AAudio_convertResultToText :: proc(returnCode: AAudioResult) -> cstring ---
+
+ /**
+ * The text is the ASCII symbol corresponding to the stream state,
+ * or an English message saying the state is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * Available since API level 26.
+ *
+ * @return pointer to a text representation of an AAudio state.
+ */
+ AAudio_convertStreamStateToText :: proc(state: AAudioStreamState) -> cstring ---
+
+ // ============================================================
+ // StreamBuilder
+ // ============================================================
+
+ /**
+ * Create a StreamBuilder that can be used to open a Stream.
+ *
+ * The deviceId is initially unspecified, meaning that the current default device will be used.
+ *
+ * The default direction is {@link #AAUDIO_DIRECTION_OUTPUT}.
+ * The default sharing mode is {@link #AAUDIO_SHARING_MODE_SHARED}.
+ * The data format, samplesPerFrames and sampleRate are unspecified and will be
+ * chosen by the device when it is opened.
+ *
+ * AAudioStreamBuilder_delete :: proc() must be called when you are done using the builder.
+ *
+ * Available since API level 26.
+ */
+ AAudio_createStreamBuilder :: proc(builder: ^^AAudioStreamBuilder) -> AAudioResult ---
+
+ /**
+ * Request an audio device identified by an ID.
+ *
+ * The ID could be obtained from the Java AudioManager.
+ * AudioManager.getDevices :: proc() returns an array of {@link AudioDeviceInfo},
+ * which contains a getId :: proc() method. That ID can be passed to this function.
+ *
+ * It is possible that you may not get the device that you requested.
+ * So if it is important to you, you should call
+ * AAudioStream_getDeviceId :: proc() after the stream is opened to
+ * verify the actual ID.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED},
+ * in which case the primary device will be used.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param deviceId device identifier or {@link #AAUDIO_UNSPECIFIED}
+ */
+ AAudioStreamBuilder_setDeviceId :: proc(builder: ^AAudioStreamBuilder, deviceId: i32) ---
+
+ /**
+ * Declare the name of the package creating the stream.
+ *
+ * This is usually {@code Context#getPackageName :: proc()}.
+ *
+ * The default, if you do not call this function, is a random package in the calling uid.
+ * The vast majority of apps have only one package per calling UID.
+ * If an invalid package name is set, input streams may not be given permission to
+ * record when started.
+ *
+ * The package name is usually the applicationId in your app's build.gradle file.
+ *
+ * Available since API level 31.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param packageName packageName of the calling app.
+ */
+ AAudioStreamBuilder_setPackageName :: proc(builder: ^AAudioStreamBuilder, packageName: cstring) ---
+
+ /**
+ * Declare the attribution tag of the context creating the stream.
+ *
+ * This is usually {@code Context#getAttributionTag :: proc()}.
+ *
+ * The default, if you do not call this function, is null.
+ *
+ * Available since API level 31.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param attributionTag attributionTag of the calling context.
+ */
+ AAudioStreamBuilder_setAttributionTag :: proc(builder: ^AAudioStreamBuilder, attributionTag: cstring) ---
+
+ /**
+ * Request a sample rate in Hertz.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ * An optimal value will then be chosen when the stream is opened.
+ * After opening a stream with an unspecified value, the application must
+ * query for the actual value, which may vary by device.
+ *
+ * If an exact value is specified then an opened stream will use that value.
+ * If a stream cannot be opened with the specified value then the open will fail.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param sampleRate frames per second. Common rates include 44100 and 48000 Hz.
+ */
+ AAudioStreamBuilder_setSampleRate :: proc(builder: ^AAudioStreamBuilder, sampleRate: i32) ---
+
+ /**
+ * Request a number of channels for the stream.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ * An optimal value will then be chosen when the stream is opened.
+ * After opening a stream with an unspecified value, the application must
+ * query for the actual value, which may vary by device.
+ *
+ * If an exact value is specified then an opened stream will use that value.
+ * If a stream cannot be opened with the specified value then the open will fail.
+ *
+ * As the channel count provided here may be different from the corresponding channel count
+ * of channel mask used in {@link AAudioStreamBuilder_setChannelMask}, the last called function
+ * will be respected if both this function and {@link AAudioStreamBuilder_setChannelMask} are
+ * called.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param channelCount Number of channels desired.
+ */
+ AAudioStreamBuilder_setChannelCount :: proc(builder: ^AAudioStreamBuilder, channelCount: i32) ---
+
+ /**
+ * Identical to AAudioStreamBuilder_setChannelCount :: proc().
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param samplesPerFrame Number of samples in a frame.
+ *
+ * @deprecated use {@link AAudioStreamBuilder_setChannelCount}
+ */
+ AAudioStreamBuilder_setSamplesPerFrame :: proc(builder: ^AAudioStreamBuilder, samplesPerFrame: i32) ---
+
+ /**
+ * Request a sample data format, for example {@link #AAUDIO_FORMAT_PCM_I16}.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ * An optimal value will then be chosen when the stream is opened.
+ * After opening a stream with an unspecified value, the application must
+ * query for the actual value, which may vary by device.
+ *
+ * If an exact value is specified then an opened stream will use that value.
+ * If a stream cannot be opened with the specified value then the open will fail.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
+ * {@link #AAUDIO_FORMAT_PCM_I16}.
+ */
+ AAudioStreamBuilder_setFormat :: proc(builder: ^AAudioStreamBuilder, format: AAudioFormat) ---
+
+ /**
+ * Request a mode for sharing the device.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_SHARING_MODE_SHARED}.
+ *
+ * The requested sharing mode may not be available.
+ * The application can query for the actual mode after the stream is opened.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
+ */
+ AAudioStreamBuilder_setSharingMode :: proc(builder: ^AAudioStreamBuilder, sharingMode: AAudioSharingMode) ---
+
+ /**
+ * Request the direction for a stream.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_DIRECTION_OUTPUT}.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
+ */
+ AAudioStreamBuilder_setDirection :: proc(builder: ^AAudioStreamBuilder, direction: AAudioDirection) ---
+
+ /**
+ * Set the requested buffer capacity in frames.
+ * The final AAudioStream capacity may differ, but will probably be at least this big.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
+ */
+ AAudioStreamBuilder_setBufferCapacityInFrames :: proc(builder: ^AAudioStreamBuilder, numFrames: i32) ---
+
+ /**
+ * Set the requested performance mode.
+ *
+ * Supported modes are {@link #AAUDIO_PERFORMANCE_MODE_NONE},
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING} * and {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_PERFORMANCE_MODE_NONE}.
+ *
+ * You may not get the mode you requested.
+ * You can call AAudioStream_getPerformanceMode :: proc()
+ * to find out the final mode for the stream.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
+ */
+ AAudioStreamBuilder_setPerformanceMode :: proc(builder: ^AAudioStreamBuilder, mode: AAudioPerformanceMode) ---
+
+ /**
+ * Set the intended use case for the output stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect how volume and focus is handled for the stream.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
+ *
+ * Available since API level 28.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
+ */
+ AAudioStreamBuilder_setUsage :: proc(builder: ^AAudioStreamBuilder, usage: AAudioUsage) ---
+
+ /**
+ * Set the type of audio data that the output stream will carry.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect whether a stream is paused when a notification occurs.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
+ *
+ * Available since API level 28.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
+ */
+ AAudioStreamBuilder_setContentType :: proc(builder: ^AAudioStreamBuilder, contentType: AAudioContentType) ---
+
+ /**
+ * Sets the behavior affecting whether spatialization will be used.
+ *
+ * The AAudio system will use this information to select whether the stream will go
+ * through a spatializer effect or not when the effect is supported and enabled.
+ *
+ * Available since API level 32.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param spatializationBehavior the desired behavior with regards to spatialization, eg.
+ * {@link #AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO}
+ */
+ AAudioStreamBuilder_setSpatializationBehavior :: proc(builder: ^AAudioStreamBuilder, spatializationBehavior: AAudioSpatializationBehavior) ---
+
+ /**
+ * Specifies whether the audio data of this output stream has already been processed for
+ * spatialization.
+ *
+ * If the stream has been processed for spatialization, setting this to true will prevent
+ * issues such as double-processing on platforms that will spatialize audio data.
+ *
+ * Available since API level 32.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param isSpatialized true if the content is already processed for binaural or transaural spatial
+ * rendering, false otherwise.
+ */
+ AAudioStreamBuilder_setIsContentSpatialized :: proc(builder: ^AAudioStreamBuilder, isSpatialized: bool) ---
+
+ /**
+ * Set the input (capture) preset for the stream.
+ *
+ * The AAudio system will use this information to optimize the
+ * behavior of the stream.
+ * This could, for example, affect which microphones are used and how the
+ * recorded data is processed.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_INPUT_PRESET_VOICE_RECOGNITION}.
+ * That is because VOICE_RECOGNITION is the preset with the lowest latency
+ * on many platforms.
+ *
+ * Available since API level 28.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param inputPreset the desired configuration for recording
+ */
+ AAudioStreamBuilder_setInputPreset :: proc(builder: ^AAudioStreamBuilder, inputPreset: AAudioInputPreset) ---
+
+ /**
+ * Specify whether this stream audio may or may not be captured by other apps or the system.
+ *
+ * The default is {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}.
+ *
+ * Note that an application can also set its global policy, in which case the most restrictive
+ * policy is always applied. See
+ *
+ * setAllowedCapturePolicy :: proc(int)
+ *
+ * Available since API level 29.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param capturePolicy the desired level of opt-out from being captured.
+ */
+ AAudioStreamBuilder_setAllowedCapturePolicy :: proc(builder: ^AAudioStreamBuilder, capturePolicy: AAudioAllowedCapturePolicy) ---
+
+ /** Set the requested session ID.
+ *
+ * The session ID can be used to associate a stream with effects processors.
+ * The effects are controlled using the Android AudioEffect Java API.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_SESSION_ID_NONE}.
+ *
+ * If set to {@link #AAUDIO_SESSION_ID_ALLOCATE} then a session ID will be allocated
+ * when the stream is opened.
+ *
+ * The allocated session ID can be obtained by calling AAudioStream_getSessionId :: proc()
+ * and then used with this function when opening another stream.
+ * This allows effects to be shared between streams.
+ *
+ * Session IDs from AAudio can be used with the Android Java APIs and vice versa.
+ * So a session ID from an AAudio stream can be passed to Java
+ * and effects applied using the Java AudioEffect API.
+ *
+ * Note that allocating or setting a session ID may result in a stream with higher latency.
+ *
+ * Allocated session IDs will always be positive and nonzero.
+ *
+ * Available since API level 28.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
+ */
+ AAudioStreamBuilder_setSessionId :: proc(builder: ^AAudioStreamBuilder, sessionId: AAudioSessionId) ---
+
+
+ /** Indicates whether this input stream must be marked as privacy sensitive or not.
+ *
+ * When true, this input stream is privacy sensitive and any concurrent capture
+ * is not permitted.
+ *
+ * This is off (false) by default except when the input preset is {@link #AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION}
+ * or {@link #AAUDIO_INPUT_PRESET_CAMCORDER}.
+ *
+ * Always takes precedence over default from input preset when set explicitly.
+ *
+ * Only relevant if the stream direction is {@link #AAUDIO_DIRECTION_INPUT}.
+ *
+ * Added in API level 30.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param privacySensitive true if capture from this stream must be marked as privacy sensitive,
+ * false otherwise.
+ */
+ AAudioStreamBuilder_setPrivacySensitive :: proc(builder: ^AAudioStreamBuilder, privacySensitive: bool) ---
+
+ /**
+ * Request that AAudio call this functions when the stream is running.
+ *
+ * Note that when using this callback, the audio data will be passed in or out
+ * of the function as an argument.
+ * So you cannot call AAudioStream_write :: proc() or AAudioStream_read()
+ * on the same stream that has an active data callback.
+ *
+ * The callback function will start being called after AAudioStream_requestStart :: proc()
+ * is called.
+ * It will stop being called after AAudioStream_requestPause :: proc() or
+ * AAudioStream_requestStop :: proc() is called.
+ *
+ * This callback function will be called on a real-time thread owned by AAudio.
+ * The low latency streams may have callback threads with higher priority than normal streams.
+ * See {@link #AAudioStream_dataCallback} for more information.
+ *
+ * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param callback pointer to a function that will process audio data.
+ * @param userData pointer to an application data structure that will be passed
+ * to the callback functions.
+ */
+ AAudioStreamBuilder_setDataCallback :: proc(builder: ^AAudioStreamBuilder, callback: AAudioStream_dataCallback, userData: rawptr) ---
+
+ /**
+ * Set the requested data callback buffer size in frames.
+ * See {@link #AAudioStream_dataCallback}.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ *
+ * For the lowest possible latency, do not call this function. AAudio will then
+ * call the dataProc callback function with whatever size is optimal.
+ * That size may vary from one callback to another.
+ *
+ * Only use this function if the application requires a specific number of frames for processing.
+ * The application might, for example, be using an FFT that requires
+ * a specific power-of-two sized buffer.
+ *
+ * AAudio may need to add additional buffering in order to adapt between the internal
+ * buffer size and the requested buffer size.
+ *
+ * If you do call this function then the requested size should be less than
+ * half the buffer capacity, to allow double buffering.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
+ */
+ AAudioStreamBuilder_setFramesPerDataCallback :: proc(builder: ^AAudioStreamBuilder, numFrames: i32) ---
+
+ /**
+ * Request that AAudio call this function if any error occurs or the stream is disconnected.
+ *
+ * It will be called, for example, if a headset or a USB device is unplugged causing the stream's
+ * device to be unavailable or "disconnected".
+ * Another possible cause of error would be a timeout or an unanticipated internal error.
+ *
+ * In response, this function should signal or create another thread to stop
+ * and close this stream. The other thread could then reopen a stream on another device.
+ * Do not stop or close the stream, or reopen the new stream, directly from this callback.
+ *
+ * This callback will not be called because of actions by the application, such as stopping
+ * or closing a stream.
+ *
+ * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param callback pointer to a function that will be called if an error occurs.
+ * @param userData pointer to an application data structure that will be passed
+ * to the callback functions.
+ */
+ AAudioStreamBuilder_setErrorCallback :: proc(builder: ^AAudioStreamBuilder, callback: AAudioStream_errorCallback, userData: rawptr) ---
+
+ /**
+ * Open a stream based on the options in the StreamBuilder.
+ *
+ * AAudioStream_close :: proc() must be called when finished with the stream to recover
+ * the memory and to free the associated resources.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param stream pointer to a variable to receive the new stream reference
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStreamBuilder_openStream :: proc(builder: ^AAudioStreamBuilder, stream: ^^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Delete the resources associated with the StreamBuilder.
+ *
+ * Available since API level 26.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStreamBuilder_delete :: proc(builder: ^AAudioStreamBuilder) -> AAudioResult ---
+
+ /**
+ * Set audio channel mask for the stream.
+ *
+ * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
+ * If both channel mask and count are not set, then stereo will then be chosen when the
+ * stream is opened.
+ * After opening a stream with an unspecified value, the application must query for the
+ * actual value, which may vary by device.
+ *
+ * If an exact value is specified then an opened stream will use that value.
+ * If a stream cannot be opened with the specified value then the open will fail.
+ *
+ * As the corresponding channel count of provided channel mask here may be different
+ * from the channel count used in {@link AAudioStreamBuilder_setChannelCount} or
+ * {@link AAudioStreamBuilder_setSamplesPerFrame}, the last called function will be
+ * respected if this function and {@link AAudioStreamBuilder_setChannelCount} or
+ * {@link AAudioStreamBuilder_setSamplesPerFrame} are called.
+ *
+ * Available since API level 32.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder :: proc()
+ * @param channelMask Audio channel mask desired.
+ */
+ AAudioStreamBuilder_setChannelMask :: proc(builder: ^AAudioStreamBuilder, channelMask: AAudioChannelMask) ---
+
+ // ============================================================
+ // Stream Control
+ // ============================================================
+
+ /**
+ * Free the audio resources associated with a stream created by
+ * AAudioStreamBuilder_openStream :: proc().
+ * AAudioStream_close :: proc() should be called at some point after calling
+ * this function.
+ *
+ * After this call, the stream will be in {@link #AAUDIO_STREAM_STATE_CLOSING}
+ *
+ * This function is useful if you want to release the audio resources immediately,
+ * but still allow queries to the stream to occur from other threads. This often
+ * happens if you are monitoring stream progress from a UI thread.
+ *
+ * NOTE: This function is only fully implemented for MMAP streams,
+ * which are low latency streams supported by some devices.
+ * On other "Legacy" streams some audio resources will still be in use
+ * and some callbacks may still be in process after this call.
+ *
+ * Available since API level 30.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_release :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Delete the internal data structures associated with the stream created
+ * by AAudioStreamBuilder_openStream :: proc().
+ *
+ * If AAudioStream_release :: proc() has not been called then it will be called automatically.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_close :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Asynchronously request to start playing the stream. For output streams, one should
+ * write to the stream to fill the buffer before starting.
+ * Otherwise it will underflow.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STARTING} or
+ * {@link #AAUDIO_STREAM_STATE_STARTED}.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_requestStart :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Asynchronous request for the stream to pause.
+ * Pausing a stream will freeze the data flow but not flush any buffers.
+ * Use AAudioStream_requestStart :: proc() to resume playback after a pause.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_PAUSING} or
+ * {@link #AAUDIO_STREAM_STATE_PAUSED}.
+ *
+ * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
+ * For input streams use AAudioStream_requestStop :: proc().
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_requestPause :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Asynchronous request for the stream to flush.
+ * Flushing will discard any pending data.
+ * This call only works if the stream is pausing or paused. TODO review
+ * Frame counters are not reset by a flush. They may be advanced.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_FLUSHING} or
+ * {@link #AAUDIO_STREAM_STATE_FLUSHED}.
+ *
+ * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_requestFlush :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Asynchronous request for the stream to stop.
+ * The stream will stop after all of the data currently buffered has been played.
+ * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STOPPING} or
+ * {@link #AAUDIO_STREAM_STATE_STOPPED}.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_requestStop :: proc(stream: ^AAudioStream) -> AAudioResult ---
+
+ /**
+ * Query the current state of the client, eg. {@link #AAUDIO_STREAM_STATE_PAUSING}
+ *
+ * This function will immediately return the state without updating the state.
+ * If you want to update the client state based on the server state then
+ * call AAudioStream_waitForStateChange :: proc() with currentState
+ * set to {@link #AAUDIO_STREAM_STATE_UNKNOWN} and a zero timeout.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ */
+ AAudioStream_getState :: proc(stream: ^AAudioStream) -> AAudioStreamState ---
+
+ /**
+ * Wait until the current state no longer matches the input state.
+ *
+ * This will update the current client state.
+ *
+ *
+ * AAudioResult result = AAUDIO_OK
+ * AAudioStreamState currentState = AAudioStream_getState :: proc(stream)
+ * AAudioStreamState inputState = currentState
+ * while (result == AAUDIO_OK && currentState != AAUDIO_STREAM_STATE_PAUSED) {
+ * result = AAudioStream_waitForStateChange :: proc(
+ * stream, inputState, ¤tState, MY_TIMEOUT_NANOS)
+ * inputState = currentState
+ * }
+ *
+ *
+ * Available since API level 26.
+ *
+ * @param stream A reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @param inputState The state we want to avoid.
+ * @param nextState Pointer to a variable that will be set to the new state.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return {@link #AAUDIO_OK} or a negative error.
+ */
+ AAudioStream_waitForStateChange :: proc(stream: ^AAudioStream, inputState: AAudioStreamState, nextState: ^AAudioStreamState, timeoutNanoseconds: i64) -> AAudioResult ---
+
+ // ============================================================
+ // Stream I/O
+ // ============================================================
+
+ /**
+ * Read data from the stream.
+ *
+ * The call will wait until the read is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for data.
+ *
+ * If the call times out then zero or a partial frame count will be returned.
+ *
+ * Available since API level 26.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream :: proc().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to read. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually read or a negative error.
+ */
+ AAudioStream_read :: proc(stream: ^AAudioStream, buffer: rawptr, numFrames: i32, timeoutNanoseconds: i64) -> AAudioResult ---
+
+ /**
+ * Write data to the stream.
+ *
+ * The call will wait until the write is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for room in the buffer.
+ *
+ * If the call times out then zero or a partial frame count will be returned.
+ *
+ * Available since API level 26.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream :: proc().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to write. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+ AAudioStream_write :: proc(stream: ^AAudioStream, buffer: rawptr, numFrames: i32, timeoutNanoseconds: i64) -> AAudioResult ---
+
+ // ============================================================
+ // Stream - queries
+ // ============================================================
+
+ /**
+ * This can be used to adjust the latency of the buffer by changing
+ * the threshold where blocking will occur.
+ * By combining this with AAudioStream_getXRunCount :: proc(), the latency can be tuned
+ * at run-time for each device.
+ *
+ * This cannot be set higher than AAudioStream_getBufferCapacityInFrames :: proc().
+ *
+ * Note that you will probably not get the exact size you request.
+ * You can check the return value or call AAudioStream_getBufferSizeInFrames :: proc()
+ * to see what the actual final size is.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @param numFrames requested number of frames that can be filled without blocking
+ * @return actual buffer size in frames or a negative error
+ */
+ AAudioStream_setBufferSizeInFrames :: proc(stream: ^AAudioStream, numFrames: i32) -> AAudioResult ---
+
+ /**
+ * Query the maximum number of frames that can be filled without blocking.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return buffer size in frames.
+ */
+ AAudioStream_getBufferSizeInFrames :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Query the number of frames that the application should read or write at
+ * one time for optimal performance. It is OK if an application writes
+ * a different number of frames. But the buffer size may need to be larger
+ * in order to avoid underruns or overruns.
+ *
+ * Note that this may or may not match the actual device burst size.
+ * For some endpoints, the burst size can vary dynamically.
+ * But these tend to be devices with high latency.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return burst size
+ */
+ AAudioStream_getFramesPerBurst :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Query maximum buffer capacity in frames.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return buffer capacity in frames
+ */
+ AAudioStream_getBufferCapacityInFrames :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Query the size of the buffer that will be passed to the dataProc callback
+ * in the numFrames parameter.
+ *
+ * This call can be used if the application needs to know the value of numFrames before
+ * the stream is started. This is not normally necessary.
+ *
+ * If a specific size was requested by calling
+ * AAudioStreamBuilder_setFramesPerDataCallback :: proc() then this will be the same size.
+ *
+ * If AAudioStreamBuilder_setFramesPerDataCallback :: proc() was not called then this will
+ * return the size chosen by AAudio, or {@link #AAUDIO_UNSPECIFIED}.
+ *
+ * {@link #AAUDIO_UNSPECIFIED} indicates that the callback buffer size for this stream
+ * may vary from one dataProc callback to the next.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
+ */
+ AAudioStream_getFramesPerDataCallback :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * An XRun is an Underrun or an Overrun.
+ * During playing, an underrun will occur if the stream is not written in time
+ * and the system runs out of valid data.
+ * During recording, an overrun will occur if the stream is not read in time
+ * and there is no place to put the incoming data so it is discarded.
+ *
+ * An underrun or overrun can cause an audible "pop" or "glitch".
+ *
+ * Note that some INPUT devices may not support this function.
+ * In that case a 0 will always be returned.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return the underrun or overrun count
+ */
+ AAudioStream_getXRunCount :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual sample rate
+ */
+ AAudioStream_getSampleRate :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * A stream has one or more channels of data.
+ * A frame will contain one sample for each channel.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual number of channels
+ */
+ AAudioStream_getChannelCount :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Identical to AAudioStream_getChannelCount :: proc().
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual number of samples frame
+ */
+ AAudioStream_getSamplesPerFrame :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual device ID
+ */
+ AAudioStream_getDeviceId :: proc(stream: ^AAudioStream) -> i32 ---
+
+ /**
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual data format
+ */
+ AAudioStream_getFormat :: proc(stream: ^AAudioStream) -> AAudioFormat ---
+
+ /**
+ * Provide actual sharing mode.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual sharing mode
+ */
+ AAudioStream_getSharingMode :: proc(stream: ^AAudioStream) -> AAudioSharingMode ---
+
+ /**
+ * Get the performance mode used by the stream.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ */
+ AAudioStream_getPerformanceMode :: proc(stream: ^AAudioStream) -> AAudioPerformanceMode ---
+
+ /**
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return direction
+ */
+ AAudioStream_getDirection :: proc(stream: ^AAudioStream) -> AAudioDirection ---
+
+ /**
+ * Passes back the number of frames that have been written since the stream was created.
+ * For an output stream, this will be advanced by the application calling write :: proc()
+ * or by a data callback.
+ * For an input stream, this will be advanced by the endpoint.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return frames written
+ */
+ AAudioStream_getFramesWritten :: proc(stream: ^AAudioStream) -> i64 ---
+
+ /**
+ * Passes back the number of frames that have been read since the stream was created.
+ * For an output stream, this will be advanced by the endpoint.
+ * For an input stream, this will be advanced by the application calling read :: proc()
+ * or by a data callback.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return frames read
+ */
+ AAudioStream_getFramesRead :: proc(stream: ^AAudioStream) -> i64 ---
+
+ /**
+ * Passes back the session ID associated with this stream.
+ *
+ * The session ID can be used to associate a stream with effects processors.
+ * The effects are controlled using the Android AudioEffect Java API.
+ *
+ * If AAudioStreamBuilder_setSessionId :: proc() was
+ * called with {@link #AAUDIO_SESSION_ID_ALLOCATE}
+ * then a new session ID should be allocated once when the stream is opened.
+ *
+ * If AAudioStreamBuilder_setSessionId :: proc() was called with a previously allocated
+ * session ID then that value should be returned.
+ *
+ * If AAudioStreamBuilder_setSessionId :: proc() was not called then this function should
+ * return {@link #AAUDIO_SESSION_ID_NONE}.
+ *
+ * The sessionID for a stream should not change once the stream has been opened.
+ *
+ * Available since API level 28.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
+ */
+ AAudioStream_getSessionId :: proc(stream: ^AAudioStream) -> AAudioSessionId ---
+
+ /**
+ * Passes back the time at which a particular frame was presented.
+ * This can be used to synchronize audio with video or MIDI.
+ * It can also be used to align a recorded stream with a playback stream.
+ *
+ * Timestamps are only valid when the stream is in {@link #AAUDIO_STREAM_STATE_STARTED}.
+ * {@link #AAUDIO_ERROR_INVALID_STATE} will be returned if the stream is not started.
+ * Note that because requestStart :: proc() is asynchronous, timestamps will not be valid until
+ * a short time after calling requestStart :: proc().
+ * So {@link #AAUDIO_ERROR_INVALID_STATE} should not be considered a fatal error.
+ * Just try calling again later.
+ *
+ * If an error occurs, then the position and time will not be modified.
+ *
+ * The position and time passed back are monotonically increasing.
+ *
+ * Available since API level 26.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
+ * @param framePosition pointer to a variable to receive the position
+ * @param timeNanoseconds pointer to a variable to receive the time
+ * @return {@link #AAUDIO_OK} or a negative error
+ */
+ AAudioStream_getTimestamp :: proc(stream: ^AAudioStream, clockid: clockid_t, framePosition: ^i64, timeNanoseconds: ^i64) -> AAudioResult ---
+
+ /**
+ * Return the use case for the stream.
+ *
+ * Available since API level 28.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return frames read
+ */
+ AAudioStream_getUsage :: proc(stream: ^AAudioStream) -> AAudioUsage ---
+
+ /**
+ * Return the content type for the stream.
+ *
+ * Available since API level 28.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
+ */
+ AAudioStream_getContentType :: proc(stream: ^AAudioStream) -> AAudioContentType ---
+
+ /**
+ * Return the spatialization behavior for the stream.
+ *
+ * If none was explicitly set, it will return the default
+ * {@link #AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO} behavior.
+ *
+ * Available since API level 32.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return spatialization behavior, for example {@link #AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO}
+ */
+ AAudioStream_getSpatializationBehavior :: proc(stream: ^AAudioStream) -> AAudioSpatializationBehavior ---
+
+ /**
+ * Return whether the content of the stream is spatialized.
+ *
+ * Available since API level 32.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return true if the content is spatialized
+ */
+ AAudioStream_isContentSpatialized :: proc(stream: ^AAudioStream) -> bool ---
+
+
+ /**
+ * Return the input preset for the stream.
+ *
+ * Available since API level 28.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
+ */
+ AAudioStream_getInputPreset :: proc(stream: ^AAudioStream) -> AAudioInputPreset ---
+
+ /**
+ * Return the policy that determines whether the audio may or may not be captured
+ * by other apps or the system.
+ *
+ * Available since API level 29.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
+ */
+ AAudioStream_getAllowedCapturePolicy :: proc(stream: ^AAudioStream) -> AAudioAllowedCapturePolicy ---
+
+
+ /**
+ * Return whether this input stream is marked as privacy sensitive or not.
+ *
+ * See {@link #AAudioStreamBuilder_setPrivacySensitive :: proc()}.
+ *
+ * Added in API level 30.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return true if privacy sensitive, false otherwise
+ */
+ AAudioStream_isPrivacySensitive :: proc(stream: ^AAudioStream) -> bool ---
+
+ /**
+ * Return the channel mask for the stream. This will be the mask set using
+ * {@link #AAudioStreamBuilder_setChannelMask}, or {@link #AAUDIO_UNSPECIFIED} otherwise.
+ *
+ * Available since API level 32.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream :: proc()
+ * @return actual channel mask
+ */
+ AAudioStream_getChannelMask :: proc(stream: ^AAudioStream) -> AAudioChannelMask ---
+}
diff --git a/amidi/AMidi.odin b/amidi/AMidi.odin
new file mode 100644
index 0000000..21cae7d
--- /dev/null
+++ b/amidi/AMidi.odin
@@ -0,0 +1,329 @@
+//+build android
+package amidi
+
+foreign import amidi "system:amidi"
+
+/*
+ * Message Op Codes. Used to parse MIDI data packets
+ */
+AMidiOpcode :: enum i32 {
+ DATA = 1, /* The MIDI packet contains normal MIDI data */
+ FLUSH = 2, /* The MIDI packet contains just a MIDI FLUSH command. */
+ /* Forces the send of any pending MIDI data. */
+}
+
+/*
+ * Type IDs for various MIDI devices.
+ */
+AMidiDeviceType :: enum i32 {
+ USB = 1, /* A MIDI device connected to the Android USB port */
+ VIRTUAL = 2, /* A software object implementing MidiDeviceService */
+ BLUETOOTH = 3 /* A MIDI device connected via BlueTooth */
+}
+
+/*
+ * Protocol IDs for various MIDI devices.
+ *
+ * Introduced in API 33.
+ */
+AMidiDevice_Protocol :: enum i32 {
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use UMP to negotiate with the device with MIDI-CI.
+ * MIDI-CI is defined in "MIDI Capability Inquiry (MIDI-CI)" spec.
+ */
+ UMP_USE_MIDI_CI = 0,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 1.0 through UMP with packet sizes up to 64 bits.
+ */
+ UMP_MIDI_1_0_UP_TO_64_BITS = 1,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 1.0 through UMP with packet sizes up to 64 bits and jitter reduction timestamps.
+ */
+ UMP_MIDI_1_0_UP_TO_64_BITS_AND_JRTS = 2,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 1.0 through UMP with packet sizes up to 128 bits.
+ */
+ UMP_MIDI_1_0_UP_TO_128_BITS = 3,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 1.0 through UMP with packet sizes up to 128 bits and jitter reduction timestamps.
+ */
+ UMP_MIDI_1_0_UP_TO_128_BITS_AND_JRTS = 4,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 2.0 through UMP.
+ */
+ UMP_MIDI_2_0 = 17,
+
+ /**
+ * Constant representing a default protocol with Universal MIDI Packets (UMP).
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * All UMP data should be a multiple of 4 bytes.
+ * Use MIDI 2.0 through UMP and jitter reduction timestamps.
+ */
+ UMP_MIDI_2_0_AND_JRTS = 18,
+
+ /**
+ * Constant representing a device with an unknown default protocol.
+ * If Universal MIDI Packets (UMP) are needed, use MIDI-CI through MIDI 1.0.
+ * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec.
+ * MIDI-CI is defined in "MIDI Capability Inquiry (MIDI-CI)" spec.
+ */
+ UNKNOWN = -1
+}
+
+AMidiDevice :: struct{}
+AMidiInputPort :: struct{}
+AMidiOutputPort :: struct{}
+
+foreign amidi {
+ /*
+ * Device API
+ */
+ /**
+ * Connects a native Midi Device object to the associated Java MidiDevice object. Use this
+ * AMidiDevice to access the rest of the native MIDI API. Use AMidiDevice_release() to
+ * disconnect from the Java object when not being used any more.
+ *
+ * @param env Points to the Java Environment.
+ * @param midiDeviceObj The Java MidiDevice Object.
+ * @param outDevicePtrPtr Points to the pointer to receive the AMidiDevice
+ *
+ * @return AMEDIA_OK on success, or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the midiDeviceObj
+ * is null or already connected to a native AMidiDevice
+ * @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
+ *
+ * Available since API level 29.
+ */
+ AMidiDevice_fromJava :: proc(env: ^JNIEnv, midiDeviceObj: jobject, outDevicePtrPtr: ^^AMidiDevice) -> media_status_t ---
+
+ /**
+ * Disconnects the native Midi Device Object from the associated Java MidiDevice object.
+ *
+ * @param midiDevice Points to the native AMIDI_MidiDevice.
+ *
+ * @return AMEDIA_OK on success,
+ * or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the device is not consistent with the associated Java MidiDevice.
+ * @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
+ *
+ * Available since API level 29.
+ */
+ AMidiDevice_release :: proc(midiDevice: ^AMidiDevice) -> media_status_t ---
+
+ /**
+ * Gets the MIDI device type.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return The identifier of the MIDI device type:
+ * AMIDI_DEVICE_TYPE_USB
+ * AMIDI_DEVICE_TYPE_VIRTUAL
+ * AMIDI_DEVICE_TYPE_BLUETOOTH
+ * or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown error.
+ *
+ * Available since API level 29.
+ */
+ AMidiDevice_getType :: proc(device: ^AMidiDevice) -> i32 ---
+
+ /**
+ * Gets the number of input (sending) ports available on the specified MIDI device.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return If successful, returns the number of MIDI input (sending) ports available on the
+ * device. If an error occurs, returns a negative value indicating the error:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
+ *
+ * Available since API level 29.
+ */
+ AMidiDevice_getNumInputPorts :: proc(device: ^AMidiDevice) -> int ---
+
+ /**
+ * Gets the number of output (receiving) ports available on the specified MIDI device.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return If successful, returns the number of MIDI output (receiving) ports available on the
+ * device. If an error occurs, returns a negative value indicating the error:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
+ *
+ * Available since API level 29.
+ */
+ AMidiDevice_getNumOutputPorts :: proc(device: ^AMidiDevice) -> int ---
+
+ /**
+ * Gets the MIDI device default protocol.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return The identifier of the MIDI device default protocol:
+ * AMIDI_DEVICE_PROTOCOL_UMP_USE_MIDI_CI
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_1_0_UP_TO_64_BITS_AND_JRTS
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_1_0_UP_TO_128_BITS_AND_JRTS
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_2_0
+ * AMIDI_DEVICE_PROTOCOL_UMP_MIDI_2_0_AND_JRTS
+ * AMIDI_DEVICE_PROTOCOL_UNKNOWN
+ *
+ * Most devices should return PROTOCOL_UNKNOWN (-1). This is intentional as devices
+ * with default UMP support are not backwards compatible. When the device is null,
+ * return AMIDI_DEVICE_PROTOCOL_UNKNOWN.
+ *
+ * Available since API 33.
+ */
+ AMidiDevice_getDefaultProtocol :: proc(device: AMidiDevice) -> AMidiDevice_Protocol ---
+
+ /*
+ * API for receiving data from the Output port of a device.
+ */
+ /**
+ * Opens the output port so that the client can receive data from it. The port remains open and
+ * valid until AMidiOutputPort_close() is called for the returned AMidiOutputPort.
+ *
+ * @param device Specifies the MIDI device.
+ * @param portNumber Specifies the zero-based port index on the device to open. This value ranges
+ * between 0 and one less than the number of output ports reported by the
+ * AMidiDevice_getNumOutputPorts function.
+ * @param outOutputPortPtr Receives the native API port identifier of the opened port.
+ *
+ * @return AMEDIA_OK, or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
+ *
+ * Available since API level 29.
+ */
+ AMidiOutputPort_open :: proc(device: ^AMidiDevice, portNumber: i32, outOutputPortPtr: ^^AMidiOutputPort) -> media_status_t ---
+
+ /**
+ * Closes the output port.
+ *
+ * @param outputPort The native API port identifier of the port.
+ *
+ * Available since API level 29.
+ */
+ AMidiOutputPort_close :: proc(outputPort: ^AMidiOutputPort) ---
+
+ /**
+ * Receives the next pending MIDI message. To retrieve all pending messages, the client should
+ * repeatedly call this method until it returns 0.
+ *
+ * Note that this is a non-blocking call. If there are no Midi messages are available, the function
+ * returns 0 immediately (for 0 messages received).
+ *
+ * @param outputPort Identifies the port to receive messages from.
+ * @param opcodePtr Receives the message Op Code.
+ * @param buffer Points to the buffer to receive the message data bytes.
+ * @param maxBytes Specifies the size of the buffer pointed to by the buffer parameter.
+ * @param numBytesReceivedPtr On exit, receives the actual number of bytes stored in buffer.
+ * @param outTimestampPtr If non-NULL, receives the timestamp associated with the message.
+ * (the current value of the running Java Virtual Machine's high-resolution time source,
+ * in nanoseconds)
+ * @return the number of messages received (either 0 or 1), or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
+ *
+ * Available since API level 29.
+ */
+ AMidiOutputPort_receive :: proc(outputPort: ^AMidiOutputPort, opcodePtr: ^AMidiOpcode, buffer: [^]byte, maxBytes: uint, numBytesReceivedPtr: ^uint, outTimestampPtr: ^i64) -> int ---
+
+ /*
+ * API for sending data to the Input port of a device.
+ */
+ /**
+ * Opens the input port so that the client can send data to it. The port remains open and
+ * valid until AMidiInputPort_close() is called for the returned AMidiInputPort.
+ *
+ * @param device Specifies the MIDI device.
+ * @param portNumber Specifies the zero-based port index on the device to open. This value ranges
+ * between 0 and one less than the number of input ports reported by the
+ * AMidiDevice_getNumInputPorts() function..
+ * @param outInputPortPtr Receives the native API port identifier of the opened port.
+ *
+ * @return AMEDIA_OK, or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
+ *
+ * Available since API level 29.
+ */
+ AMidiInputPort_open :: proc(device: ^AMidiDevice, portNumber: i32, outInputPortPtr: ^^AMidiInputPort) -> media_status_t ---
+
+ /**
+ * Sends data to the specified input port.
+ *
+ * @param inputPort The identifier of the port to send data to.
+ * @param buffer Points to the array of bytes containing the data to send.
+ * @param numBytes Specifies the number of bytes to write.
+ *
+ * @return The number of bytes sent, which could be less than specified or a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
+ *
+ * Available since API level 29.
+ */
+ AMidiInputPort_send :: proc(inputPort: ^AMidiInputPort, buffer: [^]byte, numBytes: uint) -> int ---
+
+ /**
+ * Sends data to the specified input port with a timestamp.
+ *
+ * @param inputPort The identifier of the port to send data to.
+ * @param buffer Points to the array of bytes containing the data to send.
+ * @param numBytes Specifies the number of bytes to write.
+ * @param timestamp The CLOCK_MONOTONIC time in nanoseconds to associate with the sent data.
+ *
+ * @return The number of bytes sent, which could be less than specified or a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
+ *
+ * Available since API level 29.
+ */
+ AMidiInputPort_sendWithTimestamp :: proc(inputPort: ^AMidiInputPort, buffer: [^]byte, numBytes: uint, timestamp: i64) -> int ---
+
+ /**
+ * Sends a message with a 'MIDI flush command code' to the specified port. This should cause
+ * a receiver to discard any pending MIDI data it may have accumulated and not processed.
+ *
+ * @param inputPort The identifier of the port to send the flush command to.
+ *
+ * @returns @see AMEDIA_OK if successful, otherwise a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL
+ * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
+ * be sent.
+ *
+ * Available since API level 29.
+ */
+ AMidiInputPort_sendFlush :: proc(inputPort: ^AMidiInputPort) -> media_status_t ---
+
+ /**
+ * Closes the input port.
+ *
+ * @param inputPort Identifies the input (sending) port to close.
+ *
+ * Available since API level 29.
+ */
+ AMidiInputPort_close :: proc(inputPort: ^AMidiInputPort) ---
+}
diff --git a/android_native_app_glue.odin b/android_native_app_glue.odin
index 7944dd5..fd40daa 100644
--- a/android_native_app_glue.odin
+++ b/android_native_app_glue.odin
@@ -122,7 +122,6 @@ android_poll_source :: struct {
// Function to call to perform the standard processing of data from
// this source.
- //void (*process)(struct android_app* app, struct android_poll_source* source),
process: #type proc "c" (app: ^android_app, source: ^android_poll_source),
}
diff --git a/media/NdkImage.odin b/media/NdkImage.odin
new file mode 100644
index 0000000..e3316e4
--- /dev/null
+++ b/media/NdkImage.odin
@@ -0,0 +1,784 @@
+//+build android
+package mediandk
+
+import "../"
+
+foreign import mediandk "system:mediandk"
+
+/**
+ * AImage supported formats: AImageReader only guarantees the support for the formats
+ * listed here.
+ */
+AImageFormats :: enum i32 {
+ /**
+ * 32 bits RGBA format, 8 bits for each of the four channels.
+ *
+ *
+ * Corresponding formats:
+ *
+ * - AHardwareBuffer: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
+ * - Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+ * - OpenGL ES: GL_RGBA8
+ *
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see AHardwareBuffer
+ */
+ RGBA_8888 = 0x1,
+
+ /**
+ * 32 bits RGBX format, 8 bits for each of the four channels. The values
+ * of the alpha channel bits are ignored (image is assumed to be opaque).
+ *
+ *
+ * Corresponding formats:
+ *
+ * - AHardwareBuffer: AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM
+ * - Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+ * - OpenGL ES: GL_RGB8
+ *
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see AHardwareBuffer
+ */
+ RGBX_8888 = 0x2,
+
+ /**
+ * 24 bits RGB format, 8 bits for each of the three channels.
+ *
+ *
+ * Corresponding formats:
+ *
+ * - AHardwareBuffer: AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM
+ * - Vulkan: VK_FORMAT_R8G8B8_UNORM
+ * - OpenGL ES: GL_RGB8
+ *
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see AHardwareBuffer
+ */
+ RGB_888 = 0x3,
+
+ /**
+ * 16 bits RGB format, 5 bits for Red channel, 6 bits for Green channel,
+ * and 5 bits for Blue channel.
+ *
+ *
+ * Corresponding formats:
+ *
+ * - AHardwareBuffer: AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM
+ * - Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16
+ * - OpenGL ES: GL_RGB565
+ *
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see AHardwareBuffer
+ */
+ RGB_565 = 0x4,
+
+ /**
+ * 64 bits RGBA format, 16 bits for each of the four channels.
+ *
+ *
+ * Corresponding formats:
+ *
+ * - AHardwareBuffer: AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT
+ * - Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT
+ * - OpenGL ES: GL_RGBA16F
+ *
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see AHardwareBuffer
+ */
+ RGBA_FP16 = 0x16,
+
+ /**
+ * Multi-plane Android YUV 420 format.
+ *
+ * This format is a generic YCbCr format, capable of describing any 4:2:0
+ * chroma-subsampled planar or semiplanar buffer (but not fully interleaved),
+ * with 8 bits per color sample.
+ *
+ * Images in this format are always represented by three separate buffers
+ * of data, one for each color plane. Additional information always
+ * accompanies the buffers, describing the row stride and the pixel stride
+ * for each plane.
+ *
+ * The order of planes is guaranteed such that plane #0 is always Y, plane #1 is always
+ * U (Cb), and plane #2 is always V (Cr).
+ *
+ * The Y-plane is guaranteed not to be interleaved with the U/V planes
+ * (in particular, pixel stride is always 1 in {@link AImage_getPlanePixelStride}).
+ *
+ * The U/V planes are guaranteed to have the same row stride and pixel stride, that is, the
+ * return value of {@link AImage_getPlaneRowStride} for the U/V plane are guaranteed to be the
+ * same, and the return value of {@link AImage_getPlanePixelStride} for the U/V plane are also
+ * guaranteed to be the same.
+ *
+ * For example, the {@link AImage} object can provide data
+ * in this format from a {@link ACameraDevice} through an {@link AImageReader} object.
+ *
+ * This format is always supported as an output format for the android Camera2 NDK API.
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see ACameraDevice
+ */
+ YUV_420_888 = 0x23,
+
+ /**
+ * Compressed JPEG format.
+ *
+ * This format is always supported as an output format for the android Camera2 NDK API.
+ */
+ JPEG = 0x100,
+
+ /**
+ * 16 bits per pixel raw camera sensor image format, usually representing a single-channel
+ * Bayer-mosaic image.
+ *
+ * The layout of the color mosaic, the maximum and minimum encoding
+ * values of the raw pixel data, the color space of the image, and all other
+ * needed information to interpret a raw sensor image must be queried from
+ * the {@link ACameraDevice} which produced the image.
+ */
+ RAW16 = 0x20,
+
+ /**
+ * Private raw camera sensor image format, a single channel image with implementation depedent
+ * pixel layout.
+ *
+ * RAW_PRIVATE is a format for unprocessed raw image buffers coming from an
+ * image sensor. The actual structure of buffers of this format is implementation-dependent.
+ *
+ */
+ RAW_PRIVATE = 0x24,
+
+ /**
+ * Android 10-bit raw format.
+ *
+ *
+ * This is a single-plane, 10-bit per pixel, densely packed (in each row),
+ * unprocessed format, usually representing raw Bayer-pattern images coming
+ * from an image sensor.
+ *
+ *
+ * In an image buffer with this format, starting from the first pixel of
+ * each row, each 4 consecutive pixels are packed into 5 bytes (40 bits).
+ * Each one of the first 4 bytes contains the top 8 bits of each pixel, The
+ * fifth byte contains the 2 least significant bits of the 4 pixels, the
+ * exact layout data for each 4 consecutive pixels is illustrated below
+ * (Pi[j] stands for the jth bit of the ith pixel):
+ *
+ *
+ *
+ * |
+ * bit 7 |
+ * bit 6 |
+ * bit 5 |
+ * bit 4 |
+ * bit 3 |
+ * bit 2 |
+ * bit 1 |
+ * bit 0 |
+ *
+ *
+ * | Byte 0: |
+ * P0[9] |
+ * P0[8] |
+ * P0[7] |
+ * P0[6] |
+ * P0[5] |
+ * P0[4] |
+ * P0[3] |
+ * P0[2] |
+ *
+ *
+ * | Byte 1: |
+ * P1[9] |
+ * P1[8] |
+ * P1[7] |
+ * P1[6] |
+ * P1[5] |
+ * P1[4] |
+ * P1[3] |
+ * P1[2] |
+ *
+ *
+ * | Byte 2: |
+ * P2[9] |
+ * P2[8] |
+ * P2[7] |
+ * P2[6] |
+ * P2[5] |
+ * P2[4] |
+ * P2[3] |
+ * P2[2] |
+ *
+ *
+ * | Byte 3: |
+ * P3[9] |
+ * P3[8] |
+ * P3[7] |
+ * P3[6] |
+ * P3[5] |
+ * P3[4] |
+ * P3[3] |
+ * P3[2] |
+ *
+ *
+ * | Byte 4: |
+ * P3[1] |
+ * P3[0] |
+ * P2[1] |
+ * P2[0] |
+ * P1[1] |
+ * P1[0] |
+ * P0[1] |
+ * P0[0] |
+ *
+ *
+ *
+ * This format assumes
+ *
+ * - a width multiple of 4 pixels
+ * - an even height
+ *
+ *
+ *
+ * size = row stride * height
where the row stride is in bytes,
+ * not pixels.
+ *
+ *
+ * Since this is a densely packed format, the pixel stride is always 0. The
+ * application must use the pixel data layout defined in above table to
+ * access each row data. When row stride is equal to (width * (10 / 8)), there
+ * will be no padding bytes at the end of each row, the entire image data is
+ * densely packed. When stride is larger than (width * (10 / 8)), padding
+ * bytes will be present at the end of each row.
+ *
+ *
+ * For example, the {@link AImage} object can provide data in this format from a
+ * {@link ACameraDevice} (if supported) through a {@link AImageReader} object.
+ * The number of planes returned by {@link AImage_getNumberOfPlanes} will always be 1.
+ * The pixel stride is undefined ({@link AImage_getPlanePixelStride} will return
+ * {@link AMEDIA_ERROR_UNSUPPORTED}), and the {@link AImage_getPlaneRowStride} described the
+ * vertical neighboring pixel distance (in bytes) between adjacent rows.
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see ACameraDevice
+ */
+ RAW10 = 0x25,
+
+ /**
+ * Android 12-bit raw format.
+ *
+ *
+ * This is a single-plane, 12-bit per pixel, densely packed (in each row),
+ * unprocessed format, usually representing raw Bayer-pattern images coming
+ * from an image sensor.
+ *
+ *
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+ * and second byte contains the top 8 bits of first and second pixel. The third
+ * byte contains the 4 least significant bits of the two pixels, the exact layout
+ * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+ * the jth bit of the ith pixel):
+ *
+ *
+ *
+ * |
+ * bit 7 |
+ * bit 6 |
+ * bit 5 |
+ * bit 4 |
+ * bit 3 |
+ * bit 2 |
+ * bit 1 |
+ * bit 0 |
+ *
+ *
+ * | Byte 0: |
+ * P0[11] |
+ * P0[10] |
+ * P0[ 9] |
+ * P0[ 8] |
+ * P0[ 7] |
+ * P0[ 6] |
+ * P0[ 5] |
+ * P0[ 4] |
+ *
+ *
+ * | Byte 1: |
+ * P1[11] |
+ * P1[10] |
+ * P1[ 9] |
+ * P1[ 8] |
+ * P1[ 7] |
+ * P1[ 6] |
+ * P1[ 5] |
+ * P1[ 4] |
+ *
+ *
+ * | Byte 2: |
+ * P1[ 3] |
+ * P1[ 2] |
+ * P1[ 1] |
+ * P1[ 0] |
+ * P0[ 3] |
+ * P0[ 2] |
+ * P0[ 1] |
+ * P0[ 0] |
+ *
+ *
+ *
+ * This format assumes
+ *
+ * - a width multiple of 4 pixels
+ * - an even height
+ *
+ *
+ *
+ * size = row stride * height
where the row stride is in bytes,
+ * not pixels.
+ *
+ *
+ * Since this is a densely packed format, the pixel stride is always 0. The
+ * application must use the pixel data layout defined in above table to
+ * access each row data. When row stride is equal to (width * (12 / 8)), there
+ * will be no padding bytes at the end of each row, the entire image data is
+ * densely packed. When stride is larger than (width * (12 / 8)), padding
+ * bytes will be present at the end of each row.
+ *
+ *
+ * For example, the {@link AImage} object can provide data in this format from a
+ * {@link ACameraDevice} (if supported) through a {@link AImageReader} object.
+ * The number of planes returned by {@link AImage_getNumberOfPlanes} will always be 1.
+ * The pixel stride is undefined ({@link AImage_getPlanePixelStride} will return
+ * {@link AMEDIA_ERROR_UNSUPPORTED}), and the {@link AImage_getPlaneRowStride} described the
+ * vertical neighboring pixel distance (in bytes) between adjacent rows.
+ *
+ *
+ * @see AImage
+ * @see AImageReader
+ * @see ACameraDevice
+ */
+ RAW12 = 0x26,
+
+ /**
+ * Android dense depth image format.
+ *
+ * Each pixel is 16 bits, representing a depth ranging measurement from a depth camera or
+ * similar sensor. The 16-bit sample consists of a confidence value and the actual ranging
+ * measurement.
+ *
+ * The confidence value is an estimate of correctness for this sample. It is encoded in the
+ * 3 most significant bits of the sample, with a value of 0 representing 100% confidence, a
+ * value of 1 representing 0% confidence, a value of 2 representing 1/7, a value of 3
+ * representing 2/7, and so on.
+ *
+ * As an example, the following sample extracts the range and confidence from the first pixel
+ * of a DEPTH16-format {@link AImage}, and converts the confidence to a floating-point value
+ * between 0 and 1.f inclusive, with 1.f representing maximum confidence:
+ *
+ *
+ * uint16_t* data;
+ * int dataLength;
+ * AImage_getPlaneData(image, 0, (uint8_t**)&data, &dataLength);
+ * uint16_t depthSample = data[0];
+ * uint16_t depthRange = (depthSample & 0x1FFF);
+ * uint16_t depthConfidence = ((depthSample >> 13) & 0x7);
+ * float depthPercentage = depthConfidence == 0 ? 1.f : (depthConfidence - 1) / 7.f;
+ *
+ *
+ *
+ * This format assumes
+ *
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ *
+ *
+ *
+ * y_size = stride * height
+ *
+ * When produced by a camera, the units for the range are millimeters.
+ */
+ DEPTH16 = 0x44363159,
+
+ /**
+ * Android sparse depth point cloud format.
+ *
+ * A variable-length list of 3D points plus a confidence value, with each point represented
+ * by four floats; first the X, Y, Z position coordinates, and then the confidence value.
+ *
+ * The number of points is ((size of the buffer in bytes) / 16).
+ *
+ *
The coordinate system and units of the position values depend on the source of the point
+ * cloud data. The confidence value is between 0.f and 1.f, inclusive, with 0 representing 0%
+ * confidence and 1.f representing 100% confidence in the measured position values.
+ *
+ * As an example, the following code extracts the first depth point in a DEPTH_POINT_CLOUD
+ * format {@link AImage}:
+ *
+ * float* data;
+ * int dataLength;
+ * AImage_getPlaneData(image, 0, (uint8_t**)&data, &dataLength);
+ * float x = data[0];
+ * float y = data[1];
+ * float z = data[2];
+ * float confidence = data[3];
+ *
+ *
+ */
+ DEPTH_POINT_CLOUD = 0x101,
+
+ /**
+ * Android private opaque image format.
+ *
+ * The choices of the actual format and pixel data layout are entirely up to the
+ * device-specific and framework internal implementations, and may vary depending on use cases
+ * even for the same device. Also note that the contents of these buffers are not directly
+ * accessible to the application.
+ *
+ * When an {@link AImage} of this format is obtained from an {@link AImageReader} or
+ * {@link AImage_getNumberOfPlanes()} method will return zero.
+ */
+ PRIVATE = 0x22,
+
+ /**
+ * Android Y8 format.
+ *
+ * Y8 is a planar format comprised of a WxH Y plane only, with each pixel
+ * being represented by 8 bits.
+ *
+ * This format assumes
+ *
+ * - an even width
+ * - an even height
+ * - a horizontal stride multiple of 16 pixels
+ *
+ *
+ *
+ * size = stride * height
+ *
+ * For example, the {@link AImage} object can provide data
+ * in this format from a {@link ACameraDevice} (if supported) through a
+ * {@link AImageReader} object. The number of planes returned by
+ * {@link AImage_getNumberOfPlanes} will always be 1. The pixel stride returned by
+ * {@link AImage_getPlanePixelStride} will always be 1, and the
+ * {@link AImage_getPlaneRowStride} described the vertical neighboring pixel distance
+ * (in bytes) between adjacent rows.
+ *
+ */
+ Y8 = 0x20203859,
+
+ /**
+ * Compressed HEIC format.
+ *
+ * This format defines the HEIC brand of High Efficiency Image File
+ * Format as described in ISO/IEC 23008-12.
+ */
+ HEIC = 0x48454946,
+
+ /**
+ * Depth augmented compressed JPEG format.
+ *
+ * JPEG compressed main image along with XMP embedded depth metadata
+ * following ISO 16684-1:2011(E).
+ */
+ DEPTH_JPEG = 0x69656963,
+}
+
+/**
+ * AImage is an opaque type that provides access to image generated by {@link AImageReader}.
+ */
+AImage :: struct{}
+
+/**
+ * Data type describing an cropped rectangle returned by {@link AImage_getCropRect}.
+ *
+ * Note that the right and bottom coordinates are exclusive, so the width of the rectangle is
+ * (right - left) and the height of the rectangle is (bottom - top).
+ */
+AImageCropRect :: struct {
+ left: i32,
+ top: i32,
+ right: i32,
+ bottom: i32,
+}
+
+foreign mediandk {
+ /**
+ * Return the image back the the system and delete the AImage object from memory.
+ *
+ * Do NOT use the image pointer after this method returns.
+ * Note that if the parent {@link AImageReader} is closed, all the {@link AImage} objects acquired
+ * from the parent reader will be returned to system. All AImage_* methods except this method will
+ * return {@link AMEDIA_ERROR_INVALID_OBJECT}. Application still needs to call this method on those
+ * {@link AImage} objects to fully delete the {@link AImage} object from memory.
+ *
+ * Available since API level 24.
+ *
+ * @param image The {@link AImage} to be deleted.
+ */
+ AImage_delete :: proc(image: ^AImage) ---
+
+ /**
+ * Query the width of the input {@link AImage}.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param width the width of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or width is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getWidth :: proc(image: ^AImage, width: ^i32) -> media_status_t ---
+
+ /**
+ * Query the height of the input {@link AImage}.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param height the height of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or height is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getHeight :: proc(image: ^AImage, height: ^i32) -> media_status_t ---
+
+ /**
+ * Query the format of the input {@link AImage}.
+ *
+ * The format value will be one of AIMAGE_FORMAT_* enum value.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param format the format of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or format is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getFormat :: proc(image: ^AImage, format: ^AImageFormats) -> media_status_t ---
+
+ /**
+ * Query the cropped rectangle of the input {@link AImage}.
+ *
+ * The crop rectangle specifies the region of valid pixels in the image, using coordinates in the
+ * largest-resolution plane.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param rect the cropped rectangle of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or rect is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getCropRect :: proc(image: ^AImage, rect: ^AImageCropRect) -> media_status_t ---
+
+ /**
+ * Query the timestamp of the input {@link AImage}.
+ *
+ *
+ * The timestamp is measured in nanoseconds, and is normally monotonically increasing. The
+ * timestamps for the images from different sources may have different timebases therefore may not
+ * be comparable. The specific meaning and timebase of the timestamp depend on the source providing
+ * images. For images generated by camera, the timestamp value will match
+ * {@link ACAMERA_SENSOR_TIMESTAMP} of the {@link ACameraMetadata} in
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted} and
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
+ *
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param timestampNs the timestamp of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or timestampNs is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getTimestamp :: proc(image: ^AImage, timestampNs: ^i64) -> media_status_t ---
+
+ /**
+ * Query the number of planes of the input {@link AImage}.
+ *
+ * The number of plane of an {@link AImage} is determined by its format, which can be queried by
+ * {@link AImage_getFormat} method.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param numPlanes the number of planes of the image will be filled here if the method call
+ * succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or numPlanes is NULL.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ */
+ AImage_getNumberOfPlanes :: proc(image: ^AImage, numPlanes: ^i32) -> media_status_t ---
+
+ /**
+ * Query the pixel stride of the input {@link AImage}.
+ *
+ * This is the distance between two consecutive pixel values in a row of pixels. It may be
+ * larger than the size of a single pixel to account for interleaved image data or padded formats.
+ * Note that pixel stride is undefined for some formats such as {@link AIMAGE_FORMAT_RAW_PRIVATE},
+ * and calling this method on images of these formats will cause {@link AMEDIA_ERROR_UNSUPPORTED}
+ * being returned.
+ * For formats where pixel stride is well defined, the pixel stride is always greater than 0.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
+ * @param pixelStride the pixel stride of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or pixelStride is NULL, or planeIdx
+ * is out of the range of [0, numOfPlanes - 1].
+ * - {@link AMEDIA_ERROR_UNSUPPORTED} if pixel stride is undefined for the format of input
+ * image.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ * - {@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ * for CPU access.
+ */
+ AImage_getPlanePixelStride :: proc(image: ^AImage, planeIdx: i32, pixelStride: ^i32) -> media_status_t ---
+
+ /**
+ * Query the row stride of the input {@link AImage}.
+ *
+ * This is the distance between the start of two consecutive rows of pixels in the image. Note
+ * that row stried is undefined for some formats such as {@link AIMAGE_FORMAT_RAW_PRIVATE}, and
+ * calling this method on images of these formats will cause {@link AMEDIA_ERROR_UNSUPPORTED}
+ * being returned.
+ * For formats where row stride is well defined, the row stride is always greater than 0.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
+ * @param rowStride the row stride of the image will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or rowStride is NULL, or planeIdx
+ * is out of the range of [0, numOfPlanes - 1].
+ * - {@link AMEDIA_ERROR_UNSUPPORTED} if row stride is undefined for the format of input
+ * image.
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ * - {@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ * for CPU access.
+ */
+ AImage_getPlaneRowStride :: proc(image: ^AImage, planeIdx: i32, rowStride: ^i32) -> media_status_t ---
+
+ /**
+ * Get the data pointer of the input image for direct application access.
+ *
+ * Note that once the {@link AImage} or the parent {@link AImageReader} is deleted, the data
+ * pointer from previous AImage_getPlaneData call becomes invalid. Do NOT use it after the
+ * {@link AImage} or the parent {@link AImageReader} is deleted.
+ *
+ * Available since API level 24.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
+ * @param data the data pointer of the image will be filled here if the method call succeeeds.
+ * @param dataLength the valid length of data will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image, data or dataLength is NULL, or
+ * planeIdx is out of the range of [0, numOfPlanes - 1].
+ * - {@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
+ * image has been deleted.
+ * - {@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ * for CPU access.
+ */
+ AImage_getPlaneData :: proc(image: ^AImage, planeIdx: i32, data: ^[^]u8, dataLength: ^i32) -> media_status_t ---
+
+ /**
+ * Return the image back the the system and delete the AImage object from memory asynchronously.
+ *
+ * Similar to {@link AImage_delete}, do NOT use the image pointer after this method returns.
+ * However, the caller can still hold on to the {@link AHardwareBuffer} returned from this image and
+ * signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
+ * releaseFenceFd.
+ *
+ * Available since API level 26.
+ *
+ * @param image The {@link AImage} to be deleted.
+ * @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
+ * underlying {@link AHardwareBuffer}.
+ *
+ * @see sync.h
+ */
+ AImage_deleteAsync :: proc(image: ^AImage, releaseFenceFd: i32) ---
+
+ /**
+ * Get the hardware buffer handle of the input image intended for GPU and/or hardware access.
+ *
+ * Note that no reference on the returned {@link AHardwareBuffer} handle is acquired
+ * automatically. Once the {@link AImage} or the parent {@link AImageReader} is deleted, the
+ * {@link AHardwareBuffer} handle from previous {@link AImage_getHardwareBuffer} becomes
+ * invalid.
+ *
+ * If the caller ever needs to hold on a reference to the {@link AHardwareBuffer} handle after
+ * the {@link AImage} or the parent {@link AImageReader} is deleted, it must call {@link
+ * AHardwareBuffer_acquire} to acquire an extra reference, and call {@link AHardwareBuffer_release}
+ * once it has finished using it in order to properly deallocate the underlying memory managed by
+ * {@link AHardwareBuffer}. If the caller has acquired extra reference on an {@link AHardwareBuffer}
+ * returned from this function, it must also register a listener using the function
+ * {@link AImageReader_setBufferRemovedListener} to be notified when the buffer is no longer used
+ * by {@link AImageReader}.
+ *
+ * Available since API level 26.
+ *
+ * @param image the {@link AImage} of interest.
+ * @param buffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
+ * handle.
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if image or buffer is NULL
+ *
+ * @see AImageReader_ImageCallback
+ */
+ AImage_getHardwareBuffer :: proc(image: ^AImage, buffer: ^^android.AHardwareBuffer) -> media_status_t ---
+}
diff --git a/media/NdkImageReader.odin b/media/NdkImageReader.odin
new file mode 100644
index 0000000..b499f53
--- /dev/null
+++ b/media/NdkImageReader.odin
@@ -0,0 +1,443 @@
+//+build android
+package mediandk
+
+import "../"
+
+foreign import mediandk "system:mediandk"
+
+/**
+ * AImage is an opaque type that allows direct application access to image data rendered into a
+ * {@link ANativeWindow}.
+ */
+AImageReader :: struct{}
+
+AImageReader_ImageListener :: struct {
+ /// Optional application context passed as the first parameter of the callback.
+ _context: rawptr,
+
+ /**
+ * This callback is called when there is a new image available in the image reader's queue.
+ *
+ * The callback happens on one dedicated thread per {@link AImageReader} instance. It is okay
+ * to use AImageReader_* and AImage_* methods within the callback. Note that it is possible that
+ * calling {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}
+ * returns {@link AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE} within this callback. For example, when
+ * there are multiple images and callbacks queued, if application called
+ * {@link AImageReader_acquireLatestImage}, some images will be returned to system before their
+ * corresponding callback is executed.
+ */
+ onImageAvailable: AImageReader_ImageCallback,
+}
+
+/**
+* A listener to the AHardwareBuffer removal event, use
+* {@link AImageReader_setBufferRemovedListener} to register the listener object to AImageReader.
+*/
+AImageReader_BufferRemovedListener :: struct {
+ /// Optional application context passed as the first parameter of the callback.
+ _context: rawptr,
+
+ /**
+ * This callback is called when an old {@link AHardwareBuffer} is about to be removed from the
+ * image reader.
+ *
+ * Note that registering this callback is optional unless the user holds on extra reference
+ * to {@link AHardwareBuffer} returned from {@link AImage_getHardwareBuffer} by calling {@link
+ * AHardwareBuffer_acquire} or creating external graphic objects, such as EglImage, from it.
+ *
+ * If the callback is registered, the {@link AImageReader} will hold on the last of its
+ * references to the {@link AHardwareBuffer} until this callback returns. User can use the
+ * callback to get notified that it becomes the last owner of the buffer. It is up to the user
+ * to decide to either 1) immediately release all of its references to the buffer or 2) keep
+ * using the buffer and release it in future. Note that, if option 2 if used, user of this API
+ * is responsible to deallocate the buffer properly by calling {@link AHardwareBuffer_release}.
+ *
+ *
+ * @see AHardwareBuffer_release
+ * @see AImage_getHardwareBuffer
+ */
+ onBufferRemoved: AImageReader_BufferRemovedCallback,
+}
+
+/**
+* Signature of the callback which is called when a new image is available from {@link AImageReader}.
+*
+* @param context The optional application context provided by user in
+* {@link AImageReader_setImageListener}.
+* @param session The camera capture session whose state is changing.
+*/
+AImageReader_ImageCallback :: #type proc "c" (_context: rawptr, reader: ^AImageReader)
+
+/**
+* Signature of the callback which is called when {@link AImageReader} is about to remove a buffer.
+*
+* @param context The optional application context provided by user in
+* {@link AImageReader_setBufferRemovedListener}.
+* @param reader The {@link AImageReader} of interest.
+* @param buffer The {@link AHardwareBuffer} that is being removed from this image reader.
+*/
+AImageReader_BufferRemovedCallback :: #type proc "c" (_context: rawptr, reader: ^AImageReader, buffer: ^android.AHardwareBuffer)
+
+foreign mediandk {
+ /**
+ * Create a new reader for images of the desired size and format.
+ *
+ *
+ * The maxImages parameter determines the maximum number of {@link AImage} objects that can be
+ * acquired from the {@link AImageReader} simultaneously. Requesting more buffers will use up
+ * more memory, so it is important to use only the minimum number necessary for the use case.
+ *
+ *
+ * The valid sizes and formats depend on the source of the image data.
+ *
+ *
+ * Available since API level 24.
+ *
+ * @param width The default width in pixels of the Images that this reader will produce.
+ * @param height The default height in pixels of the Images that this reader will produce.
+ * @param format The format of the Image that this reader will produce. This must be one of the
+ * AIMAGE_FORMAT_* enum value defined in {@link AIMAGE_FORMATS}. Note that not all
+ * formats are supported. One example is {@link AIMAGE_FORMAT_PRIVATE}, as it is not
+ * intended to be read by applications directly. That format is supported by
+ * {@link AImageReader_newWithUsage} introduced in API 26.
+ * @param maxImages The maximum number of images the user will want to access simultaneously. This
+ * should be as small as possible to limit memory use. Once maxImages Images are obtained
+ * by the user, one of them has to be released before a new {@link AImage} will become
+ * available for access through {@link AImageReader_acquireLatestImage} or
+ * {@link AImageReader_acquireNextImage}. Must be greater than 0.
+ * @param reader The created image reader will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
+ * height, format, maxImages arguments is not supported.
+ * - {@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.
+ *
+ * @see AImage
+ */
+ AImageReader_new :: proc(width: i32, height: i32, format: AImageFormats, maxImages: i32, reader: ^^AImageReader) -> media_status_t ---
+
+ /**
+ * Delete an {@link AImageReader} and return all images generated by this reader to system.
+ *
+ * This method will return all {@link AImage} objects acquired by this reader (via
+ * {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}) to system,
+ * making any of data pointers obtained from {@link AImage_getPlaneData} invalid. Do NOT access
+ * the reader object or any of those data pointers after this method returns.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader to be deleted.
+ */
+ AImageReader_delete :: proc(reader: ^AImageReader) ---
+
+ /**
+ * Get a {@link ANativeWindow} that can be used to produce {@link AImage} for this image reader.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param window The output {@link ANativeWindow} will be filled here if the method call succeeds.
+ * The {@link ANativeWindow} is managed by this image reader. Do NOT call
+ * {@link ANativeWindow_release} on it. Instead, use {@link AImageReader_delete}.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or window is NULL.
+ */
+ AImageReader_getWindow :: proc(reader: ^AImageReader, window: ^^android.ANativeWindow) -> media_status_t ---
+
+ /**
+ * Query the default width of the {@link AImage} generated by this reader, in pixels.
+ *
+ * The width may be overridden by the producer sending buffers to this reader's
+ * {@link ANativeWindow}. If so, the actual width of the images can be found using
+ * {@link AImage_getWidth}.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param width the default width of the reader will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or width is NULL.
+ */
+ AImageReader_getWidth :: proc(reader: ^AImageReader, width: ^i32) -> media_status_t ---
+
+ /**
+ * Query the default height of the {@link AImage} generated by this reader, in pixels.
+ *
+ * The height may be overridden by the producer sending buffers to this reader's
+ * {@link ANativeWindow}. If so, the actual height of the images can be found using
+ * {@link AImage_getHeight}.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param height the default height of the reader will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or height is NULL.
+ */
+ AImageReader_getHeight :: proc(reader: ^AImageReader, height: ^i32) -> media_status_t ---
+
+ /**
+ * Query the format of the {@link AImage} generated by this reader.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param format the fromat of the reader will be filled here if the method call succeeeds. The
+ * value will be one of the AIMAGE_FORMAT_* enum value defiend in {@link NdkImage.h}.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or format is NULL.
+ */
+ AImageReader_getFormat :: proc(reader: ^AImageReader, format: ^AImageFormats) -> media_status_t ---
+
+ /**
+ * Query the maximum number of concurrently acquired {@link AImage}s of this reader.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param maxImages the maximum number of concurrently acquired images of the reader will be filled
+ * here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or maxImages is NULL.
+ */
+ AImageReader_getMaxImages :: proc(reader: ^AImageReader, maxImages: ^i32) -> media_status_t ---
+
+ /**
+ * Acquire the next {@link AImage} from the image reader's queue.
+ *
+ * Warning: Consider using {@link AImageReader_acquireLatestImage} instead, as it will
+ * automatically release older images, and allow slower-running processing routines to catch
+ * up to the newest frame. Usage of {@link AImageReader_acquireNextImage} is recommended for
+ * batch/background processing. Incorrectly using this method can cause images to appear
+ * with an ever-increasing delay, followed by a complete stall where no new images seem to appear.
+ *
+ *
+ *
+ * This method will fail if {@link AImageReader_getMaxImages maxImages} have been acquired with
+ * {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}. In particular
+ * a sequence of {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}
+ * calls greater than {@link AImageReader_getMaxImages maxImages} without calling
+ * {@link AImage_delete} in-between will exhaust the underlying queue. At such a time,
+ * {@link AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED} will be returned until more images are released with
+ * {@link AImage_delete}.
+ *
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or image is NULL.
+ * - {@link AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED} if the number of concurrently acquired
+ * images has reached the limit.
+ * - {@link AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE} if there is no buffers currently
+ * available in the reader queue.
+ * - {@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.
+ *
+ * @see AImageReader_acquireLatestImage
+ */
+ AImageReader_acquireNextImage :: proc(reader: ^AImageReader, image: ^^AImage) -> media_status_t ---
+
+ /**
+ * Acquire the latest {@link AImage} from the image reader's queue, dropping older images.
+ *
+ *
+ * This operation will acquire all the images possible from the image reader, but
+ * {@link AImage_delete} all images that aren't the latest. This function is recommended to use over
+ * {@link AImageReader_acquireNextImage} for most use-cases, as it's more suited for real-time
+ * processing.
+ *
+ *
+ * Note that {@link AImageReader_getMaxImages maxImages} should be at least 2 for
+ * {@link AImageReader_acquireLatestImage} to be any different than
+ * {@link AImageReader_acquireNextImage} - discarding all-but-the-newest {@link AImage} requires
+ * temporarily acquiring two {@link AImage}s at once. Or more generally, calling
+ * {@link AImageReader_acquireLatestImage} with less than two images of margin, that is
+ * (maxImages - currentAcquiredImages < 2) will not discard as expected.
+ *
+ *
+ * This method will fail if {@link AImageReader_getMaxImages maxImages} have been acquired with
+ * {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}. In particular
+ * a sequence of {@link AImageReader_acquireNextImage} or {@link AImageReader_acquireLatestImage}
+ * calls greater than {@link AImageReader_getMaxImages maxImages} without calling
+ * {@link AImage_delete} in-between will exhaust the underlying queue. At such a time,
+ * {@link AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED} will be returned until more images are released with
+ * {@link AImage_delete}.
+ *
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader or image is NULL.
+ * - {@link AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED} if the number of concurrently acquired
+ * images has reached the limit.
+ * - {@link AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE} if there is no buffers currently
+ * available in the reader queue.
+ * - {@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.
+ *
+ * @see AImageReader_acquireNextImage
+ */
+ AImageReader_acquireLatestImage :: proc(reader: ^AImageReader, image: ^^AImage) -> media_status_t ---
+
+
+ /**
+ * Set the onImageAvailable listener of this image reader.
+ *
+ * Calling this method will replace previously registered listeners.
+ *
+ * Available since API level 24.
+ *
+ * @param reader The image reader of interest.
+ * @param listener The {@link AImageReader_ImageListener} to be registered. Set this to NULL if
+ * the application no longer needs to listen to new images.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.
+ */
+ AImageReader_setImageListener :: proc(reader: ^AImageReader, listener: ^AImageReader_ImageListener) -> media_status_t ---
+
+ /**
+ * AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
+ * for the consumer usage. All other parameters and the return values are identical to those passed
+ * to {@link AImageReader_new}.
+ *
+ * If the \c format is {@link AIMAGE_FORMAT_PRIVATE}, the created {@link AImageReader}
+ * will produce images whose contents are not directly accessible by the application. The application can
+ * still acquire images from this {@link AImageReader} and access {@link AHardwareBuffer} via
+ * {@link AImage_getHardwareBuffer()}. The {@link AHardwareBuffer} gained this way can then
+ * be passed back to hardware (such as GPU or hardware encoder if supported) for future processing.
+ * For example, you can obtain an EGLClientBuffer from the {@link AHardwareBuffer} by using
+ * eglGetNativeClientBufferANDROID extension and pass that EGLClientBuffer to
+ * eglCreateImageKHR to create an EGLImage resource type, which may then be bound to a
+ * texture via glEGLImageTargetTexture2DOES on supported devices. This can be useful for
+ * transporting textures that may be shared cross-process.
+ * In general, when software access to image data is not necessary, an {@link AImageReader}
+ * created with {@link AIMAGE_FORMAT_PRIVATE} format is more efficient, compared with {@link
+ * AImageReader}s using other format such as {@link AIMAGE_FORMAT_YUV_420_888}.
+ *
+ * Note that not all format and usage flag combination is supported by the {@link AImageReader},
+ * especially if \c format is {@link AIMAGE_FORMAT_PRIVATE}, \c usage must not include either
+ * {@link AHARDWAREBUFFER_USAGE_CPU_READ_RARELY} or {@link AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}
+ *
+ * @param width The default width in pixels of the Images that this reader will produce.
+ * @param height The default height in pixels of the Images that this reader will produce.
+ * @param format The format of the Image that this reader will produce. This must be one of the
+ * AIMAGE_FORMAT_* enum value defined in {@link AIMAGE_FORMATS}.
+ * @param usage specifies how the consumer will access the AImage, using combination of the
+ * AHARDWAREBUFFER_USAGE flags described in {@link hardware_buffer.h}.
+ * Passing {@link AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN} is equivalent to calling
+ * {@link AImageReader_new} with the same parameters.
+ *
+ * Note that not all format and usage flag combination is supported by the {@link AImageReader}.
+ * Below are the combinations supported by the {@link AImageReader}.
+ *
+ *
+ * | Format |
+ * Compatible usage flags |
+ *
+ *
+ * | non-{@link AIMAGE_FORMAT_PRIVATE} formats defined in {@link NdkImage.h}
+ * |
+ * {@link AHARDWAREBUFFER_USAGE_CPU_READ_RARELY} or
+ * {@link AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN} |
+ *
+ *
+ * | {@link AIMAGE_FORMAT_RGBA_8888} |
+ * {@link AHARDWAREBUFFER_USAGE_VIDEO_ENCODE} or
+ * {@link AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE}, or combined |
+ *
+ *
+ *
+ * Available since API level 26.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
+ * height, format, maxImages, or usage arguments is not supported.
+ * - {@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.
+ *
+ * @see AImage
+ * @see AImageReader_new
+ * @see AHardwareBuffer
+ */
+ AImageReader_newWithUsage :: proc(width: i32, height: i32, format: AImageFormats, usage: u64, maxImages: i32, reader: ^^AImageReader) -> media_status_t ---
+
+ /**
+ * Acquire the next {@link AImage} from the image reader's queue asynchronously.
+ *
+ * AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireNextImage}.
+ *
+ * Available since API level 26.
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ * buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ * to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ * use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
+ * fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+ AImageReader_acquireNextImageAsync :: proc(reader: ^AImageReader, image: ^^AImage, acquireFenceFd: ^i32) -> media_status_t ---
+
+ /**
+ * Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
+ * images.
+ *
+ * AImageReader acquire method similar to {@link AImageReader_acquireLatestImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireLatestImage}.
+ *
+ * Available since API level 26.
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ * buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ * to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ * use syscalls such as \c poll(), \c epoll(), \c select() to wait for the
+ * fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+ AImageReader_acquireLatestImageAsync :: proc(reader: ^AImageReader, image: ^^AImage, acquireFenceFd: ^i32) -> media_status_t ---
+
+
+ /**
+ * Set the onBufferRemoved listener of this image reader.
+ *
+ * Note that calling this method will replace previously registered listeners.
+ *
+ * Available since API level 26.
+ *
+ * @param reader The image reader of interest.
+ * @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
+ * NULL if application no longer needs to listen to buffer removed events.
+ *
+ * @return
+ * - {@link AMEDIA_OK} if the method call succeeds.
+ * - {@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.
+ *
+ * @see AImage_getHardwareBuffer
+ */
+ AImageReader_setBufferRemovedListener :: proc(reader: ^AImageReader, listener: ^AImageReader_BufferRemovedListener) -> media_status_t ---
+}
diff --git a/media/NdkMediaCodec.odin b/media/NdkMediaCodec.odin
new file mode 100644
index 0000000..7dcf41c
--- /dev/null
+++ b/media/NdkMediaCodec.odin
@@ -0,0 +1,560 @@
+//+build android
+package mediandk
+
+import android "../"
+
+foreign import mediandk "system:android"
+
+AMEDIACODEC_KEY_HDR10_PLUS_INFO: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_LOW_LATENCY: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_OFFSET_TIME: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_REQUEST_SYNC_FRAME: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_SUSPEND: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_SUSPEND_TIME: cstring // __INTRODUCED_IN(31);
+AMEDIACODEC_KEY_VIDEO_BITRATE: cstring // __INTRODUCED_IN(31);
+
+
+AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG :: 2
+AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM :: 4
+AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME :: 8
+
+AMEDIACODEC_CONFIGURE_FLAG_ENCODE :: 1
+AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED :: -3
+AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED :: -2
+AMEDIACODEC_INFO_TRY_AGAIN_LATER :: -1
+
+_off_t_compat :: i64
+
+cryptoinfo_mode_t :: enum {
+ CLEAR = 0,
+ AES_CTR = 1,
+ AES_WV = 2,
+ AES_CBC = 3
+}
+
+AMediaCodec :: struct{}
+
+AMediaCodecBufferInfo :: struct {
+ offset: i32,
+ size: i32,
+ presentationTimeUs: i64,
+ flags: u32,
+}
+
+AMediaCodecCryptoInfo :: struct{}
+
+AMediaCodecOnAsyncNotifyCallback :: struct {
+ onAsyncInputAvailable: AMediaCodecOnAsyncInputAvailable,
+ onAsyncOutputAvailable: AMediaCodecOnAsyncOutputAvailable,
+ onAsyncFormatChanged: AMediaCodecOnAsyncFormatChanged,
+ onAsyncError: AMediaCodecOnAsyncError,
+}
+
+cryptoinfo_pattern_t :: struct {
+ encryptBlocks: i32,
+ skipBlocks: i32,
+}
+
+/**
+ * Called when an input buffer becomes available.
+ * The specified index is the index of the available input buffer.
+ */
+AMediaCodecOnAsyncInputAvailable :: #type proc "c" (codec: ^AMediaCodec, userdata: rawptr, index: i32)
+/**
+ * Called when an output buffer becomes available.
+ * The specified index is the index of the available output buffer.
+ * The specified bufferInfo contains information regarding the available output buffer.
+ */
+AMediaCodecOnAsyncOutputAvailable :: #type proc "c" (codec: ^AMediaCodec, userdata: rawptr, index: i32, bufferInfo: ^AMediaCodecBufferInfo)
+/**
+ * Called when the output format has changed.
+ * The specified format contains the new output format.
+ */
+AMediaCodecOnAsyncFormatChanged :: #type proc "c" (codec: ^AMediaCodec, userdata: rawptr, format: ^AMediaFormat)
+/**
+ * Called when the MediaCodec encountered an error.
+ * The specified actionCode indicates the possible actions that client can take,
+ * and it can be checked by calling AMediaCodecActionCode_isRecoverable or
+ * AMediaCodecActionCode_isTransient. If both AMediaCodecActionCode_isRecoverable()
+ * and AMediaCodecActionCode_isTransient() return false, then the codec error is fatal
+ * and the codec must be deleted.
+ * The specified detail may contain more detailed messages about this error.
+ */
+AMediaCodecOnAsyncError :: #type proc "c" (
+ codec: ^AMediaCodec,
+ userdata: rawptr,
+ error: media_status_t,
+ actionCode: i32,
+ detail: cstring
+)
+
+/**
+ * Called when an output frame has rendered on the output surface.
+ *
+ * \param codec The codec object that generated this notification.
+ * \param userdata The user data set at AMediaCodec_setOnFrameRenderedCallback.
+ * \param mediaTimeUs The presentation time (media time) of the frame rendered.
+ * This is usually the same as specified in
+ * AMediaCodec_queueInputBuffer, but some codecs may alter
+ * the media time by applying some time-based transformation,
+ * such as frame rate conversion. In that case, presentation
+ * time corresponds to the actual output frame rendered.
+ * \param systemNano The system time when the frame was rendered.
+ */
+AMediaCodecOnFrameRendered :: #type proc "c" (
+ codec: ^AMediaCodec,
+ userdata: rawptr,
+ mediaTimeUs: i64,
+ systemNano: i64,
+)
+
+foreign mediandk {
+ /**
+ * Create codec by name. Use this if you know the exact codec you want to use.
+ * When configuring, you will need to specify whether to use the codec as an
+ * encoder or decoder.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_createCodecByName :: proc(name: cstring) -> ^AMediaCodec ---
+
+ /**
+ * Create codec by mime type. Most applications will use this, specifying a
+ * mime type obtained from media extractor.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_createDecoderByType :: proc(mime_type: cstring) -> ^AMediaCodec ---
+
+ /**
+ * Create encoder by name.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_createEncoderByType :: proc(mime_type: cstring) -> ^AMediaCodec ---
+
+ /**
+ * Delete the codec and free its resources.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_delete :: proc(codec: ^AMediaCodec) -> media_status_t ---
+
+ /**
+ * Configure the codec. For decoding you would typically get the format from an extractor.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_configure :: proc(coded: ^AMediaCodec, format: ^AMediaFormat, surface: ^android.ANativeWindow, crypto: ^AMediaCrypto, flags: u32) -> media_status_t ---
+
+ /**
+ * Start the codec. A codec must be configured before it can be started, and must be started
+ * before buffers can be sent to it.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_start :: proc(codec: ^AMediaCodec) -> media_status_t ---
+
+ /**
+ * Stop the codec.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_stop :: proc(codec: ^AMediaCodec) -> media_status_t ---
+
+ /*
+ * Flush the codec's input and output. All indices previously returned from calls to
+ * AMediaCodec_dequeueInputBuffer and AMediaCodec_dequeueOutputBuffer become invalid.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_flush :: proc(codec: ^AMediaCodec) -> media_status_t ---
+
+ /**
+ * Get an input buffer. The specified buffer index must have been previously obtained from
+ * dequeueInputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_getInputBuffer :: proc(codec: ^AMediaCodec, idx: uint, out_size: ^uint) -> [^]byte ---
+
+ /**
+ * Get an output buffer. The specified buffer index must have been previously obtained from
+ * dequeueOutputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_getOutputBuffer :: proc(codec: ^AMediaCodec, idx: uint, out_size: ^uint) -> [^]byte ---
+
+ /**
+ * Get the index of the next available input buffer. An app will typically use this with
+ * getInputBuffer() to get a pointer to the buffer, then copy the data to be encoded or decoded
+ * into the buffer before passing it to the codec.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_dequeueInputBuffer :: proc(codec: ^AMediaCodec, timeoutUs: i64) -> int ---
+
+
+ /**
+ * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_queueInputBuffer :: proc(
+ codec: ^AMediaCodec,
+ idx: uint,
+ offset: _off_t_compat,
+ size: uint,
+ time: u64,
+ flags: u32) -> media_status_t ---
+
+ /**
+ * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_queueSecureInputBuffer :: proc(
+ codec: ^AMediaCodec,
+ idx: uint,
+ offset: _off_t_compat,
+ crypto_info: ^AMediaCodecCryptoInfo,
+ time: u64,
+ flags: u32) -> media_status_t ---
+
+ /**
+ * Get the index of the next available buffer of processed data.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_dequeueOutputBuffer :: proc(codec: ^AMediaCodec, info: ^AMediaCodecBufferInfo, timeoutUs: i64) -> int ---
+
+ /**
+ * Returns the format of the codec's output.
+ * The caller must free the returned format.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_getOutputFormat :: proc(codec: ^AMediaCodec) -> ^AMediaFormat ---
+
+ /**
+ * If you are done with a buffer, use this call to return the buffer to
+ * the codec. If you previously specified a surface when configuring this
+ * video decoder you can optionally render the buffer.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_releaseOutputBuffer :: proc(codec: ^AMediaCodec, idx: uint, render: bool) -> media_status_t ---
+
+ /**
+ * Dynamically sets the output surface of a codec.
+ *
+ * This can only be used if the codec was configured with an output surface. The
+ * new output surface should have a compatible usage type to the original output surface.
+ * E.g. codecs may not support switching from a SurfaceTexture (GPU readable) output
+ * to ImageReader (software readable) output.
+ *
+ * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_setOutputSurface :: proc(codec: ^AMediaCodec, surface: ^android.ANativeWindow) -> media_status_t ---
+
+ /**
+ * If you are done with a buffer, use this call to update its surface timestamp
+ * and return it to the codec to render it on the output surface. If you
+ * have not specified an output surface when configuring this video codec,
+ * this call will simply return the buffer to the codec.
+ *
+ * For more details, see the Java documentation for MediaCodec.releaseOutputBuffer.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodec_releaseOutputBufferAtTime :: proc(mData: ^AMediaCodec, idx: uint, timestampNs: i64) -> media_status_t ---
+
+ /**
+ * Creates a Surface that can be used as the input to encoder, in place of input buffers
+ *
+ * This can only be called after the codec has been configured via
+ * AMediaCodec_configure(..) and before AMediaCodec_start() has been called.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createInputSurface.
+ *
+ * Available since API level 26.
+ */
+ AMediaCodec_createInputSurface :: proc(mData: ^AMediaCodec, surface: ^^android.ANativeWindow) -> media_status_t ---
+
+ /**
+ * Creates a persistent Surface that can be used as the input to encoder
+ *
+ * Persistent surface can be reused by MediaCodec instances and can be set
+ * on a new instance via AMediaCodec_setInputSurface().
+ * A persistent surface can be connected to at most one instance of MediaCodec
+ * at any point in time.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ *
+ * Available since API level 26.
+ */
+ AMediaCodec_createPersistentInputSurface :: proc(surface: ^^android.ANativeWindow) -> media_status_t ---
+
+ /**
+ * Set a persistent-surface that can be used as the input to encoder, in place of input buffers
+ *
+ * The surface provided *must* be a persistent surface created via
+ * AMediaCodec_createPersistentInputSurface()
+ * This can only be called after the codec has been configured by calling
+ * AMediaCodec_configure(..) and before AMediaCodec_start() has been called.
+ *
+ * For more details, see the Java documentation for MediaCodec.setInputSurface.
+ *
+ * Available since API level 26.
+ */
+ AMediaCodec_setInputSurface :: proc(mData: ^AMediaCodec, surface: ^android.ANativeWindow) -> media_status_t ---
+
+ /**
+ * Signal additional parameters to the codec instance.
+ *
+ * Parameters can be communicated only when the codec is running, i.e
+ * after AMediaCodec_start() has been called.
+ *
+ * NOTE: Some of these parameter changes may silently fail to apply.
+ *
+ * Available since API level 26.
+ */
+ AMediaCodec_setParameters :: proc(mData: ^AMediaCodec, params: ^AMediaFormat) -> media_status_t ---
+
+ /**
+ * Signals end-of-stream on input. Equivalent to submitting an empty buffer with
+ * AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM set.
+ *
+ * Returns AMEDIA_ERROR_INVALID_OPERATION when used with an encoder not in executing state
+ * or not receiving input from a Surface created by AMediaCodec_createInputSurface or
+ * AMediaCodec_createPersistentInputSurface.
+ *
+ * Returns the previous codec error if one exists.
+ *
+ * Returns AMEDIA_OK when completed succesfully.
+ *
+ * For more details, see the Java documentation for MediaCodec.signalEndOfInputStream.
+ *
+ * Available since API level 26.
+ */
+ AMediaCodec_signalEndOfInputStream :: proc(mData: ^AMediaCodec) -> media_status_t ---
+
+ /**
+ * Get format of the buffer. The specified buffer index must have been previously obtained from
+ * dequeueOutputBuffer.
+ * The caller must free the returned format.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_getBufferFormat :: proc(codec: ^AMediaCodec, index: uint) -> ^AMediaFormat ---
+
+ /**
+ * Get the component name. If the codec was created by createDecoderByType
+ * or createEncoderByType, what component is chosen is not known beforehand.
+ * Caller shall call AMediaCodec_releaseName to free the returned pointer.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_getName :: proc(codec: ^AMediaCodec, out_name: ^cstring) -> media_status_t ---
+
+ /**
+ * Free the memory pointed by name which is returned by AMediaCodec_getName.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_releaseName :: proc(codec: ^AMediaCodec, name: cstring) ---
+
+ /**
+ * Set an asynchronous callback for actionable AMediaCodec events.
+ * When asynchronous callback is enabled, it is an error for the client to call
+ * AMediaCodec_getInputBuffers(), AMediaCodec_getOutputBuffers(),
+ * AMediaCodec_dequeueInputBuffer() or AMediaCodec_dequeueOutputBuffer().
+ *
+ * AMediaCodec_flush() behaves differently in asynchronous mode.
+ * After calling AMediaCodec_flush(), the client must call AMediaCodec_start() to
+ * "resume" receiving input buffers. Even if the client does not receive
+ * AMediaCodecOnAsyncInputAvailable callbacks from video encoders configured
+ * with an input surface, the client still needs to call AMediaCodec_start()
+ * to resume the input surface to send buffers to the encoders.
+ *
+ * When called with null callback, this method unregisters any previously set callback.
+ *
+ * Refer to the definition of AMediaCodecOnAsyncNotifyCallback on how each
+ * callback function is called and what are specified.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
+ *
+ * All callbacks are fired on one NDK internal thread.
+ * AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
+ * No heavy duty task should be performed on callback thread.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_setAsyncNotifyCallback :: proc(
+ codec: ^AMediaCodec,
+ callback: AMediaCodecOnAsyncNotifyCallback,
+ userdata: rawptr) -> media_status_t ---
+
+ /**
+ * Registers a callback to be invoked when an output frame is rendered on the output surface.
+ *
+ * This method can be called in any codec state, but will only have an effect in the
+ * Executing state for codecs that render buffers to the output surface.
+ *
+ * This callback is for informational purposes only: to get precise
+ * render timing samples, and can be significantly delayed and batched. Some frames may have
+ * been rendered even if there was no callback generated.
+ *
+ * When called with null callback, this method unregisters any previously set callback.
+ *
+ * Refer to the definition of AMediaCodecOnFrameRendered on how each
+ * callback function is called and what are specified.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
+ *
+ * All callbacks are fired on one NDK internal thread.
+ * AMediaCodec_setOnFrameRenderedCallback should not be called on the callback thread.
+ * No heavy duty task should be performed on callback thread.
+ *
+ * Available since Android T.
+ */
+ AMediaCodec_setOnFrameRenderedCallback :: proc(
+ codec: ^AMediaCodec,
+ callback: AMediaCodecOnFrameRendered,
+ userdata: rawptr) -> media_status_t ---
+
+ /**
+ * Release the crypto if applicable.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_releaseCrypto :: proc(codec: ^AMediaCodec) -> media_status_t ---
+
+ /**
+ * Call this after AMediaCodec_configure() returns successfully to get the input
+ * format accepted by the codec. Do this to determine what optional configuration
+ * parameters were supported by the codec.
+ * The caller must free the returned format.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodec_getInputFormat :: proc(codec: ^AMediaCodec) -> ^AMediaFormat ---
+
+ /**
+ * Returns true if the codec cannot proceed further, but can be recovered by stopping,
+ * configuring, and starting again.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodecActionCode_isRecoverable :: proc(actionCode: i32) -> bool ---
+
+ /**
+ * Returns true if the codec error is a transient issue, perhaps due to
+ * resource constraints, and that the method (or encoding/decoding) may be
+ * retried at a later time.
+ *
+ * Available since API level 28.
+ */
+ AMediaCodecActionCode_isTransient :: proc(actionCode: i32) -> bool ---
+
+ /**
+ * Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
+ * crypto info, rather than one obtained from AMediaExtractor.
+ *
+ * AMediaCodecCryptoInfo describes the structure of an (at least
+ * partially) encrypted input sample.
+ * A buffer's data is considered to be partitioned into "subsamples",
+ * each subsample starts with a (potentially empty) run of plain,
+ * unencrypted bytes followed by a (also potentially empty) run of
+ * encrypted bytes.
+ * numBytesOfClearData can be null to indicate that all data is encrypted.
+ * This information encapsulates per-sample metadata as outlined in
+ * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_new :: proc(
+ numsubsamples: i32,
+ key: [16]byte,
+ iv: [16]byte,
+ mode: cryptoinfo_mode_t,
+ clearbytes: ^uint,
+ encryptedbytes: ^uint) -> ^AMediaCodecCryptoInfo ---
+
+ /**
+ * Delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_delete :: proc(info: ^AMediaCodecCryptoInfo) -> media_status_t ---
+
+ /**
+ * Set the crypto pattern on an AMediaCryptoInfo object.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_setPattern :: proc(info: ^AMediaCodecCryptoInfo, pattern: ^cryptoinfo_pattern_t) ---
+
+ /**
+ * The number of subsamples that make up the buffer's contents.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getNumSubSamples :: proc(info: ^AMediaCodecCryptoInfo) -> uint ---
+
+ /**
+ * A 16-byte opaque key.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getKey :: proc(info: ^AMediaCodecCryptoInfo, dst: [^]byte) -> media_status_t ---
+
+ /**
+ * A 16-byte initialization vector.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getIV :: proc(info: ^AMediaCodecCryptoInfo, dst: [^]byte) -> media_status_t ---
+
+ /**
+ * The type of encryption that has been applied,
+ * one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getMode :: proc(info: ^AMediaCodecCryptoInfo) -> cryptoinfo_mode_t ---
+
+ /**
+ * The number of leading unencrypted bytes in each subsample.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getClearBytes :: proc(info: ^AMediaCodecCryptoInfo, dst: ^uint) -> media_status_t ---
+
+ /**
+ * The number of trailing encrypted bytes in each subsample.
+ *
+ * Available since API level 21.
+ */
+ AMediaCodecCryptoInfo_getEncryptedBytes :: proc(info: ^AMediaCodecCryptoInfo, dst: ^uint) -> media_status_t ---
+}
diff --git a/media/NdkMediaCrypto.odin b/media/NdkMediaCrypto.odin
new file mode 100644
index 0000000..fc59741
--- /dev/null
+++ b/media/NdkMediaCrypto.odin
@@ -0,0 +1,29 @@
+//+build android
+package mediandk
+
+foreign import mediandk "system:mediandk"
+
+AMediaCrypto :: struct{}
+AMediaUUID :: [16]u8
+
+foreign mediandk {
+ /**
+ * Available since API level 21.
+ */
+ AMediaCrypto_isCryptoSchemeSupported :: proc(uuid: AMediaUUID) -> bool ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaCrypto_requiresSecureDecoderComponent :: proc(mime: cstring) -> bool ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaCrypto_new :: proc(uuid: AMediaUUID, initData: rawptr, initDataSize: uint) -> ^AMediaCrypto ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaCrypto_delete :: proc(crypto: ^AMediaCrypto) ---
+}
diff --git a/media/NdkMediaDataSource.odin b/media/NdkMediaDataSource.odin
new file mode 100644
index 0000000..ba8b106
--- /dev/null
+++ b/media/NdkMediaDataSource.odin
@@ -0,0 +1,164 @@
+//+build android
+package mediandk
+
+import "../"
+
+foreign import mediandk "system:mediandk"
+
+AMediaDataSource :: struct{}
+
+/*
+ * AMediaDataSource's callbacks will be invoked on an implementation-defined thread
+ * or thread pool. No guarantees are provided about which thread(s) will be used for
+ * callbacks. For example, |close| can be invoked from a different thread than the
+ * thread invoking |readAt|. As such, the Implementations of AMediaDataSource callbacks
+ * must be threadsafe.
+ */
+
+/**
+ * Called to request data from the given |offset|.
+ *
+ * Implementations should should write up to |size| bytes into
+ * |buffer|, and return the number of bytes written.
+ *
+ * Return 0 if size is zero (thus no bytes are read).
+ *
+ * Return -1 to indicate that end of stream is reached.
+ */
+AMediaDataSourceReadAt :: #type proc "c" (userdata: rawptr, offset: android.off64_t, buffer: rawptr, size: uint) -> int
+
+/**
+ * Called to get the size of the data source.
+ *
+ * Return the size of data source in bytes, or -1 if the size is unknown.
+ */
+AMediaDataSourceGetSize :: #type proc "c" (userdata: rawptr) -> int
+
+/**
+ * Called to close the data source, unblock reads, and release associated
+ * resources.
+ *
+ * The NDK media framework guarantees that after the first |close| is
+ * called, no future callbacks will be invoked on the data source except
+ * for |close| itself.
+ *
+ * Closing a data source allows readAt calls that were blocked waiting
+ * for I/O data to return promptly.
+ *
+ * When using AMediaDataSource as input to AMediaExtractor, closing
+ * has the effect of unblocking slow reads inside of setDataSource
+ * and readSampleData.
+ */
+AMediaDataSourceClose :: #type proc "c" (userdata: rawptr)
+
+/**
+ * Called to get an estimate of the number of bytes that can be read from this data source
+ * starting at |offset| without blocking for I/O.
+ *
+ * Return -1 when such an estimate is not possible.
+ */
+AMediaDataSourceGetAvailableSize :: #type proc "c" (userdata: rawptr, offset: android.off64_t) -> int
+
+
+foreign mediandk {
+ /**
+ * Create new media data source. Returns NULL if memory allocation
+ * for the new data source object fails.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_new :: proc() -> ^AMediaDataSource ---
+
+ /**
+ * Create new media data source. Returns NULL if memory allocation
+ * for the new data source object fails.
+ *
+ * Set the |uri| from which the data source will read,
+ * plus additional http headers when initiating the request.
+ *
+ * Headers will contain corresponding items from |key_values|
+ * in the following fashion:
+ *
+ * key_values[0]:key_values[1]
+ * key_values[2]:key_values[3]
+ * ...
+ * key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
+ *
+ * Available since API level 29.
+ */
+ AMediaDataSource_newUri :: proc(uri: cstring, numheaders: i32, key_values: ^[^]u8) -> ^AMediaDataSource ---
+
+ /**
+ * Delete a previously created media data source.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_delete :: proc(ds: ^AMediaDataSource) ---
+
+ /**
+ * Set an user provided opaque handle. This opaque handle is passed as
+ * the first argument to the data source callbacks.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_setUserdata :: proc(ds: ^AMediaDataSource, userdata: rawptr) ---
+
+ /**
+ * Set a custom callback for supplying random access media data to the
+ * NDK media framework.
+ *
+ * Implement this if your app has special requirements for the way media
+ * data is obtained, or if you need a callback when data is read by the
+ * NDK media framework.
+ *
+ * Please refer to the definition of AMediaDataSourceReadAt for
+ * additional details.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_setReadAt :: proc(ds: ^AMediaDataSource, cb: AMediaDataSourceReadAt) ---
+
+ /**
+ * Set a custom callback for supplying the size of the data source to the
+ * NDK media framework.
+ *
+ * Please refer to the definition of AMediaDataSourceGetSize for
+ * additional details.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_setGetSize :: proc(ds: ^AMediaDataSource, cb: AMediaDataSourceGetSize) ---
+
+ /**
+ * Set a custom callback to receive signal from the NDK media framework
+ * when the data source is closed.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ *
+ * Available since API level 28.
+ */
+ AMediaDataSource_setClose :: proc(ds: ^AMediaDataSource, cb: AMediaDataSourceClose) ---
+
+ /**
+ * Close the data source, unblock reads, and release associated resources.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ *
+ * Available since API level 29.
+ */
+ AMediaDataSource_close :: proc(ds: ^AMediaDataSource) ---
+
+ /**
+ * Set a custom callback for supplying the estimated number of bytes
+ * that can be read from this data source starting at an offset without
+ * blocking for I/O.
+ *
+ * Please refer to the definition of AMediaDataSourceGetAvailableSize
+ * for additional details.
+ *
+ * Available since API level 29.
+ */
+ AMediaDataSource_setGetAvailableSize :: proc(ds: ^AMediaDataSource, cb: AMediaDataSourceGetAvailableSize) ---
+}
diff --git a/media/NdkMediaDrm.odin b/media/NdkMediaDrm.odin
new file mode 100644
index 0000000..0284a98
--- /dev/null
+++ b/media/NdkMediaDrm.odin
@@ -0,0 +1,658 @@
+//+build android
+package mediandk
+
+foreign import mediandk "system:mediandk"
+
+/**
+* String property name: identifies the maker of the DRM engine plugin
+*/
+PROPERTY_VENDOR :: "vendor"
+
+/**
+* String property name: identifies the version of the DRM engine plugin
+*/
+PROPERTY_VERSION :: "version"
+
+/**
+* String property name: describes the DRM engine plugin
+*/
+PROPERTY_DESCRIPTION :: "description"
+
+/**
+* String property name: a comma-separated list of cipher and mac algorithms
+* supported by CryptoSession. The list may be empty if the DRM engine
+* plugin does not support CryptoSession operations.
+*/
+PROPERTY_ALGORITHMS :: "algorithms"
+
+/**
+* Byte array property name: the device unique identifier is established during
+* device provisioning and provides a means of uniquely identifying each device.
+*/
+PROPERTY_DEVICE_UNIQUE_ID :: "deviceUniqueId"
+
+AMediaDrm :: struct{}
+
+AMediaDrmByteArray :: struct {
+ ptr: [^]byte,
+ length: uint,
+}
+
+AMediaDrmSessionId :: AMediaDrmByteArray
+AMediaDrmScope :: AMediaDrmByteArray
+AMediaDrmKeySetId :: AMediaDrmByteArray
+AMediaDrmSecureStop :: AMediaDrmByteArray
+AMediaDrmKeyId :: AMediaDrmByteArray
+
+AMediaDrmEventType :: enum {
+ /**
+ * This event type indicates that the app needs to request a certificate from
+ * the provisioning server. The request message data is obtained using
+ * AMediaDrm_getProvisionRequest.
+ */
+ PROVISION_REQUIRED = 1,
+
+ /**
+ * This event type indicates that the app needs to request keys from a license
+ * server. The request message data is obtained using AMediaDrm_getKeyRequest.
+ */
+ KEY_REQUIRED = 2,
+
+ /**
+ * This event type indicates that the licensed usage duration for keys in a session
+ * has expired. The keys are no longer valid.
+ */
+ KEY_EXPIRED = 3,
+
+ /**
+ * This event may indicate some specific vendor-defined condition, see your
+ * DRM provider documentation for details
+ */
+ VENDOR_DEFINED = 4,
+
+ /**
+ * This event indicates that a session opened by the app has been reclaimed
+ * by the resource manager.
+ */
+ SESSION_RECLAIMED = 5,
+}
+
+AMediaDrmKeyType :: enum {
+ /**
+ * This key request type specifies that the keys will be for online use, they will
+ * not be saved to the device for subsequent use when the device is not connected
+ * to a network.
+ */
+ STREAMING = 1,
+
+ /**
+ * This key request type specifies that the keys will be for offline use, they
+ * will be saved to the device for use when the device is not connected to a network.
+ */
+ OFFLINE = 2,
+
+ /**
+ * This key request type specifies that previously saved offline keys should be released.
+ */
+ RELEASE = 3
+}
+
+/**
+ * Introduced in API 33.
+ */
+AMediaDrmKeyRequestType :: enum i32 {
+ /**
+ * Key request type is initial license request.
+ * An initial license request is necessary to load keys.
+ */
+ INITIAL,
+
+ /**
+ * Key request type is license renewal.
+ * A renewal license request is necessary to prevent the keys from expiring.
+ */
+ RENEWAL,
+
+ /**
+ * Key request type is license release.
+ * A license release request indicates that keys are removed.
+ */
+ RELEASE,
+
+ /**
+ * Keys are already loaded and are available for use. No license request is necessary, and
+ * no key request data is returned.
+ */
+ NONE,
+
+ /**
+ * Keys have been loaded but an additional license request is needed
+ * to update their values.
+ */
+ UPDATE
+}
+
+/**
+ * Data type containing {key, value} pair
+ */
+AMediaDrmKeyValue :: struct {
+ mKey: cstring,
+ mValue: cstring,
+}
+
+AMediaDrmKeyStatusType :: enum {
+ /**
+ * The key is currently usable to decrypt media data.
+ */
+ USABLE,
+
+ /**
+ * The key is no longer usable to decrypt media data because its expiration
+ * time has passed.
+ */
+ EXPIRED,
+
+ /**
+ * The key is not currently usable to decrypt media data because its output
+ * requirements cannot currently be met.
+ */
+ OUTPUTNOTALLOWED,
+
+ /**
+ * The status of the key is not yet known and is being determined.
+ */
+ STATUSPENDING,
+
+ /**
+ * The key is not currently usable to decrypt media data because of an
+ * internal error in processing unrelated to input parameters.
+ */
+ INTERNALERROR,
+}
+
+AMediaDrmKeyStatus :: struct {
+ keyId: AMediaDrmKeyId,
+ keyType: AMediaDrmKeyStatusType,
+}
+
+AMediaDrmEventListener :: #type proc "c" (drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId, eventType: AMediaDrmEventType, extra: i32, data: [^]byte, dataSize: uint)
+
+AMediaDrmExpirationUpdateListener :: #type proc "c" (drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId, expiryTimeInMS: i64)
+
+AMediaDrmKeysChangeListener :: #type proc "c" (drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId, keyStatus: ^AMediaDrmKeyStatus, numKeys: uint, hasNewUsableKey: bool)
+
+foreign mediandk {
+ /**
+ * Query if the given scheme identified by its UUID is supported on this device, and
+ * whether the drm plugin is able to handle the media container format specified by mimeType.
+ *
+ * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
+ * mimeType is the MIME type of the media container, e.g. "video/mp4". If mimeType
+ * is not known or required, it can be provided as NULL.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_isCryptoSchemeSupported :: proc(uuid: [^]byte, mimeType: cstring) -> bool ---
+
+ /**
+ * Create a MediaDrm instance from a UUID.
+ * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_createByUUID :: proc(uuid: [^]byte) -> ^AMediaDrm ---
+
+ /**
+ * Release a MediaDrm object.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_release :: proc(drm: ^AMediaDrm) ---
+
+ /**
+ * Register a callback to be invoked when an event occurs.
+ *
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_setOnEventListener :: proc(drm: ^AMediaDrm, listener: AMediaDrmEventListener) -> media_status_t ---
+
+ /**
+ * Register a callback to be invoked when an expiration update event occurs.
+ *
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
+ */
+ AMediaDrm_setOnExpirationUpdateListener :: proc(drm: ^AMediaDrm, listener: AMediaDrmExpirationUpdateListener) -> media_status_t ---
+
+ /**
+ * Register a callback to be invoked when a key status change event occurs.
+ *
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
+ */
+ AMediaDrm_setOnKeysChangeListener :: proc(drm: ^AMediaDrm, listener: AMediaDrmKeysChangeListener) -> media_status_t ---
+
+ /**
+ * Open a new session with the MediaDrm object. A session ID is returned.
+ *
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if provisioning is needed.
+ * Returns AMEDIA_DRM_RESOURCE_BUSY if required resources are in use.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_openSession :: proc(drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId) -> media_status_t ---
+
+ /**
+ * Close a session on the MediaDrm object that was previously opened
+ * with AMediaDrm_openSession.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_closeSession :: proc(drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId) -> media_status_t ---
+
+ /**
+ * A key request/response exchange occurs between the app and a license server
+ * to obtain or release keys used to decrypt encrypted content.
+ * AMediaDrm_getKeyRequest is used to obtain an opaque key request byte array that
+ * is delivered to the license server. The opaque key request byte array is
+ * returned in *keyRequest and the number of bytes in the request is
+ * returned in *keyRequestSize.
+ * This API has same functionality as AMediaDrm_getKeyRequestWithDefaultUrlAndType()
+ * when defaultUrl and keyRequestType are passed in as NULL.
+ *
+ * After the app has received the key request response from the server,
+ * it should deliver to the response to the DRM engine plugin using the method
+ * AMediaDrm_provideKeyResponse.
+ *
+ * scope may be a sessionId or a keySetId, depending on the specified keyType.
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set
+ * to the sessionId the keys will be provided to. When the keyType is
+ * KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys being released.
+ * Releasing keys from a device invalidates them for all sessions.
+ *
+ * init container-specific data, its meaning is interpreted based on the mime type
+ * provided in the mimeType parameter. It could contain, for example, the content
+ * ID, key ID or other data obtained from the content metadata that is required in
+ * generating the key request. init may be null when keyType is KEY_TYPE_RELEASE.
+ *
+ * initSize is the number of bytes of initData
+ *
+ * mimeType identifies the mime type of the content.
+ *
+ * keyType specifes the type of the request. The request may be to acquire keys for
+ * streaming or offline content, or to release previously acquired keys, which are
+ * identified by a keySetId.
+ *
+ * optionalParameters are included in the key request message to allow a client
+ * application to provide additional message parameters to the server.
+ *
+ * numOptionalParameters indicates the number of optional parameters provided
+ * by the caller
+ *
+ * On exit:
+ * If this returns AMEDIA_OK,
+ * 1. The keyRequest pointer will reference the opaque key request data. It
+ * will reside in memory owned by the AMediaDrm object, and will remain
+ * accessible until the next call to AMediaDrm_getKeyRequest
+ * or AMediaDrm_getKeyRequestWithDefaultUrlAndType or until the
+ * MediaDrm object is released.
+ * 2. keyRequestSize will be set to the size of the request
+ * If this does not return AMEDIA_OK, value of these parameters should not be used.
+ *
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if reprovisioning is needed, due to a
+ * problem with the device certificate.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_getKeyRequest :: proc(
+ drm: ^AMediaDrm,
+ scope: ^AMediaDrmScope,
+ init: [^]byte,
+ initSize: uint,
+ mimeType: cstring,
+ keyType: AMediaDrmKeyType,
+ optionalParameters: [^]AMediaDrmKeyValue,
+ numOptionalParameters: uint,
+ keyRequest: ^[^]byte,
+ keyRequestSize: ^uint) -> media_status_t ---
+
+ /**
+ * A key request/response exchange occurs between the app and a license server
+ * to obtain or release keys used to decrypt encrypted content.
+ * AMediaDrm_getKeyRequest is used to obtain an opaque key request byte array that
+ * is delivered to the license server. The opaque key request byte array is
+ * returned in *keyRequest and the number of bytes in the request is
+ * returned in *keyRequestSize.
+ *
+ * After the app has received the key request response from the server,
+ * it should deliver to the response to the DRM engine plugin using the method
+ * AMediaDrm_provideKeyResponse.
+ *
+ * scope may be a sessionId or a keySetId, depending on the specified keyType.
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set
+ * to the sessionId the keys will be provided to. When the keyType is
+ * KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys being released.
+ * Releasing keys from a device invalidates them for all sessions.
+ *
+ * init container-specific data, its meaning is interpreted based on the mime type
+ * provided in the mimeType parameter. It could contain, for example, the content
+ * ID, key ID or other data obtained from the content metadata that is required in
+ * generating the key request. init may be null when keyType is KEY_TYPE_RELEASE.
+ *
+ * initSize is the number of bytes of initData
+ *
+ * mimeType identifies the mime type of the content.
+ *
+ * keyType specifes the type of the request. The request may be to acquire keys for
+ * streaming or offline content, or to release previously acquired keys, which are
+ * identified by a keySetId.
+ *
+ * optionalParameters are included in the key request message to allow a client
+ * application to provide additional message parameters to the server.
+ *
+ * numOptionalParameters indicates the number of optional parameters provided
+ * by the caller
+ *
+ * On exit:
+ * If this returns AMEDIA_OK,
+ * 1. The keyRequest pointer will reference the opaque key request data. It
+ * will reside in memory owned by the AMediaDrm object, and will remain
+ * accessible until the next call to either AMediaDrm_getKeyRequest
+ * or AMediaDrm_getKeyRequestWithDefaultUrlAndType or until the
+ * MediaDrm object is released.
+ * 2. keyRequestSize will be set to the size of the request.
+ * 3. defaultUrl will be set to the recommended URL to deliver the key request.
+ * The defaultUrl pointer will reference a NULL terminated URL string.
+ * It will be UTF-8 encoded and have same lifetime with the key request data
+ * KeyRequest pointer references to. Passing in NULL means you don't need it
+ * to be reported.
+ * 4. keyRequestType will be set to the key request type. Passing in NULL means
+ * you don't need it to be reported.
+ *
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if reprovisioning is needed, due to a
+ * problem with the device certificate.
+ *
+ * Available since API level 33.
+ */
+ AMediaDrm_getKeyRequestWithDefaultUrlAndType :: proc(
+ drm: ^AMediaDrm,
+ scope: ^AMediaDrmScope,
+ init: [^]byte,
+ initSize: uint,
+ mimeType: cstring,
+ keyType: AMediaDrmKeyType,
+ optionalParameters: [^]AMediaDrmKeyValue,
+ numOptionalParameters: uint,
+ keyRequest: ^[^]byte,
+ keyRequestSize: ^uint,
+ defaultUrl: ^cstring,
+ keyRequestType: ^AMediaDrmKeyRequestType) -> media_status_t ---
+
+ /**
+ * A key response is received from the license server by the app, then it is
+ * provided to the DRM engine plugin using provideKeyResponse. When the
+ * response is for an offline key request, a keySetId is returned that can be
+ * used to later restore the keys to a new session with AMediaDrm_restoreKeys.
+ * When the response is for a streaming or release request, a null keySetId is
+ * returned.
+ *
+ * scope may be a sessionId or keySetId depending on the type of the
+ * response. Scope should be set to the sessionId when the response is for either
+ * streaming or offline key requests. Scope should be set to the keySetId when
+ * the response is for a release request.
+ *
+ * response points to the opaque response from the server
+ * responseSize should be set to the size of the response in bytes
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_provideKeyResponse :: proc(
+ drm: ^AMediaDrm,
+ scope: ^AMediaDrmScope,
+ response: [^]byte,
+ responseSize: uint,
+ keySetId: ^AMediaDrmKeySetId) -> media_status_t ---
+
+ /**
+ * Restore persisted offline keys into a new session. keySetId identifies the
+ * keys to load, obtained from a prior call to AMediaDrm_provideKeyResponse.
+ *
+ * sessionId is the session ID for the DRM session.
+ * keySetId identifies the saved key set to restore.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_restoreKeys :: proc(drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId, keySetId: ^AMediaDrmKeySetId) -> media_status_t ---
+
+ /**
+ * Remove the current keys from a session.
+ *
+ * keySetId identifies keys to remove.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_removeKeys :: proc(drm: ^AMediaDrm, keySetId: ^AMediaDrmSessionId) -> media_status_t ---
+
+ /**
+ * Request an informative description of the key status for the session. The status is
+ * in the form of {key, value} pairs. Since DRM license policies vary by vendor,
+ * the specific status field names are determined by each DRM vendor. Refer to your
+ * DRM provider documentation for definitions of the field names for a particular
+ * DRM engine plugin.
+ *
+ * On entry, numPairs should be set by the caller to the maximum number of pairs
+ * that can be returned (the size of the array). On exit, numPairs will be set
+ * to the number of entries written to the array. If the number of {key, value} pairs
+ * to be returned is greater than *numPairs, AMEDIA_DRM_SHORT_BUFFER will be returned
+ * and numPairs will be set to the number of pairs available.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_queryKeyStatus :: proc(drm: ^AMediaDrm, sessionId: ^AMediaDrmSessionId, keyValuePairs: [^]AMediaDrmKeyValue, numPairs: ^uint) -> media_status_t ---
+
+
+ /**
+ * A provision request/response exchange occurs between the app and a provisioning
+ * server to retrieve a device certificate. If provisionining is required, the
+ * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+ * getProvisionRequest is used to obtain the opaque provision request byte array that
+ * should be delivered to the provisioning server.
+ * On exit:
+ * 1. The provision request data will be referenced by provisionRequest, in
+ * memory owned by the AMediaDrm object. It will remain accessible until the
+ * next call to getProvisionRequest.
+ * 2. provisionRequestSize will be set to the size of the request data.
+ * 3. serverUrl will reference a NULL terminated string containing the URL
+ * the provisioning request should be sent to. It will remain accessible until
+ * the next call to getProvisionRequest.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_getProvisionRequest :: proc(drm: ^AMediaDrm, provisionRequest: ^[^]byte, provisionRequestSize: ^uint, serverUrl: ^cstring) -> media_status_t ---
+
+ /**
+ * After a provision response is received by the app, it is provided to the DRM
+ * engine plugin using this method.
+ *
+ * response is the opaque provisioning response byte array to provide to the
+ * DRM engine plugin.
+ * responseSize is the length of the provisioning response in bytes.
+ *
+ * Returns AMEDIA_DRM_DEVICE_REVOKED if the response indicates that the
+ * server rejected the request
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_provideProvisionResponse :: proc(drm: ^AMediaDrm, response: [^]byte, responseSize: uint) -> media_status_t ---
+
+ /**
+ * A means of enforcing limits on the number of concurrent streams per subscriber
+ * across devices is provided via SecureStop. This is achieved by securely
+ * monitoring the lifetime of sessions.
+ *
+ * Information from the server related to the current playback session is written
+ * to persistent storage on the device when each MediaCrypto object is created.
+ *
+ * In the normal case, playback will be completed, the session destroyed and the
+ * Secure Stops will be queried. The app queries secure stops and forwards the
+ * secure stop message to the server which verifies the signature and notifies the
+ * server side database that the session destruction has been confirmed. The persisted
+ * record on the client is only removed after positive confirmation that the server
+ * received the message using releaseSecureStops().
+ *
+ * numSecureStops is set by the caller to the maximum number of secure stops to
+ * return. On exit, *numSecureStops will be set to the number actually returned.
+ * If *numSecureStops is too small for the number of secure stops available,
+ * AMEDIA_DRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
+ * number required.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_getSecureStops :: proc(drm: ^AMediaDrm, secureStops: ^AMediaDrmSecureStop, numSecureStops: ^uint) -> media_status_t ---
+
+ /**
+ * Process the SecureStop server response message ssRelease. After authenticating
+ * the message, remove the SecureStops identified in the response.
+ *
+ * ssRelease is the server response indicating which secure stops to release
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_releaseSecureStops :: proc(drm: ^AMediaDrm, ssRelease: ^AMediaDrmSecureStop) -> media_status_t ---
+
+ /**
+ * Read a DRM engine plugin String property value, given the property name string.
+ *
+ * propertyName identifies the property to query
+ * On return, propertyValue will be set to point to the property value. The
+ * memory that the value resides in is owned by the NDK MediaDrm API and
+ * will remain valid until the next call to AMediaDrm_getPropertyString.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_getPropertyString :: proc(drm: ^AMediaDrm, propertyName: cstring, propertyValue: ^cstring) -> media_status_t ---
+
+ /**
+ * Read a DRM engine plugin byte array property value, given the property name string.
+ * On return, *propertyValue will be set to point to the property value. The
+ * memory that the value resides in is owned by the NDK MediaDrm API and
+ * will remain valid until the next call to AMediaDrm_getPropertyByteArray.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_getPropertyByteArray :: proc(drm: ^AMediaDrm, propertyName: cstring, propertyValue: ^AMediaDrmByteArray) -> media_status_t ---
+
+ /**
+ * Set a DRM engine plugin String property value.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_setPropertyString :: proc(drm: ^AMediaDrm, propertyName: cstring, value: cstring) -> media_status_t ---
+
+ /**
+ * Set a DRM engine plugin byte array property value.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_setPropertyByteArray :: proc(drm: ^AMediaDrm, propertyName: cstring, value: [^]byte, valueSize: uint) -> media_status_t ---
+
+ /**
+ * In addition to supporting decryption of DASH Common Encrypted Media, the
+ * MediaDrm APIs provide the ability to securely deliver session keys from
+ * an operator's session key server to a client device, based on the factory-installed
+ * root of trust, and then perform encrypt, decrypt, sign and verify operations
+ * with the session key on arbitrary user data.
+ *
+ * Operators create session key servers that receive session key requests and provide
+ * encrypted session keys which can be used for general purpose crypto operations.
+ *
+ * Generic encrypt/decrypt/sign/verify methods are based on the established session
+ * keys. These keys are exchanged using the getKeyRequest/provideKeyResponse methods.
+ *
+ * Applications of this capability include securing various types of purchased or
+ * private content, such as applications, books and other media, photos or media
+ * delivery protocols.
+ */
+
+ /*
+ * Encrypt the data referenced by input of length dataSize using algorithm specified
+ * by cipherAlgorithm, and write the encrypted result into output. The caller must
+ * ensure that the output buffer is large enough to accept dataSize bytes. The key
+ * to use is identified by the 16 byte keyId. The key must have been loaded into
+ * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_encrypt :: proc(
+ drm: ^AMediaDrm,
+ sessionId: ^AMediaDrmSessionId,
+ cipherAlgorithm: cstring,
+ keyId: [^]byte,
+ iv: [^]byte,
+ input: [^]byte,
+ output: [^]byte,
+ dataSize: uint) -> media_status_t ---
+
+ /*
+ * Decrypt the data referenced by input of length dataSize using algorithm specified
+ * by cipherAlgorithm, and write the decrypted result into output. The caller must
+ * ensure that the output buffer is large enough to accept dataSize bytes. The key
+ * to use is identified by the 16 byte keyId. The key must have been loaded into
+ * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_decrypt :: proc(
+ drm: ^AMediaDrm,
+ sessionId: ^AMediaDrmSessionId,
+ cipherAlgorithm: cstring,
+ keyId: [^]byte,
+ iv: [^]byte,
+ input: [^]byte,
+ output: [^]byte,
+ dataSize: uint) -> media_status_t ---
+
+ /*
+ * Generate a signature using the specified macAlgorithm over the message data
+ * referenced by message of size messageSize and store the signature in the
+ * buffer referenced signature of max size *signatureSize. If the buffer is not
+ * large enough to hold the signature, AMEDIA_DRM_SHORT_BUFFER is returned and
+ * *signatureSize is set to the buffer size required. The key to use is identified
+ * by the 16 byte keyId. The key must have been loaded into the session using
+ * provideKeyResponse.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_sign :: proc(
+ drm: ^AMediaDrm,
+ sessionId: ^AMediaDrmSessionId,
+ macAlgorithm: cstring,
+ keyId: [^]byte,
+ message: [^]byte,
+ messageSize: uint,
+ signature: [^]byte,
+ signatureSize: ^uint) -> media_status_t ---
+
+ /*
+ * Perform a signature verification using the specified macAlgorithm over the message
+ * data referenced by the message parameter of size messageSize. Returns AMEDIA_OK
+ * if the signature matches, otherwise MEDAIDRM_VERIFY_FAILED is returned. The key to
+ * use is identified by the 16 byte keyId. The key must have been loaded into the
+ * session using provideKeyResponse.
+ *
+ * Available since API level 21.
+ */
+ AMediaDrm_verify :: proc(
+ drm: ^AMediaDrm,
+ sessionId: ^AMediaDrmSessionId,
+ macAlgorithm: cstring,
+ keyId: [^]byte,
+ message: [^]byte,
+ messageSize: uint,
+ signature: [^]byte,
+ signatureSize: uint) -> media_status_t ---
+}
diff --git a/media/NdkMediaError.odin b/media/NdkMediaError.odin
new file mode 100644
index 0000000..5753cba
--- /dev/null
+++ b/media/NdkMediaError.odin
@@ -0,0 +1,81 @@
+//+build android
+package mediandk
+
+/**
+ * Media error message types returned from NDK media functions.
+ */
+media_status_t :: enum {
+ /** The requested media operation completed successfully. */
+ AMEDIA_OK = 0,
+
+ /**
+ * This indicates required resource was not able to be allocated.
+ */
+ AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE = 1100,
+
+ /**
+ * This indicates the resource manager reclaimed the media resource used by the codec.
+ * With this error, the codec must be released, as it has moved to terminal state.
+ */
+ AMEDIACODEC_ERROR_RECLAIMED = 1101,
+
+ AMEDIA_ERROR_BASE = -10000,
+
+ /** The called media function failed with an unknown error. */
+ AMEDIA_ERROR_UNKNOWN = AMEDIA_ERROR_BASE,
+
+ /** The input media data is corrupt or incomplete. */
+ AMEDIA_ERROR_MALFORMED = AMEDIA_ERROR_BASE - 1,
+
+ /** The required operation or media formats are not supported. */
+ AMEDIA_ERROR_UNSUPPORTED = AMEDIA_ERROR_BASE - 2,
+
+ /** An invalid (or already closed) object is used in the function call. */
+ AMEDIA_ERROR_INVALID_OBJECT = AMEDIA_ERROR_BASE - 3,
+
+ /** At least one of the invalid parameters is used. */
+ AMEDIA_ERROR_INVALID_PARAMETER = AMEDIA_ERROR_BASE - 4,
+
+ /** The media object is not in the right state for the required operation. */
+ AMEDIA_ERROR_INVALID_OPERATION = AMEDIA_ERROR_BASE - 5,
+
+ /** Media stream ends while processing the requested operation. */
+ AMEDIA_ERROR_END_OF_STREAM = AMEDIA_ERROR_BASE - 6,
+
+ /** An Error occurred when the Media object is carrying IO operation. */
+ AMEDIA_ERROR_IO = AMEDIA_ERROR_BASE - 7,
+
+ /** The required operation would have to be blocked (on I/O or others),
+ * but blocking is not enabled.
+ */
+ AMEDIA_ERROR_WOULD_BLOCK = AMEDIA_ERROR_BASE - 8,
+
+ AMEDIA_DRM_ERROR_BASE = -20000,
+ AMEDIA_DRM_NOT_PROVISIONED = AMEDIA_DRM_ERROR_BASE - 1,
+ AMEDIA_DRM_RESOURCE_BUSY = AMEDIA_DRM_ERROR_BASE - 2,
+ AMEDIA_DRM_DEVICE_REVOKED = AMEDIA_DRM_ERROR_BASE - 3,
+ AMEDIA_DRM_SHORT_BUFFER = AMEDIA_DRM_ERROR_BASE - 4,
+ AMEDIA_DRM_SESSION_NOT_OPENED = AMEDIA_DRM_ERROR_BASE - 5,
+ AMEDIA_DRM_TAMPER_DETECTED = AMEDIA_DRM_ERROR_BASE - 6,
+ AMEDIA_DRM_VERIFY_FAILED = AMEDIA_DRM_ERROR_BASE - 7,
+ AMEDIA_DRM_NEED_KEY = AMEDIA_DRM_ERROR_BASE - 8,
+ AMEDIA_DRM_LICENSE_EXPIRED = AMEDIA_DRM_ERROR_BASE - 9,
+
+ AMEDIA_IMGREADER_ERROR_BASE = -30000,
+
+ /** There are no more image buffers to read/write image data. */
+ AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE = AMEDIA_IMGREADER_ERROR_BASE - 1,
+
+ /** The AImage object has used up the allowed maximum image buffers. */
+ AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED = AMEDIA_IMGREADER_ERROR_BASE - 2,
+
+ /** The required image buffer could not be locked to read. */
+ AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE = AMEDIA_IMGREADER_ERROR_BASE - 3,
+
+ /** The media data or buffer could not be unlocked. */
+ AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE = AMEDIA_IMGREADER_ERROR_BASE - 4,
+
+ /** The media/buffer needs to be locked to perform the required operation. */
+ AMEDIA_IMGREADER_IMAGE_NOT_LOCKED = AMEDIA_IMGREADER_ERROR_BASE - 5,
+}
+
diff --git a/media/NdkMediaExtractor.odin b/media/NdkMediaExtractor.odin
new file mode 100644
index 0000000..793f3f7
--- /dev/null
+++ b/media/NdkMediaExtractor.odin
@@ -0,0 +1,213 @@
+//+build android
+package mediandk
+
+import "../"
+
+foreign import mediandk "system:mediandk"
+
+SeekMode :: enum {
+ PREVIOUS_SYNC,
+ NEXT_SYNC,
+ CLOSEST_SYNC
+}
+
+SampleFlags :: enum u32 {
+ SYNC = 1,
+ ENCRYPTED = 2,
+}
+
+AMediaExtractor :: struct{}
+
+/**
+* mapping of crypto scheme uuid to the scheme specific data for that scheme
+*/
+PsshEntry :: struct {
+ uuid: AMediaUUID,
+ datalen: uint,
+ data: rawptr,
+}
+
+/**
+* list of crypto schemes and their data
+*/
+PsshInfo :: struct {
+ numentries: uint,
+ entries: [0]PsshEntry,
+}
+
+foreign mediandk {
+ /**
+ * Create new media extractor.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_new :: proc() -> ^AMediaExtractor ---
+
+ /**
+ * Delete a previously created media extractor.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_delete :: proc(extractor: ^AMediaExtractor) -> media_status_t ---
+
+ /**
+ * Set the file descriptor from which the extractor will read.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_setDataSourceFd :: proc(extractor: ^AMediaExtractor, fd: i32, offset: android.off64_t, length: android.off64_t) -> media_status_t ---
+
+ /**
+ * Set the URI from which the extractor will read.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_setDataSource :: proc(extractor: ^AMediaExtractor, location: cstring) -> media_status_t ---
+
+ /**
+ * Set the custom data source implementation from which the extractor will read.
+ *
+ * Available since API level 28.
+ */
+ AMediaExtractor_setDataSourceCustom :: proc(extractor: ^AMediaExtractor, src: ^AMediaDataSource) -> media_status_t ---
+
+ /**
+ * Return the number of tracks in the previously specified media file
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getTrackCount :: proc(extractor: ^AMediaExtractor) -> uint ---
+
+ /**
+ * Return the format of the specified track. The caller must free the returned format
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getTrackFormat :: proc(extractor: ^AMediaExtractor, idx: uint) -> ^AMediaFormat ---
+
+ /**
+ * Select the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
+ * getSampleTime only retrieve information for the subset of tracks selected.
+ * Selecting the same track multiple times has no effect, the track is
+ * only selected once.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_selectTrack :: proc(extractor: ^AMediaExtractor, idx: uint) -> media_status_t ---
+
+ /**
+ * Unselect the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
+ * getSampleTime only retrieve information for the subset of tracks selected.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_unselectTrack :: proc(extractor: ^AMediaExtractor, idx: uint) -> media_status_t ---
+
+ /**
+ * Read the current sample.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_readSampleData :: proc(extractor: ^AMediaExtractor, buffer: [^]u8, capacity: uint) -> int ---
+
+ /**
+ * Read the current sample's flags.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getSampleFlags :: proc(extractor: ^AMediaExtractor) -> SampleFlags ---
+
+ /**
+ * Returns the track index the current sample originates from (or -1
+ * if no more samples are available)
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getSampleTrackIndex :: proc(extractor: ^AMediaExtractor) -> i32 ---
+
+ /**
+ * Returns the current sample's presentation time in microseconds.
+ * or -1 if no more samples are available.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getSampleTime :: proc(extractor: ^AMediaExtractor) -> i64 ---
+
+ /**
+ * Advance to the next sample. Returns false if no more sample data
+ * is available (end of stream).
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_advance :: proc(extractor: ^AMediaExtractor) -> bool ---
+
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaExtractor_seekTo :: proc(extractor: ^AMediaExtractor, seekPosUs: i64, mode: SeekMode) -> media_status_t ---
+
+ /**
+ * Get the PSSH info if present.
+ *
+ * Available since API level 21.
+ */
+ AMediaExtractor_getPsshInfo :: proc(extractor: ^AMediaExtractor) -> ^PsshInfo ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaExtractor_getSampleCryptoInfo :: proc(extractor: ^AMediaExtractor) -> ^AMediaCodecCryptoInfo ---
+
+ /**
+ * Returns the format of the extractor. The caller must free the returned format
+ * using AMediaFormat_delete(format).
+ *
+ * This function will always return a format however, the format could be empty
+ * (no key-value pairs) if the media container does not provide format information.
+ *
+ * Available since API level 28.
+ */
+ AMediaExtractor_getFileFormat :: proc(extractor: ^AMediaExtractor) -> ^AMediaFormat ---
+
+ /**
+ * Returns the size of the current sample in bytes, or -1 when no samples are
+ * available (end of stream). This API can be used in in conjunction with
+ * AMediaExtractor_readSampleData:
+ *
+ * ssize_t sampleSize = AMediaExtractor_getSampleSize(ex)
+ * uint8_t *buf = new uint8_t[sampleSize]
+ * AMediaExtractor_readSampleData(ex, buf, sampleSize)
+ *
+ * Available since API level 28.
+ */
+ AMediaExtractor_getSampleSize :: proc(extractor: ^AMediaExtractor) -> int ---
+
+ /**
+ * Returns the duration of cached media samples downloaded from a network data source
+ * (AMediaExtractor_setDataSource with a "http(s)" URI) in microseconds.
+ *
+ * This information is calculated using total bitrate if total bitrate is not in the
+ * media container it is calculated using total duration and file size.
+ *
+ * Returns -1 when the extractor is not reading from a network data source, or when the
+ * cached duration cannot be calculated (bitrate, duration, and file size information
+ * not available).
+ *
+ * Available since API level 28.
+ */
+ AMediaExtractor_getCachedDuration :: proc(extractor: ^AMediaExtractor) -> i64 ---
+
+ /**
+ * Read the current sample's metadata format into |fmt|. Examples of sample metadata are
+ * SEI (supplemental enhancement information) and MPEG user data, both of which can embed
+ * closed-caption data.
+ *
+ * Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
+ * Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
+ * The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ *
+ * Available since API level 28.
+ */
+ AMediaExtractor_getSampleFormat :: proc(ex: ^AMediaExtractor, fmt: ^AMediaFormat) -> media_status_t ---
+}
diff --git a/media/NdkMediaFormat.odin b/media/NdkMediaFormat.odin
new file mode 100644
index 0000000..d33569e
--- /dev/null
+++ b/media/NdkMediaFormat.odin
@@ -0,0 +1,306 @@
+//+build android
+package mediandk
+
+foreign import mediandk "system:mediandk"
+
+AMediaFormat :: struct{}
+
+AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_DRC_TARGET_REFERENCE_LEVEL: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_ENCODED_TARGET_LEVEL: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AAC_PROFILE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_AAC_SBR_MODE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_AUDIO_SESSION_ID: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_BITRATE_MODE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_BIT_RATE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_CAPTURE_RATE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_CHANNEL_COUNT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_CHANNEL_MASK: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_COLOR_FORMAT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_COLOR_RANGE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_COLOR_STANDARD: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_COLOR_TRANSFER: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_COMPLEXITY: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_CSD: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_CSD_0: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_CSD_1: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_CSD_2: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_DISPLAY_CROP: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_DISPLAY_HEIGHT: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_DISPLAY_WIDTH: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_DURATION: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_FRAME_RATE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_GRID_COLUMNS: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_GRID_ROWS: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_HDR_STATIC_INFO: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_HEIGHT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_IS_ADTS: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_IS_AUTOSELECT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_IS_DEFAULT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_I_FRAME_INTERVAL: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_LANGUAGE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_LATENCY: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_LEVEL: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_MAX_HEIGHT: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_MAX_INPUT_SIZE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_MAX_WIDTH: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_MIME: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_MPEG_USER_DATA: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_OPERATING_RATE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_PCM_ENCODING: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_PRIORITY: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_PROFILE: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_ROTATION: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_SAMPLE_RATE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_SEI: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_SLICE_HEIGHT: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_STRIDE: cstring //__INTRODUCED_IN(21)
+AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TEMPORAL_LAYERING: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TILE_HEIGHT: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TILE_WIDTH: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TIME_US: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TRACK_ID: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_TRACK_INDEX: cstring //__INTRODUCED_IN(28)
+AMEDIAFORMAT_KEY_WIDTH: cstring //__INTRODUCED_IN(21)
+
+
+AMEDIAFORMAT_KEY_ALBUM: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ALBUMART: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ALBUMARTIST: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ARTIST: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_PRESENTATION_ID: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_PROGRAM_ID: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_AUTHOR: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_BITS_PER_SAMPLE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CDTRACKNUMBER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_COMPILATION: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_COMPOSER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CREATE_INPUT_SURFACE_SUSPENDED: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_BYTE_BLOCK: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_SIZES: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_IV: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_KEY: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_MODE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CRYPTO_SKIP_BYTE_BLOCK: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CSD_AVC: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_CSD_HEVC: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_D263: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_DATE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_DISCNUMBER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ENCODER_DELAY: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ENCODER_PADDING: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ESDS: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_EXIF_OFFSET: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_EXIF_SIZE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_FRAME_COUNT: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_GENRE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_ICC_PROFILE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_IS_SYNC_FRAME: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_LOCATION: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_LOOP: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_LYRICIST: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_MANUFACTURER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_MAX_BIT_RATE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_MPEG2_STREAM_HEADER: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_PSSH: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_SAR_HEIGHT: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_SAR_WIDTH: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_TARGET_TIME: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_THUMBNAIL_TIME: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_TITLE: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_VALID_SAMPLES: cstring //__INTRODUCED_IN(29)
+AMEDIAFORMAT_KEY_YEAR: cstring //__INTRODUCED_IN(29)
+
+/**
+ * An optional key describing the low latency decoding mode. This is an optional parameter
+ * that applies only to decoders. If enabled, the decoder doesn't hold input and output
+ * data more than required by the codec standards.
+ * The associated value is an integer (0 or 1): 1 when low-latency decoding is enabled,
+ * 0 otherwise. The default value is 0.
+ *
+ * Available since API level 30.
+ */
+AMEDIAFORMAT_KEY_LOW_LATENCY: cstring //__INTRODUCED_IN(30)
+
+AMEDIAFORMAT_KEY_HDR10_PLUS_INFO: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_XMP_OFFSET: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_XMP_SIZE: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_SAMPLE_FILE_OFFSET: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND: cstring //__INTRODUCED_IN(31)
+
+AMEDIAFORMAT_KEY_PICTURE_TYPE: cstring //__INTRODUCED_IN(33)
+AMEDIAFORMAT_KEY_VIDEO_ENCODING_STATISTICS_LEVEL: cstring //__INTRODUCED_IN(33)
+AMEDIAFORMAT_KEY_VIDEO_QP_AVERAGE: cstring //__INTRODUCED_IN(33)
+
+AMEDIAFORMAT_VIDEO_QP_B_MAX: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_B_MIN: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_I_MAX: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_I_MIN: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_MAX: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_MIN: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_P_MAX: cstring //__INTRODUCED_IN(31)
+AMEDIAFORMAT_VIDEO_QP_P_MIN: cstring //__INTRODUCED_IN(31)
+
+/**
+ * MPEG-H audio profile and level compatibility.
+ *
+ * See FDAmd_2 of ISO_IEC_23008-3;2019 MHAProfileAndLevelCompatibilitySetBox.
+ *
+ * Available since API level 32.
+ */
+AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS: cstring //__INTRODUCED_IN(32)
+
+/**
+ * MPEG-H audio profile level indication.
+ *
+ * See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord mpegh3daProfileLevelIndication.
+ *
+ * Available since API level 32.
+ */
+AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION: cstring //__INTRODUCED_IN(32)
+
+/**
+ * MPEG-H audio reference channel layout.
+ *
+ * See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord referenceChannelLayout
+ * and ISO_IEC_23001‐8 ChannelConfiguration value.
+ *
+ * Available since API level 32.
+ */
+AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT: cstring //__INTRODUCED_IN(32)
+
+foreign mediandk {
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_new :: proc() -> ^AMediaFormat ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_delete :: proc(format: ^AMediaFormat) -> media_status_t ---
+
+ /**
+ * Human readable representation of the format. The returned string is owned by the format,
+ * and remains valid until the next call to toString, or until the format is deleted.
+ *
+ * Available since API level 21.
+ */
+ AMediaFormat_toString :: proc(format: ^AMediaFormat) -> cstring ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_getInt32 :: proc(format: ^AMediaFormat, name: cstring, out: ^i32) -> bool ---
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_getInt64 :: proc(format: ^AMediaFormat, name: cstring, out: ^i64) -> bool ---
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_getFloat :: proc(format: ^AMediaFormat, name: cstring, out: ^f32) -> bool ---
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_getSize :: proc(format: ^AMediaFormat, name: cstring, out: ^uint) -> bool ---
+ /**
+ * The returned data is owned by the format and remains valid as long as the named entry
+ * is part of the format.
+ *
+ * Available since API level 21.
+ */
+ AMediaFormat_getBuffer :: proc(format: ^AMediaFormat, name: cstring, data: ^rawptr, size: ^uint) -> bool ---
+ /**
+ * The returned string is owned by the format, and remains valid until the next call to getString,
+ * or until the format is deleted.
+ *
+ * Available since API level 21.
+ */
+ AMediaFormat_getString :: proc(format: ^AMediaFormat, name: cstring, out: ^cstring) -> bool ---
+
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_setInt32 :: proc(format: ^AMediaFormat, name: cstring, value: i32) ---
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_setInt64 :: proc(format: ^AMediaFormat, name: cstring, value: i64) ---
+ /**
+ * Available since API level 21.
+ */
+ AMediaFormat_setFloat :: proc(format: ^AMediaFormat, name: cstring, value: f32) ---
+ /**
+ * The provided string is copied into the format.
+ *
+ * Available since API level 21.
+ */
+ AMediaFormat_setString :: proc(format: ^AMediaFormat, name: cstring, value: cstring) ---
+ /**
+ * The provided data is copied into the format.
+ *
+ * Available since API level 21.
+ */
+ AMediaFormat_setBuffer :: proc(format: ^AMediaFormat, name: cstring, data: rawptr, size: uint) ---
+
+ /**
+ * Available since API level 28.
+ */
+ AMediaFormat_getDouble :: proc(format: ^AMediaFormat, name: cstring, out: ^f64) -> bool ---
+ /**
+ * Available since API level 28.
+ */
+ AMediaFormat_getRect :: proc(format: ^AMediaFormat, name: cstring, left: ^i32, top: ^i32, right: ^i32, bottom: ^i32) -> bool ---
+
+ /**
+ * Available since API level 28.
+ */
+ AMediaFormat_setDouble :: proc(format: ^AMediaFormat, name: cstring, value: f64) ---
+ /**
+ * Available since API level 28.
+ */
+ AMediaFormat_setSize :: proc(format: ^AMediaFormat, name: cstring, value: uint) ---
+ /**
+ * Available since API level 28.
+ */
+ AMediaFormat_setRect :: proc(format: ^AMediaFormat, name: cstring, left: i32, top: i32, right: i32, bottom: i32) ---
+
+ /**
+ * Remove all key/value pairs from the given AMediaFormat.
+ *
+ * Available since API level 29.
+ */
+ AMediaFormat_clear :: proc(format: ^AMediaFormat) ---
+
+ /**
+ * Copy one AMediaFormat to another.
+ *
+ * Available since API level 29.
+ */
+ AMediaFormat_copy :: proc(to: ^AMediaFormat, from: ^AMediaFormat) -> media_status_t ---
+}
diff --git a/media/NdkMediaMuxer.odin b/media/NdkMediaMuxer.odin
new file mode 100644
index 0000000..9f00094
--- /dev/null
+++ b/media/NdkMediaMuxer.odin
@@ -0,0 +1,146 @@
+//+build android
+package mediandk
+
+foreign import mediandk "system:mediandk"
+
+OutputFormat :: enum i32 {
+ MPEG_4 = 0,
+ WEBM = 1,
+ THREE_GPP = 2,
+}
+
+AppendMode :: enum i32 {
+ /* Last group of pictures(GOP) of video track can be incomplete, so it would be safe to
+ * scrap that and rewrite. If both audio and video tracks are present in a file, then
+ * samples of audio track after last GOP of video would be scrapped too.
+ * If only audio track is present, then no sample would be discarded.
+ */
+ IGNORE_LAST_VIDEO_GOP = 0,
+ // Keep all existing samples as it is and append new samples after that only.
+ TO_EXISTING_DATA = 1,
+}
+
+AMediaMuxer :: struct{}
+
+foreign mediandk {
+ /**
+ * Create new media muxer.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_new :: proc(fd: i32, format: OutputFormat) -> ^AMediaMuxer ---
+
+ /**
+ * Delete a previously created media muxer.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_delete :: proc(muxer: ^AMediaMuxer) -> media_status_t ---
+
+ /**
+ * Set and store the geodata (latitude and longitude) in the output file.
+ * This method should be called before AMediaMuxer_start. The geodata is stored
+ * in udta box if the output format is AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, and is
+ * ignored for other output formats.
+ * The geodata is stored according to ISO-6709 standard.
+ *
+ * Both values are specified in degrees.
+ * Latitude must be in the range [-90, 90].
+ * Longitude must be in the range [-180, 180].
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_setLocation :: proc(muxer: ^AMediaMuxer, latitude: f32, longitude: f32) -> media_status_t ---
+
+ /**
+ * Sets the orientation hint for output video playback.
+ * This method should be called before AMediaMuxer_start. Calling this
+ * method will not rotate the video frame when muxer is generating the file,
+ * but add a composition matrix containing the rotation angle in the output
+ * video if the output format is AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, so that a
+ * video player can choose the proper orientation for playback.
+ * Note that some video players may choose to ignore the composition matrix
+ * during playback.
+ * The angle is specified in degrees, clockwise.
+ * The supported angles are 0, 90, 180, and 270 degrees.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_setOrientationHint :: proc(muxer: ^AMediaMuxer, degrees: i32) -> media_status_t ---
+
+ /**
+ * Adds a track with the specified format.
+ * Returns the index of the new track or a negative value in case of failure,
+ * which can be interpreted as a media_status_t.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_addTrack :: proc(muxer: ^AMediaMuxer, format: ^AMediaFormat) -> int ---
+
+ /**
+ * Start the muxer. Should be called after AMediaMuxer_addTrack and
+ * before AMediaMuxer_writeSampleData.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_start :: proc(muxer: ^AMediaMuxer) -> media_status_t ---
+
+ /**
+ * Stops the muxer.
+ * Once the muxer stops, it can not be restarted.
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_stop :: proc(muxer: ^AMediaMuxer) -> media_status_t ---
+
+ /**
+ * Writes an encoded sample into the muxer.
+ * The application needs to make sure that the samples are written into
+ * the right tracks. Also, it needs to make sure the samples for each track
+ * are written in chronological order (e.g. in the order they are provided
+ * by the encoder.)
+ *
+ * Available since API level 21.
+ */
+ AMediaMuxer_writeSampleData :: proc(muxer: ^AMediaMuxer, trackIdx: uint, data: [^]u8, info: ^AMediaCodecBufferInfo) -> media_status_t ---
+
+ /**
+ * Creates a new media muxer for appending data to an existing MPEG4 file.
+ * This is a synchronous API call and could take a while to return if the existing file is large.
+ * Only works for MPEG4 files matching one of the following characteristics:
+ *
+ * - a single audio track.
+ * - a single video track.
+ * - a single audio and a single video track.
+ *
+ * @param fd Must be opened with read and write permission. Does not take ownership of
+ * this fd i.e., caller is responsible for closing fd.
+ * @param mode Specifies how data will be appended the AppendMode enum describes
+ * the possible methods for appending..
+ * @return Pointer to AMediaMuxer if the file(fd) has tracks already, otherwise, nullptr.
+ * {@link AMediaMuxer_delete} should be used to free the returned pointer.
+ *
+ * Available since API level 31.
+ */
+ AMediaMuxer_append :: proc(fd: i32, mode: AppendMode) -> ^AMediaMuxer ---
+
+ /**
+ * Returns the number of tracks added in the file passed to {@link AMediaMuxer_new} or
+ * the number of existing tracks in the file passed to {@link AMediaMuxer_append}.
+ * Should be called in INITIALIZED or STARTED state, otherwise returns -1.
+ *
+ * Available since API level 31.
+ */
+ AMediaMuxer_getTrackCount :: proc(muxer: ^AMediaMuxer) -> int ---
+
+ /**
+ * Returns AMediaFormat of the added track with index idx in the file passed to
+ * {@link AMediaMuxer_new} or the AMediaFormat of the existing track with index idx
+ * in the file passed to {@link AMediaMuxer_append}.
+ * Should be called in INITIALIZED or STARTED state, otherwise returns nullptr.
+ * {@link AMediaFormat_delete} should be used to free the returned pointer.
+ *
+ * Available since API level 31.
+ */
+ AMediaMuxer_getTrackFormat :: proc(muxer: ^AMediaMuxer, idx: uint) -> ^AMediaFormat ---
+}
diff --git a/sensor.odin b/sensor.odin
index a88898e..d5c4286 100644
--- a/sensor.odin
+++ b/sensor.odin
@@ -48,6 +48,11 @@ SensorType :: enum i32 {
* field in the X, Y and Z axis.
*/
MAGNETIC_FIELD = 2,
+
+ /* Deprecated in API level 15
+ * This isn't defined in the NDK but the procedures report it as a valid sensor and can work with it.
+ */
+ ORIENTATION = 3,
/**
* {@link ASENSOR_TYPE_GYROSCOPE}
* reporting-mode: continuous
@@ -69,6 +74,11 @@ SensorType :: enum i32 {
* The pressure sensor value is returned in hPa (millibar).
*/
PRESSURE = 6,
+
+ /* Deprecated in API level 15. Use AMBIENT_TEMPERATURE instead.
+ * This isn't defined in the NDK but the procedures report it as a valid sensor and can work with it.
+ */
+ TEMPERATURE = 7,
/**
* {@link ASENSOR_TYPE_PROXIMITY}
* reporting-mode: on-change
@@ -381,8 +391,6 @@ ASensorVector :: struct {
reserved: [3]u8,
}
-// TODO: sensor might be SensorType here, will need some code to confirm though.
-// Not sure what "what" is, maybe code will confirm this too.
AMetaDataEvent :: struct {
what: i32,
sensor: i32,