/*

 * 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.h

 *

 * @brief Declares MIDI related interfaces.

 *

 * MIDI is a technical standard that enables communication between electronic

 * musical instruments, computers, and other devices. The interfaces in this

 * file are used for MIDI device management, MIDI events sending and receiving,

 * and device status monitoring.

 *

 * A common case of using OHMIDI to connect with MIDI device works as follows:

 *

 * <pre>

 * OH_MIDIClient_Create(&client, callbacks, userData);

 *

 * OH_MIDIClient_GetDeviceCount(client, &deviceCount);

 * // The developer should allocate a buffer for 'deviceInfos' based on 'deviceCount'.

 * OH_MIDIClient_GetDeviceInfos(client, deviceInfos, deviceCount, &actualDeviceCount);

 *

 * // Iterate through 'deviceInfos' to get the 'midiDeviceId' and query its ports.

 * OH_MIDIClient_GetPortCount(client, midiDeviceId, &portCount);

 * // The developer should allocate a buffer for 'portInfos' based on 'portCount'.

 * OH_MIDIClient_GetPortInfos(client, midiDeviceId, portInfos, portCount, &actualPortCount);

 *

 * OH_MIDIClient_OpenDevice(client, midiDeviceId, &device);

 * // Or use OH_MIDIClient_OpenBLEDevice to open a BLE device,

 * // waiting for the OH_MIDIClient_OnDeviceOpened callback.

 *

 * // Get the port descriptor from the 'portInfos' array to open the ports.

 * OH_MIDIDevice_OpenInputPort(device, inputportDesc, onMidiReceivedCallback, userData);

 * // The 'onMidiReceivedCallback' is triggered upon receiving MIDI messages.

 *

 * OH_MIDIDevice_OpenOutputPort(device, outputportDesc);

 * OH_MIDIDevice_Send(device, outputportIndex, events, eventCount, &writtenEventCount);

 *

 * ...

 *

 * OH_MIDIClient_CloseDevice(client, device);

 * // Use OH_MIDIDevice_CloseInputPort and OH_MIDIDevice_CloseOutputPort to close specific ports.

 * OH_MIDIClient_Destroy(client);

 * </pre>

 *

 * @library libohmidi.so

 * @syscap SystemCapability.Multimedia.Audio.MIDI

 * @kit AudioKit

 * @since 24

 */



#ifndef NATIVE_MIDI_H

#define NATIVE_MIDI_H



#include "native_midi_base.h"



#ifdef __cplusplus

