/*
   This file is part of GNUnet
   Copyright (C) 2013, 2014, 2016 GNUnet e.V.

   GNUnet is free software: you can redistribute it and/or modify it
   under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   GNUnet is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

     SPDX-License-Identifier: AGPL3.0-or-later
 */

/**
 * @addtogroup conversation_l2  Conversation service and libraries
 * @{
 *
 * @author Simon Dieterle
 * @author Andreas Fuchs
 * @author Christian Grothoff
 *
 * @file
 * API to the conversation service
 *
 * @defgroup conversation  Conversation service
 * One-to-one voice communication over CADET
 *
 * NOTE: This API is deliberately deceptively simple; the idea
 * is that advanced features (such as answering machines) will
 * be done with a separate service (an answering machine service)
 * with its own APIs; the speaker/microphone abstractions are
 * used to facilitate plugging in custom logic for implementing
 * such a service later by creating "software" versions of
 * speakers and microphones that record to disk or play a file.
 * Notifications about missed calls should similarly be done
 * using a separate service; CONVERSATION is supposed to be just
 * the "bare bones" voice service.
 *
 * As this is supposed to be a "secure" service, caller ID is of
 * course provided as part of the basic implementation, as only the
 * CONVERSATION service can know for sure who it is that we are
 * talking to.
 *
 * @{
 */
#ifndef GNUNET_CONVERSATION_SERVICE_H
#define GNUNET_CONVERSATION_SERVICE_H

#ifdef __cplusplus
extern "C"
{
#if 0                           /* keep Emacsens' auto-indent happy */
}
#endif
#endif


#include "gnunet_util_lib.h"
#include "gnunet_identity_service.h"
#include "gnunet_namestore_service.h"
#include "gnunet_speaker_lib.h"
#include "gnunet_microphone_lib.h"


/**
 * Version of the conversation API.
 */
#define GNUNET_CONVERSATION_VERSION 0x00000004

/**
 * Handle to identify a particular caller.  A caller is an entity that
 * initiate a call to a phone.  This struct identifies the caller to
 * the user operating the phone.  The entity that initiated the call
 * will have a `struct GNUNET_CONVERSATION_Call`.
 */
struct GNUNET_CONVERSATION_Caller;


GNUNET_NETWORK_STRUCT_BEGIN

/**
 * A phone record specifies which peer is hosting a given user and
 * may also specify the phone line that is used (typically zero).
 * The version is also right now always zero.
 */
struct GNUNET_CONVERSATION_PhoneRecord
{
  /**
   * Version of the phone record, for now always one.  We may
   * use other versions for anonymously hosted phone lines in
   * the future.
   */
  uint32_t version GNUNET_PACKED;

  /**
   * Reserved. In v1. always zero.
   */
  uint32_t reserved GNUNET_PACKED;

  /**
   * Identity of the peer hosting the phone service.
   */
  struct GNUNET_PeerIdentity peer;

  /**
   * Phone line (CADET port) to connect to.
   */
  struct GNUNET_HashCode line_port;
};

GNUNET_NETWORK_STRUCT_END

/**
 * Information about active callers to a phone.
 */
enum GNUNET_CONVERSATION_PhoneEventCode
{
  /**
   * We are the callee and the phone is ringing.
   * We should accept the call or hang up.
   */
  GNUNET_CONVERSATION_EC_PHONE_RING,

  /**
   * The conversation was terminated by the caller.
   * We must no longer use the caller's handle.
   */
  GNUNET_CONVERSATION_EC_PHONE_HUNG_UP
};


/**
 * Function called with an event emitted by a phone.
 *
 * @param cls closure
 * @param code type of the event
 * @param caller handle for the caller
 * @param caller_id public key of the caller (in GNS)
 */
typedef void
(*GNUNET_CONVERSATION_PhoneEventHandler)(void *cls,
                                         enum GNUNET_CONVERSATION_PhoneEventCode
                                         code,
                                         struct GNUNET_CONVERSATION_Caller *
                                         caller,
                                         const struct
                                         GNUNET_CRYPTO_PublicKey *caller_id);


/**
 * Information about the current status of a call.  Each call
 * progresses from ring over ready to terminated.  Steps may
 * be skipped.
 */
enum GNUNET_CONVERSATION_CallerEventCode
{
  /**
   * We are the callee and the caller suspended the call.  Note that
   * both sides can independently suspend and resume calls; a call is
   * only "working" of both sides are active.
   */
  GNUNET_CONVERSATION_EC_CALLER_SUSPEND,

