/*

 * Copyright (c) 2026 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

/**

 * @addtogroup OHMIDI

 * @{

 *

 * @brief Provides the definition of the C interface for the MIDI module.

 *

 * @since 24

 */

/**

 * @file native_midi_base.h

 *

 * @brief Declares the underlying data structure for MIDI module.

 *

 * @library libohmidi.so

 * @syscap SystemCapability.Multimedia.Audio.MIDI

 * @kit AudioKit

 * @since 24

 */

#ifndef NATIVE_MIDI_BASE_H

#define NATIVE_MIDI_BASE_H



#include <stdbool.h>

#include <stddef.h>

#include <stdint.h>





#ifdef __cplusplus

extern "C" {

#endif



/**

 * @brief MIDI status code enumeration.

 *

 * @since 24

 */

typedef enum {

    /**

     * @error Operation successful.

     *

     * @since 24

     */

    OH_MIDI_STATUS_OK = 0,



    /**

     * @error Invalid parameter (e.g., null pointer).

     *

     * @since 24

     */

    OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT = 35500001,



    /**

     * @error IPC communication failure.

     *

     * @since 24

     */

    OH_MIDI_STATUS_GENERIC_IPC_FAILURE = 35500002,



    /**

     * @error Invalid client handle.

     *

     * @since 24

     */

    OH_MIDI_STATUS_INVALID_CLIENT = 35500003,



    /**

     * @error Invalid device handle.

     *

     * @since 24

     */

    OH_MIDI_STATUS_INVALID_DEVICE_HANDLE = 35500004,



    /**

     * @error Invalid port index.

     *

     * @since 24

     */

    OH_MIDI_STATUS_INVALID_PORT = 35500005,



    /**

     * @error The send buffer is transiently full.

     * Indicates that the shared memory buffer currently lacks space.

     * Returned by non-blocking send when a message cannot fit in the buffer.

     * Retry the operation with a short delay (recommended: 10ms).

     *

     * @since 24

     */

    OH_MIDI_STATUS_WOULD_BLOCK = 35500006,



    /**

     * @error Operation can not be handled in a reasonable time.

     *

     * @since 24

     */

    OH_MIDI_STATUS_TIMEOUT = 35500007,



    /**

     * @error The client has reached the maximum number of open devices allowed.

     * To open a new device, the client must close an existing one first.

     *

     * @since 24

     */

    OH_MIDI_STATUS_TOO_MANY_OPEN_DEVICES = 35500008,



    /**

     * @error The client has reached the maximum number of open ports allowed.

     * To open a new port, the client must close an existing one first.

     *

     * @since 24

     */

    OH_MIDI_STATUS_TOO_MANY_OPEN_PORTS = 35500009,



    /**

     * @error The client has already opened this device.

     *

     * @since 24

     */

    OH_MIDI_STATUS_DEVICE_ALREADY_OPEN = 35500010,



    /**

     * @error The client has already opened this port.

     *

     * @since 24

     */

    OH_MIDI_STATUS_PORT_ALREADY_OPEN = 35500011,



    /**

     * @error The system-wide or per-application limit for MIDI clients has been reached.

     * The application should wait or release other resources before retrying.

     *

     * @since 24

     */

    OH_MIDI_STATUS_TOO_MANY_CLIENTS = 35500012,



    /**

     * @error Permission denied.

     * Returned when the application attempts to perform an operation

     * without the required permission (e.g., Bluetooth for BLE devices).

     *

     * @since 24

     */

    OH_MIDI_STATUS_PERMISSION_DENIED = 35500013,



    /**

     * @error The MIDI system service has died or disconnected.

     * The client must be destroyed and recreated.

     *

     * @since 24

     */

    OH_MIDI_STATUS_SERVICE_DIED = 35500014,



    /**

     * @error System-level errors such as insufficient memory or system service failure.

     *

     * @since 24

     */

    OH_MIDI_STATUS_SYSTEM_ERROR = 35500100

} OH_MIDIStatusCode;



/**

 * @brief Port direction enumeration.

 *

 * @since 24

 */

typedef enum {

    /**

     * @brief Input port (Device -> Host).

     *

     * @since 24

     */

    OH_MIDI_PORT_DIRECTION_INPUT = 0,



    /**

     * @brief Output port (Host -> Device).

     *

     * @since 24

     */

    OH_MIDI_PORT_DIRECTION_OUTPUT = 1

} OH_MIDIPortDirection;



/**

 * @brief MIDI transport protocol semantics.

 *

 * @note **CRITICAL**: The SDK always uses UMP (Universal MIDI Packet) format for data transfer,

 * regardless of the selected protocol. This enum defines the "Behavior" and "Semantics"

 * of the connection, not the data structure.

 *

 * @since 24

 */

typedef enum {

    /**

     * @brief Legacy MIDI 1.0 Semantics.

     * Behavior:

     * - The service expects UMP packets strictly compatible with MIDI 1.0.

     * - **MT 0x0**: Utility Messages (e.g., Timestamps).

     * - **MT 0x1**: System Real Time and System Common Messages.

     * - **MT 0x2**: MIDI 1.0 Channel Voice Messages (32-bit).

     * - **MT 0x3**: Data Messages (64-bit) used for SysEx (7-bit payload).

     * - If the target hardware is MIDI 1.0: The service converts UMP back to byte stream (F0...F7).

     * - If the target hardware is MIDI 2.0: The service sends these packets as-is (encapsulated MIDI 1.0).

     *

     * @since 24

     */

    OH_MIDI_PROTOCOL_1_0 = 1,



    /**

     * @brief MIDI 2.0 Semantics.

     * Behavior:

     * - The service expects UMP packets leveraging MIDI 2.0 features.

     * - **MT 0x4**: MIDI 2.0 Channel Voice Messages (64-bit, high resolution).

     * - **MT 0x0**: Utility Messages (Timestamps).

     * - **MT 0xD**: Flex Data Messages (128-bit, e.g., Text, Lyrics).

     * - **MT 0xF**: UMP Stream Messages (128-bit, Endpoint Discovery, Function Blocks).

     * - **MT 0x3 / MT 0x5**: Data Messages (64-bit or 128-bit).

     * @note Fallback Policy: If this protocol is requested but the hardware only supports MIDI 1.0,

     * the service will perform "Best-Effort" translation (e.g., downscaling 32-bit velocity

     * to 7-bit, converting Type 4 back to Type 2). Some data precision or message types (like Flex Data)

     * may be lost or ignored.

     *

     * @since 24

     */

    OH_MIDI_PROTOCOL_2_0 = 2

} OH_MIDIProtocol;



/**

 * @brief MIDI Device type.

 *

 * @since 24

 */

typedef enum {

    /**

     * @brief USB MIDI device.

     *

     * @since 24

     */

    OH_MIDI_DEVICE_TYPE_USB = 0,



    /**

     * @brief Bluetooth Low Energy MIDI device.

     *

     * @since 24

     */

    OH_MIDI_DEVICE_TYPE_BLE = 1

} OH_MIDIDeviceType;



/**

 * @brief Device connection state change action.

 *

 * @since 24

 */

typedef enum {

    /**

     * @brief Device connected.

     *

     * @since 24

     */

    OH_MIDI_DEVICE_CHANGE_ACTION_CONNECTED = 0,



    /**

     * @brief Device disconnected.

     *

     * @since 24

     */

    OH_MIDI_DEVICE_CHANGE_ACTION_DISCONNECTED = 1

} OH_MIDIDeviceChangeAction;



/**

 * @brief MIDI Event Structure (Universal).

 * The event data is transferred in Universal MIDI Packets (UMP) format.

 * MIDI 1.0 byte stream data should be converted to UMP format before

 * filling this structure.

 *

 * @since 24

 */

typedef struct {

    /**

     * @brief Timestamp in nanoseconds.

     * Base time obtained via clock_gettime(CLOCK_MONOTONIC, &time)

     * 0 indicates "send immediately".

     *

     * @since 24

     */

    uint64_t timestamp;



    /**

     * @brief Number of 32-bit words in the packet.

     * e.g., 1 for Type 2/4 (64-bit messages use 2 words)

     *

     * @since 24

     */

    size_t length;



    /**

     * @brief Pointer to UMP data (Must be 4-byte aligned).

     * This contains the raw UMP words (uint32_t).

     *

     * @since 24

     */

    uint32_t *data;

} OH_MIDIEvent;



/**

 * @brief Device Information.

 * Used for enumeration and display.

 *

 * @since 24

 */

typedef struct {

    /**

     * @brief Unique identifier for the MIDI device.

     *

     * @since 24

     */

    int64_t midiDeviceId;



    /**

     * @brief Type of the device (USB, BLE, etc.).

     *

     * @since 24

     */

    OH_MIDIDeviceType deviceType;



    /**

     * @brief The native protocol supported by the hardware.

     *

     * - If OH_MIDI_PROTOCOL_1_0: The device is a legacy device or currently configured as such.

     * - If OH_MIDI_PROTOCOL_2_0: The device supports MIDI 2.0 features.

     * @note Applications can use this to decide whether to enable high-resolution UI controls.

     *

     * @since 24

     */

    OH_MIDIProtocol nativeProtocol;



    /**

     * @brief Device name.

     *

     * @since 24

     */

    char deviceName[256];



    /**

     * @brief Vendor ID.

     *

     * @since 24

     */

    uint64_t vendorId;



    /**

     * @brief Product ID.

     *

     * @since 24

     */

    uint64_t productId;



    /**

     * @brief Physical address (for BLE device).

     *

     * @since 24

     */

    char deviceAddress[64];

} OH_MIDIDeviceInformation;



/**

 * @brief Port Information (detailed).

 * Used for enumeration (contains display names).

 *

 * @since 24

 */

typedef struct {

    /**

     * @brief The index of the port.

     *

     * @since 24

     */

    uint32_t portIndex;



    /**

     * @brief The ID of the device this port belongs to.

     *

     * @since 24

     */

    int64_t deviceId;



    /**

     * @brief Direction of the port (Input/Output).

     *

     * @since 24

     */

    OH_MIDIPortDirection direction;



    /**

     * @brief Name of the port.

     *

     * @since 24

     */

    char name[64];

} OH_MIDIPortInformation;



/**

 * @brief Port Descriptor.

 *

 * @since 24

 */

typedef struct {

    /**

     * @brief The unique ID of the port within the device (index).

     *

     * @since 24

     */

    uint32_t portIndex;



    /**

     * @brief The requested protocol behavior for this session.

     *

     * This field dictates how the Service translates data between the app and the hardware.

     *

     * **Compatibility Behavior:**

     *

     * 1. **Request OH_MIDI_PROTOCOL_1_0 on a 2.0 Device**: (Safe)

     * - The service creates a virtual 1.0 view.

     * - App sends UMP Type 2 (MIDI 1.0 Channel Voice).

     * - Device receives UMP Type 2.

     * - Fully compatible.

     *

     * 2. **Request OH_MIDI_PROTOCOL_2_0 on a 1.0 Device**: (Lossy)

     * - The service creates a virtual 2.0 view.

     * - App sends UMP Type 4 (MIDI 2.0 Voice).

     * - Service **down-converts** Type 4 to Type 2 (e.g., clipping velocity, dropping per-note data).

     * - **Warning**: Data precision will be lost. Advanced messages may be dropped.

     *

     * @since 24

     */

    OH_MIDIProtocol protocol;

} OH_MIDIPortDescriptor;



/**

 * @brief Declares a MIDI client.

 *

 * @since 24

 */

typedef struct OH_MIDIClientStruct OH_MIDIClient;



/**

 * @brief Declares a MIDI device.

 *

 * @since 24

 */

typedef struct OH_MIDIDeviceStruct OH_MIDIDevice;



/**

 * @brief Callback for monitoring device connection/disconnection.

 *

 * @param userData The user context pointer passed to {@link #OH_MIDIClient_Create}.

 * @param action Device change action (connected/disconnected).

 * @param deviceInfo Information of the changed device.

 *

 * @since 24

 */

typedef void (*OH_MIDICallback_OnDeviceChange)(

    void *userData, OH_MIDIDeviceChangeAction action, OH_MIDIDeviceInformation deviceInfo);



/**

 * @brief Callback for handling client-level errors.

 * Invoked when a critical error occurs in the MIDI service (e.g., service crash).

 * Applications may need to recreate the client when this occurs.

 *

 * @param userData The user context pointer passed to {@link #OH_MIDIClient_Create}.

 * @param code The error code indicating the cause.

 *

 * @since 24

 */

typedef void (*OH_MIDICallback_OnError)(void *userData, OH_MIDIStatusCode code);



/**

 * @brief Callback for receiving MIDI data (Batch Processing).

 *

 * @warning **CRITICAL: Memory Safety**

 * The events array and all data pointers within it

 * are **transient and ONLY valid during this callback**.

 * Accessing these pointers after the callback returns

 * causes **undefined behavior** (crashes, memory corruption).

 * You MUST copy any data you need to keep.

 *

 * @warning This callback is invoked on a high-priority system thread.

 * Do **not** perform blocking operations, heavy computation, or I/O.

 *

 * @param userData The user context pointer passed to {@link #OH_MIDIDevice_OpenInputPort}.

 * @param events Pointer to the array of MIDI events received.

 * @param eventCount The number of events in the array.

 *

 * @since 24

 */

typedef void (*OH_MIDIDevice_OnReceived)(void *userData, const OH_MIDIEvent *events, size_t eventCount);



/**

 * @brief Callback for the result of asynchronously opening a BLE device.

 *

 * This callback is invoked when the BLE device open attempt finishes, either successfully

 * or with a failure.

 *

 * @param userData The user context pointer passed to {@link #OH_MIDIClient_OpenBLEDevice}.

 * @param opened Indicates whether the device was successfully opened.

 *     True: Device successfully opened, device handle is valid.

 *     False: Device open failed, device handle is NULL.

 * @param device The handle of the opened device.

 *     If opened is true, the application MUST close this handle using

 * {@link #OH_MIDIClient_CloseDevice} when it is no longer needed.

 *     If opened is false, this parameter is NULL.

 * @param info The information of the opened device.

 * Note: This object is valid ONLY within the scope of this callback.

 *     If you need to persist specific attributes (e.g., ID or Name), copy them.

 *

 * @since 24

 */

typedef void (*OH_MIDIClient_OnDeviceOpened)(void *userData,

                                             bool opened,

                                             OH_MIDIDevice *device,

                                             OH_MIDIDeviceInformation info);



/**

 * @brief Client callbacks structure.

 *

 * @since 24

 */

typedef struct {

    /**

     * @brief Handler for device hotplug events.

     *

     * @since 24

     */

    OH_MIDICallback_OnDeviceChange onDeviceChange;



    /**

     * @brief Handler for critical service errors.

     *

     * @since 24

     */

    OH_MIDICallback_OnError onError;

} OH_MIDICallbacks;



#ifdef __cplusplus

}

#endif

/** @} */

#endif // NATIVE_MIDI_BASE_H