extern "C" {

#endif



/**

 * @brief Creates a MIDI client instance.

 *

 * @note **Resource Management & Best Practices**:

 *     MIDI is a delay-sensitive system service. To ensure real-time performance (QoS)

 *     and system stability, the service enforces the following limits:

 *     1. **System-wide limit**: A global maximum number of active MIDI clients that are allowed.

 *     2. **Per-Application limit**: A maximum number of MIDI clients that are allowed per app uid.

 *

 *     Applications are **strongly recommended** to maintain a single `OH_MIDIClient`

 *     instance throughout their lifecycle and use it to manage multiple devices/ports.

 *

 *     Use {@link #OH_MIDIClient_Destroy} to release the client and all associated resources.

 *

 * @param client Pointer to receive the new client handle.

 * @param callbacks Callback structure for system events.

 * @param userData User context to be passed to callbacks.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds,

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if client is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 *     or {@link #OH_MIDI_STATUS_TOO_MANY_CLIENTS} if creation failed due to resource limits.

 *         This occurs if the calling application exceeded its per-uid quota or the system is busy.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_Create(OH_MIDIClient **client, OH_MIDICallbacks callbacks, void *userData);



/**

 * @brief Destroys the MIDI client and releases resources.

 *

 * @note Destroying the client will close all devices and ports (fail-safe mechanism) automatically.

 *     It is recommended to close resources in reverse order (ports->devices->client) for code clarity,

 *     but this is not a mandatory requirement.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is null or invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_Destroy(OH_MIDIClient *client);



/**

 * @brief Gets the number of connected MIDI devices.

 *

 * This function is used to determine the size of the array needed to get devices information.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param count Pointer to receive the number of devices.

 * @return {@link #OH_MIDI_STATUS_OK} on success.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if count is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_GetDeviceCount(const OH_MIDIClient *client, size_t *count);



/**

 * @brief Gets the information of connected MIDI devices.

 *

 * Fills the user-allocated array with devices information.

 *

 * @note The actual number of connected devices may be larger than the capacity of the input parameter

 *     'infos' array. If this happens, the output 'infos' array will only contain partial devices information,

 *     the output 'actualDeviceCount' will be equal to 'capacity', and the function returns {@link #OH_MIDI_STATUS_OK}.

 *     If the actual number is less than or equal to 'capacity', all available devices information

 *     will be filled into 'infos', and the output 'actualDeviceCount' reflects the actual devices number.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param infos A user-allocated array to get devices information.

 * @param capacity The allocated size of 'infos' array.

 * @param actualDeviceCount Pointer to receive the actual number of devices filled into the 'infos' array.

 * @return {@link #OH_MIDI_STATUS_OK} on success.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if infos or actualDeviceCount is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_GetDeviceInfos(const OH_MIDIClient *client,

                                               OH_MIDIDeviceInformation *infos,

                                               size_t capacity,

                                               size_t *actualDeviceCount);



/**

 * @brief Opens a MIDI device.

 *

 * @note Use {@link #OH_MIDIClient_CloseDevice} to release the device resource.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param deviceId Device ID.

 * @param device Pointer to receive the device handle, allocated by the system.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_DEVICE_ALREADY_OPEN} if device is already opened by this client.

 *     or {@link #OH_MIDI_STATUS_TOO_MANY_OPEN_DEVICES} if the client has reached the maximum number of open devices.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if device is null or the deviceId does not exist.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_OpenDevice(OH_MIDIClient *client, int64_t deviceId, OH_MIDIDevice **device);



/**

 * @brief Opens MIDI BLE device asynchronously.

 *

 * Initiates the opening of a Bluetooth LE MIDI device. This function returns immediately,

 * and the result is delivered via the provided callback.

 *

 * @note This function triggers a BLE scan so the opening process may take time.

 *     Use {@link #OH_MIDIClient_CloseDevice} to release the device resource.

 *

 * @permission ohos.permission.ACCESS_BLUETOOTH

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param deviceAddr The MAC address of the BLE device (e.g., "AA:BB:CC:DD:EE:FF").

 * @param callback The callback function to be invoked when the open process completes.

 * @param userData User context pointer to be passed to the callback.

 * @return {@link #OH_MIDI_STATUS_OK} if the open request was successfully dispatched.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_DEVICE_ALREADY_OPEN} if device is already opened by this client.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if deviceAddr or callback is null.

 *     or {@link #OH_MIDI_STATUS_PERMISSION_DENIED} if Bluetooth permission is missing.

 *     or {@link #OH_MIDI_STATUS_TOO_MANY_OPEN_DEVICES} if the client has reached the maximum number of open devices.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if the service is unreachable.

 * @warning If Bluetooth permission is denied, the {@link #OH_MIDIClient_OnDeviceOpened} will be

 *     invoked with opened parameter set to false and device parameter set to null. The application

 *     should check the opened parameter before attempting to use the device handle.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_OpenBLEDevice(OH_MIDIClient *client,

                                              const char *deviceAddr,

                                              OH_MIDIClient_OnDeviceOpened callback,

                                              void *userData);



/**

 * @brief Closes the MIDI device.

 *

 * @note Closing a device automatically closes all opened ports on that device.

 *     Paired with {@link #OH_MIDIClient_OpenDevice} or {@link #OH_MIDIClient_OpenBLEDevice}.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param device Target device handle, generated by {@link OH_MIDIClient_OpenDevice}

 *     or {@link OH_MIDIClient_OpenBLEDevice}.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_CloseDevice(OH_MIDIClient *client, OH_MIDIDevice *device);



/**

 * @brief Gets the number of ports for a specific MIDI device.

 *

 * This function is used to determine the size of the array needed to get ports information.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param deviceId The target device ID.

 * @param count Pointer to receive the number of ports.

 * @return {@link #OH_MIDI_STATUS_OK} on success.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if count is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if deviceId is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_GetPortCount(const OH_MIDIClient *client, int64_t deviceId, size_t *count);



/**

 * @brief Get the port information of a specific MIDI device.

 *

 * Fills the user-allocated buffer with port information.

 *

 * @note The actual number of connected devices may be larger than the capacity of the input parameter

 *     'infos' array. If this happens, the output 'infos' array will only contain partial devices information,

 *     the output 'actualPortCount' will be equal to 'capacity', and the function returns {@link #OH_MIDI_STATUS_OK}.

 *     If the actual number is less than or equal to 'capacity', all available ports information

 *     will be filled into 'infos', and the output 'actualPortCount' reflects the actual ports number.

 *

 * @param client The MIDI client handle, generated by {@link OH_MIDIClient_Create}.

 * @param deviceId The target device ID.

 * @param infos A user-allocated array to get ports information.

 * @param capacity The allocated size of 'infos' array.

 * @param actualPortCount Pointer to receive the actual number of ports filled into the 'infos' array.

 * @return {@link #OH_MIDI_STATUS_OK} on success.

 *     or {@link #OH_MIDI_STATUS_INVALID_CLIENT} if client is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if infos or actualPortCount is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if deviceId is invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIClient_GetPortInfos(const OH_MIDIClient *client,

                                             int64_t deviceId,

                                             OH_MIDIPortInformation *infos,

                                             size_t capacity,

                                             size_t *actualPortCount);



/**

 * @brief Opens a MIDI input port (Receive data).

 *

 * Registers a callback to receive MIDI data in batches.

 *

 * @note Use {@link #OH_MIDIDevice_CloseInputPort} to close the input port.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param descriptor Port index and protocol configuration.

 * @param callback Callback function invoked when data is available.

 * @param userData User context to be passed to callbacks.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if the port is invalid or not an input port.

 *     or {@link #OH_MIDI_STATUS_PORT_ALREADY_OPEN} if the port is already opened by this client.

 *     or {@link #OH_MIDI_STATUS_TOO_MANY_OPEN_PORTS} if the maximum number of open ports has been reached.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if callback is null.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_OpenInputPort(

    OH_MIDIDevice *device, OH_MIDIPortDescriptor descriptor, OH_MIDIDevice_OnReceived callback, void *userData);



/**

 * @brief Opens a MIDI output port (Send data).

 *

 * @note Use {@link #OH_MIDIDevice_CloseOutputPort} to close the output port.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param descriptor Port index and protocol configuration.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if the port is invalid or not an output port.

 *     or {@link #OH_MIDI_STATUS_PORT_ALREADY_OPEN} if the port is already opened by this client.

 *     or {@link #OH_MIDI_STATUS_TOO_MANY_OPEN_PORTS} if the maximum number of open ports has been reached.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_OpenOutputPort(OH_MIDIDevice *device, OH_MIDIPortDescriptor descriptor);



/**

 * @brief Closes the MIDI input port.

 *

 * @note Paired with {@link #OH_MIDIDevice_OpenInputPort}.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param portIndex Input port index to close.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if portIndex is invalid or not an open input port.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_CloseInputPort(OH_MIDIDevice *device, uint32_t portIndex);



/**

 * @brief Closes the MIDI output port.

 *

 * @note Paired with {@link #OH_MIDIDevice_OpenOutputPort}.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param portIndex Output port index to close.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if portIndex is invalid or not an open output port.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_CloseOutputPort(OH_MIDIDevice *device, uint32_t portIndex);



/**

 * @brief Sends MIDI events (Batch, Non-blocking & Atomic).

 *

 * Attempts to write an array of events to the shared memory buffer.

 *

 * - Atomicity: Each event in the array is treated atomically.

 * It is either fully written or not written at all.

 * - Partial Success: If the buffer becomes full midway, the function returns

 * {@link #OH_MIDI_STATUS_WOULD_BLOCK} and sets eventsWritten to the number of events

 * successfully enqueued.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param portIndex Target port index.

 * @param events Pointer to the array of events to send, the memory space needs to be allocated

 *     by developer.

 * @param eventCount Number of events in the array.

 * @param eventsWritten Returns the number of events successfully consumed.

 * @return {@link #OH_MIDI_STATUS_OK} if all events were written.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if portIndex is invalid, or not open.

 *     or {@link #OH_MIDI_STATUS_WOULD_BLOCK} if buffer is full (check eventsWritten).

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if arguments are invalid.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_Send(OH_MIDIDevice *device, uint32_t portIndex,

    const OH_MIDIEvent *events, uint32_t eventCount, uint32_t *eventsWritten);



/**

 * @brief Sends a large SysEx message (Byte-Stream to UMP Helper).

 *

 * This is a utility function for applications that handle SysEx as raw byte streams(MIDI 1.0 style, F0...F7).

 * This works for both OH_MIDI_PROTOCOL_1_0 and OH_MIDI_PROTOCOL_2_0 sessions.

 * The underlying service handles the final conversion based on the device's actual capabilities.

 *

 * How it works:

 * 1. It automatically fragments the raw bytes into a sequence of UMP Type 3(64-bit Data Message) packets.

 * 2. It sends these packets sequentially using OH_MIDIDevice_Send.

 *

 * @warning **BLOCKING CALL**: This function executes a loop and may block if the buffer fills up.

 *

 * @param device Target device handle,

 *     generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param portIndex Target port index.

 * @param data Pointer to the byte stream to send, the memory space needs to be allocated by developer.

 * @param byteSize Byte size of data.

 * @return {@link #OH_MIDI_STATUS_OK} if all events were written.

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if portIndex is invalid, or not open.

 *     or {@link #OH_MIDI_STATUS_TIMEOUT} if the operation could not be completed within a reasonable time,

 *                                     application may use OH_MIDIDevice_FlushOutputPort to reset.

 *     or {@link #OH_MIDI_STATUS_GENERIC_INVALID_ARGUMENT} if arguments are invalid.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_SendSysEx(OH_MIDIDevice *device, uint32_t portIndex,

    const uint8_t *data, uint32_t byteSize);



/**

 * @brief Flushes pending events in output buffer.

 *

 * Immediately discards all MIDI events currently waiting in the output buffer

 * for the specified port. This includes events scheduled for future timestamps

 * that haven't been processed by the service yet.

 *

 * @note This function does not send "All Notes Off" event. It simply clears the queue.

 *

 * @param device Target device handle,

 *               generated by {@link OH_MIDIClient_OpenDevice} or {@link OH_MIDIClient_OpenBLEDevice}.

 * @param portIndex Target port index.

 * @return {@link #OH_MIDI_STATUS_OK} if execution succeeds,

 *     or {@link #OH_MIDI_STATUS_INVALID_DEVICE_HANDLE} if device is invalid.

 *     or {@link #OH_MIDI_STATUS_INVALID_PORT} if portIndex is invalid or not an output port.

 *     or {@link #OH_MIDI_STATUS_GENERIC_IPC_FAILURE} if connection to system service fails.

 * @since 24

 */

OH_MIDIStatusCode OH_MIDIDevice_FlushOutputPort(OH_MIDIDevice *device, uint32_t portIndex);



#ifdef __cplusplus

}

#endif

/** @} */

#endif // NATIVE_MIDI_H