  /**
   * We are the callee and the caller resumed the call.  Note that
   * both sides can independently suspend and resume calls; a call is
   * only "working" of both sides are active.
   */
  GNUNET_CONVERSATION_EC_CALLER_RESUME
};


/**
 * Function called with an event emitted by a caller.
 * These events are only generated after the phone is
 * picked up.
 *
 * @param cls closure
 * @param code type of the event for this caller
 */
typedef void
(*GNUNET_CONVERSATION_CallerEventHandler)(void *cls,
                                          enum
                                          GNUNET_CONVERSATION_CallerEventCode
                                          code);


/**
 * A phone is a device that can ring to signal an incoming call and
 * that you can pick up to answer the call and hang up to terminate
 * the call.  You can also hang up a ringing phone immediately
 * (without picking it up) to stop it from ringing.  Phones have
 * caller ID.  You can ask the phone for its record and make that
 * record available (via GNS) to enable others to call you.
 * Multiple phones maybe connected to the same line (the line is
 * something rather internal to a phone and not obvious from it).
 * You can only have one conversation per phone at any time.
 */
struct GNUNET_CONVERSATION_Phone;


/**
 * Create a new phone.
 *
 * @param cfg configuration for the phone; specifies the phone service and
 *        which line the phone is to be connected to
 * @param ego ego to use for name resolution (when determining caller ID)
 * @param event_handler how to notify the owner of the phone about events
 * @param event_handler_cls closure for @a event_handler
 */
struct GNUNET_CONVERSATION_Phone *
GNUNET_CONVERSATION_phone_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                  const struct GNUNET_IDENTITY_Ego *ego,
                                  GNUNET_CONVERSATION_PhoneEventHandler
                                  event_handler,
                                  void *event_handler_cls);


/**
 * Fill in a namestore record with the contact information
 * for this phone.  Note that the filled in "data" value
 * is only valid until the phone is destroyed.
 *
 * @param phone phone to create a record for
 * @param rd namestore record to fill in
 */
void
GNUNET_CONVERSATION_phone_get_record (struct GNUNET_CONVERSATION_Phone *phone,
                                      struct GNUNET_GNSRECORD_Data *rd);


/**
 * Picks up a (ringing) phone call.  This will connect the speaker
 * to the microphone of the other party, and vice versa.
 *
 * @param caller handle that identifies which caller should be answered
 * @param event_handler how to notify about events by the caller
 * @param event_handler_cls closure for @a event_handler
 * @param speaker speaker to use
 * @param mic microphone to use
 */
void
GNUNET_CONVERSATION_caller_pick_up (struct GNUNET_CONVERSATION_Caller *caller,
                                    GNUNET_CONVERSATION_CallerEventHandler
                                    event_handler,
                                    void *event_handler_cls,
                                    struct GNUNET_SPEAKER_Handle *speaker,
                                    struct GNUNET_MICROPHONE_Handle *mic);


/**
 * Pause conversation of an active call.  This will disconnect the speaker
 * and the microphone.  The call can later be resumed with
 * #GNUNET_CONVERSATION_caller_resume.
 *
 * @param caller call to suspend
 */
void
GNUNET_CONVERSATION_caller_suspend (struct GNUNET_CONVERSATION_Caller *caller);


/**
 * Resume suspended conversation of a phone.
 *
 * @param caller call to resume
 * @param speaker speaker to use
 * @param mic microphone to use
 */
void
GNUNET_CONVERSATION_caller_resume (struct GNUNET_CONVERSATION_Caller *caller,
                                   struct GNUNET_SPEAKER_Handle *speaker,
                                   struct GNUNET_MICROPHONE_Handle *mic);


/**
 * Hang up up a (possibly ringing or paused) phone.  This will notify
 * the caller that we are no longer interested in talking with them.
 *
 * @param caller who should we hang up on
 */
void
GNUNET_CONVERSATION_caller_hang_up (struct GNUNET_CONVERSATION_Caller *caller);


/**
 * Destroys a phone.
 *
 * @param phone phone to destroy
 */
void
GNUNET_CONVERSATION_phone_destroy (struct GNUNET_CONVERSATION_Phone *phone);


/* *********************** CALL API ************************ */

/**
 * Handle for an outgoing call.
 */
