/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file 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.
 */

#ifndef __AAL_H_
#define __AAL_H_

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef enum { AAL_SUCCESS = 0, AAL_PAUSED, AAL_ERROR, AAL_UNKNOWN } aal_status_t;

typedef enum {
    AAL_SAMPLE_FORMAT_S16LE = 0,

    AAL_SAMPLE_FORMAT_DEFAULT = AAL_SAMPLE_FORMAT_S16LE,
    AAL_AVS_SAMPLE_FORMAT = AAL_SAMPLE_FORMAT_S16LE,
} aal_sample_format_t;

#define AAL_AVS_CHANNELS 1
#define AAL_AVS_SAMPLE_RATE 16000

typedef struct {
    void (*on_start)(void* user_data);
    void (*on_stop)(aal_status_t reason, void* user_data);
    void (*on_almost_done)(void* user_data);
    void (*on_data)(const int16_t* data, const size_t length, void* user_data);
    void (*on_data_requested)(void* user_data);
} aal_listener_t;

typedef struct {
    const char* name;                // printable name majorly for logging
    const char* device;              // audio device
    const char* uri;                 // the URL to open
    const aal_listener_t* listener;  // listener callback
    void* user_data;                 // user data for listener callback
    int module_id;                   // the AAL module to use
} aal_attributes_t;

typedef enum { AAL_STREAM_LPCM, AAL_STREAM_UNKNOWN } aal_stream_type_t;

typedef struct {
    /**
	 * Sample format. For the player, it specifies the sample format of the input LPCM audio. The value is ignored
	 * if the input audio type is not LPCM. For the recorder, it specifies the sample format that the audio input
	 * device should be configured with. The sample format of output audio from a recorder is always
	 * AAL_AVS_SAMPLE_FORMAT.
	 */
    aal_sample_format_t sample_format;

    /**
	 * The number of audio channels. For the player, it specifies the number of audio channels of input LPCM audio.
	 * The value is ignored if the input audio type is not LPCM. For the recorder, it specifies the number of audio
	 * channels that the audio input device should be configured with. The number of output audio from a recorder is
	 * always AAL_AVS_CHANNELS.
	 */
    int channels;

    /**
	 * Sample rate in Hz. For the player, it specifies the sample rate of input LPCM audio. The value is ignored if
	 * the input audio type is not LPCM. For the recorder, it specifies the sample rate that the audio input device
	 * should be configured with. The sample rate of output audio from a recorder is always AAL_AVS_SAMPLE_RATE.
	 */
    int sample_rate;
} aal_lpcm_parameters_t;

typedef struct {
    aal_stream_type_t stream_type;
    union {
        aal_lpcm_parameters_t lpcm;
    };
} aal_audio_parameters_t;

typedef void* aal_handle_t;

#define AAL_INVALID_MODULE (-1)

#define AAL_MODULE_CAP_STREAM_PLAYBACK 0x01u
#define AAL_MODULE_CAP_URL_PLAYBACK 0x02u
#define AAL_MODULE_CAP_LPCM_PLAYBACK 0x04u

int aal_get_module_count();
int aal_find_module_by_capability(uint32_t caps);
uint32_t aal_get_module_capabilities(int module_id);
const char* aal_get_module_name(int module_id);
bool aal_initialize(int module_id);
void aal_deinitialize(int module_id);

typedef void aal_log_func(int level, const char* data, int len);
void aal_set_log_func(aal_log_func* func);

aal_handle_t aal_player_create(const aal_attributes_t* attr, aal_audio_parameters_t* params);
void aal_player_play(aal_handle_t handle);
void aal_player_pause(aal_handle_t handle);
void aal_player_stop(aal_handle_t handle);
int64_t aal_player_get_position(aal_handle_t handle);
int64_t aal_player_get_duration(aal_handle_t handle);
int64_t aal_player_get_num_bytes_buffered(aal_handle_t handle);
void aal_player_seek(aal_handle_t handle, int64_t position);
void aal_player_set_volume(aal_handle_t handle, double volume);
void aal_player_set_mute(aal_handle_t handle, bool mute);
ssize_t aal_player_write(aal_handle_t handle, const char* data, size_t size);
void aal_player_notify_end_of_stream(aal_handle_t handle);
void aal_player_destroy(aal_handle_t handle);

aal_handle_t aal_recorder_create(const aal_attributes_t* attr, aal_lpcm_parameters_t* params);
void aal_recorder_play(aal_handle_t handle);
void aal_recorder_stop(aal_handle_t handle);
void aal_recorder_destroy(aal_handle_t handle);

#ifdef __cplusplus
}
#endif

#endif  // __AAL_H_
