/* Copyright (c) 2020-2023 The Creators of Simphone

   See the file COPYING.LESSER.txt for copying permission.
*/

#ifndef _AUDIO_H_
#define _AUDIO_H_

#include "simtypes.h"

#define AUDIO_PARAM_OLDRATE (-1) /* previously used sample rate or zero if none or equal to current */
#define AUDIO_PARAM_RATE 0       /* currently used sample rate or zero if not talking */
#define AUDIO_PARAM_CPU 1        /* estimated load per cpu core (SMP unit) of current audio call */
#define AUDIO_PARAM_SPEED 2      /* currently allocated proxy speed or non-positive if not allocated */

/* return audio parameter. param is AUDIO_PARAM_xxx */
int audio_get_param (int param);
/* return array of available audio codecs */
simtype audio_get_codecs (void);

#define AUDIO_TYPE_INPUT 1   /* default input device */
#define AUDIO_TYPE_OUTPUT 2  /* default output device */
#define AUDIO_TYPE_VIRTUAL 4 /* software audio device */

/* return number of audio devices currently available (zero if none) */
int audio_device_count (void);
/* enumerate audio devices. device index is 0-based, return nil if no more. caller must call string_free */
simtype audio_device_get (int device, int *inchannels, int *outchannels, int *types);

/* load sound file from memory; resample to *sample rate and set number of *samples. caller must call string_free */
simtype sim_sound_load (const char *sound, int *sample, unsigned *samples);

/* start playing sound file the specified number of times (0 = infinite) */
int audio_start_sound (const char *sound, int repeat);
/* stop playing sound file */
int audio_stop_sound_ (const char *sound);

/* check if currently chosen audio devices are valid and send SIM_EVENT_NET_DEVICE if necessary.
   SIM_STATUS_BUSY: send event only if a non-default device is invalid; SIM_STATUS_IDLE: do not send event */
void event_test_net_device (int status);

/* send audio close error event */
void event_test_error_audio (simnumber id, int error);

/* process audio data received from the network */
void audio_recv_packet (simtype data, simnumber timestamp); /* consumes data */
void audio_free_packet (simtype arrays);                    /* array_free */

/* close audio device if open and optionally send hangup (if later = true) */
int audio_close_ (simbool hangup);

/* recalculate call parameters and initiate a sample rate change if necessary */
int audio_reset (simclient client);
/* receive a sample rate change request or reply */
int audio_reopen_ (simclient client, simnumber sample, simbool reply);

/* send a UDP control packet. consumes table */
int audio_send_udp (simclient client, simtype table, const char *cmd, unsigned ip, int port);
/* send UDP start request to the talking client */
void audio_start_udp (simbool nat);

/* call a connected client (internal use only). state is AUDIO_CALL_xxx */
int audio_start (simclient client, int sample, int state, simbool call);

/* call a contact or do an audio test if id is CONTACT_ID_KEYGEN or CONTACT_ID_TEST */
int audio_call_ (simnumber id);

/* client is answering or calling */
int audio_ring_ (simclient client, const simtype table);

/* client hangs up (if hangup = false) or else process local hangup */
int audio_stop_ (simclient client, int error, simbool hangup);

/* send hangup to client. releases client if talking */
int audio_hangup_ (simclient client, int error);

/* initialize and deinitialize audio */
int audio_init_ (int status);
int audio_uninit_ (simbool reinit);

#define AUDIO_CLIENT_TEST ((void *) -1)

struct _audio_status {
  simclient client;   /* client which is currently talking or AUDIO_CLIENT_TEST; NULL if not talking */
  const char *hangup; /* hangup string (for XML history) */
  simnumber id;       /* contact id or CONTACT_ID_TEST or CONTACT_ID_KEYGEN; zero if not talking */
  simnumber stats[4]; /* CONTACT_STAT_MINE for audio test AND played sounds */
  int udport;         /* own UDP port (as reported by proxy) or zero if not reported */
};

extern struct _audio_status audio_status;

/* client (call) state */
#define AUDIO_CALL_HANGUP 0   /* hung up */
#define AUDIO_CALL_OUTGOING 1 /* outgoing call */
#define AUDIO_CALL_INCOMING 2 /* incoming call */
#define AUDIO_CALL_TALKING 3  /* talking now */

extern const char *audio_state_names[4]; /* names of call states */

/* debug logging */
void audio_log_sounds (const char *module, int level);
void audio_log_devices (const char *module, int level);

#endif