struct GNUNET_CONVERSATION_Call;


/**
 * Information about the current status of a call.
 */
enum GNUNET_CONVERSATION_CallEventCode
{
  /**
   * We are the caller and are now ringing the other party (GNS lookup
   * succeeded).
   */
  GNUNET_CONVERSATION_EC_CALL_RINGING,

  /**
   * We are the caller and are now ready to talk as the callee picked up.
   */
  GNUNET_CONVERSATION_EC_CALL_PICKED_UP,

  /**
   * We are the caller and failed to locate a phone record in GNS.
   * After this invocation, the respective call handle will be
   * automatically destroyed and the client must no longer call
   * #GNUNET_CONVERSATION_call_stop or any other function on the
   * call object.
   */
  GNUNET_CONVERSATION_EC_CALL_GNS_FAIL,

  /**
   * We are the caller and the callee called
   * #GNUNET_CONVERSATION_caller_hang_up.  After this invocation, the
   * respective call handle will be automatically destroyed and the
   * client must no longer call #GNUNET_CONVERSATION_call_stop.
   */
  GNUNET_CONVERSATION_EC_CALL_HUNG_UP,

  /**
   * We are the caller and the callee suspended the call.  Note that
   * both sides can independently suspend and resume calls; a call is
   * only "working" of both sides are active.
   */
  GNUNET_CONVERSATION_EC_CALL_SUSPENDED,

  /**
   * We are the caller and the callee suspended the call.  Note that
   * both sides can independently suspend and resume calls; a call is
   * only "working" of both sides are active.
   */
  GNUNET_CONVERSATION_EC_CALL_RESUMED,

  /**
   * We had an error handing the call, and are now restarting it
   * (back to lookup).  This happens, for example, if the peer
   * is restarted during a call.
   */
  GNUNET_CONVERSATION_EC_CALL_ERROR
};


/**
 * Function called with an event emitted for a call.
 *
 * @param cls closure
 * @param code type of the event on the call
 */
typedef void
(*GNUNET_CONVERSATION_CallEventHandler)(void *cls,
                                        enum GNUNET_CONVERSATION_CallEventCode
                                        code);


/**
 * Call the phone of another user.
 *
 * @param cfg configuration to use, specifies our phone service
 * @param caller_id identity of the caller
 * @param callee GNS name of the callee (used to locate the callee's record)
 * @param speaker speaker to use (will be used automatically immediately once the
 *        #GNUNET_CONVERSATION_EC_CALL_PICKED_UP event is generated); we will NOT generate
 *        a ring tone on the speaker
 * @param mic microphone to use (will be used automatically immediately once the
 *        #GNUNET_CONVERSATION_EC_CALL_PICKED_UP event is generated)
 * @param event_handler how to notify the owner of the phone about events
 * @param event_handler_cls closure for @a event_handler
 * @return handle for the call
 */
struct GNUNET_CONVERSATION_Call *
GNUNET_CONVERSATION_call_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                struct GNUNET_IDENTITY_Ego *caller_id,
                                const char *callee,
                                struct GNUNET_SPEAKER_Handle *speaker,
                                struct GNUNET_MICROPHONE_Handle *mic,
                                GNUNET_CONVERSATION_CallEventHandler
                                event_handler,
                                void *event_handler_cls);


/**
 * Pause a call.  Temporarily suspends the use of speaker and
 * microphone.
 *
 * @param call call to pause
 */
void
GNUNET_CONVERSATION_call_suspend (struct GNUNET_CONVERSATION_Call *call);


/**
 * Resumes a call after #GNUNET_CONVERSATION_call_suspend.
 *
 * @param call call to resume
 * @param speaker speaker to use
 * @param mic microphone to use
 */
void
GNUNET_CONVERSATION_call_resume (struct GNUNET_CONVERSATION_Call *call,
                                 struct GNUNET_SPEAKER_Handle *speaker,
                                 struct GNUNET_MICROPHONE_Handle *mic);


/**
 * Terminate a call.  The call may be ringing or ready at this time.
 *
 * @param call call to terminate
 */
void
GNUNET_CONVERSATION_call_stop (struct GNUNET_CONVERSATION_Call *call);


#if 0                           /* keep Emacsens' auto-indent happy */
{
#endif
#ifdef __cplusplus
}
#endif

#endif

/** @} */  /* end of group */

/** @} */ /* end of group addition */
