/* Copyright(C) 2007-2023 VoIP objects (voipobjects.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __AUDIO_PROVIDER_H
#define __AUDIO_PROVIDER_H

#include "EP_DataProvider.h"
#include "../helper/HL_InternetAddress.h"
#include "../helper/HL_Rtp.h"
#include "../media/MT_Box.h"
#include "../media/MT_Stream.h"
#include "../media/MT_Codec.h"

#include <vector>
#include <string>

class UserAgent;

class AudioProvider: public DataProvider
{
public:

  AudioProvider(UserAgent& agent, MT::Terminal& terminal);
  virtual ~AudioProvider();
  
  // Returns provider RTP name
  std::string   streamName() override;
  
  // Returns provider RTP profile name
  std::string   streamProfile() override;
  
  // Sets destination IP address
  void          setDestinationAddress(const RtpPair<InternetAddress>& addr) override;

  // Processes incoming data
  void          processData(const PDatagramSocket& s, const void* dataBuffer, int dataSize, InternetAddress& source) override;

  // This method is called by user agent to send ICE packet from mediasocket
  void          sendData(const PDatagramSocket& s, InternetAddress& destination, const void* dataBuffer, unsigned int datasize) override;

  // Updates SDP offer
  void          updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) override;

  // Called by user agent when session is deleted.
  void          sessionDeleted() override;

  // Called by user agent when session is terminated.
  void          sessionTerminated() override;

  // Called by user agent when session is started.
  void          sessionEstablished(int conntype) override;

  // Called by user agent to save media socket for this provider
  void          setSocket(const RtpPair<PDatagramSocket>& p4, const RtpPair<PDatagramSocket>& p6) override;
  
  // Called by user agent to get media socket for this provider
  RtpPair<PDatagramSocket>& socket(int family) override;

  // Called by user agent to process media stream description from remote peer.
  // Returns true if description is processed succesfully. Otherwise method returns false.
  // myAnswer sets if the answer will be sent after.
  bool          processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) override;


  void          setState(unsigned state) override;
  unsigned      state() override;
  MT::Statistics  getStatistics() override;
  MT::PStream   activeStream();

  void readFile(const Audio::PWavFileReader& stream, MT::Stream::MediaDirection direction);
  void writeFile(const Audio::PWavFileWriter& stream, MT::Stream::MediaDirection direction);
  void setupMirror(bool enable);

  void configureMediaObserver(MT::Stream::MediaObserver* observer, void* userTag);
  static SrtpSuite processCryptoAttribute(const resip::Data& value, ByteBuffer& key, int* tag = nullptr);

protected:
  // SDP's stream name
  std::string             mStreamName;
    
  // Socket handles to operate
  RtpPair<PDatagramSocket>   mSocket4, mSocket6;

  // Destination IP4/6 address
  RtpPair<InternetAddress>         mDestination;
  
  MT::PStream mActiveStream;
  UserAgent& mUserAgent;
  MT::Terminal& mTerminal;
  MT::Statistics mBackupStats;

  unsigned mState;
  SrtpSuite mSrtpSuite;
  int mSrtpTag = 1;                       // RFC 4568 tag of the negotiated crypto attribute
  struct RemoteCodec
  {
    RemoteCodec(MT::Codec::Factory* factory, int payloadType)
      :mFactory(factory), mRemotePayloadType(payloadType)
    { }

    MT::Codec::Factory* mFactory;
    int mRemotePayloadType;
  };
  std::vector<RemoteCodec> mAvailableCodecs;
  int mRemoteTelephoneCodec;              // Payload type of remote rfc2833 codec
  bool mRemoteNoSdp;                      // Marks if we got no-sdp offer
  MT::CodecListPriority mCodecPriority;
  MT::Stream::MediaObserver* mMediaObserver = nullptr;
  void* mMediaObserverTag = nullptr;

  std::string createCryptoAttribute(SrtpSuite suite, int tag);
  void findRfc2833(const resip::SdpContents::Session::Medium::CodecContainer& codecs);

  // Implements setState() logic. This allows to be called from constructor (it is not virtual function)
  void setStateImpl(unsigned state);

};

#endif
