::max)();
+
+struct EncodedVideoFrameInfo;
+
+/**
+* Video source types definition.
+**/
+enum VIDEO_SOURCE_TYPE {
+ /** Video captured by the camera.
+ */
+ VIDEO_SOURCE_CAMERA_PRIMARY = 0,
+ VIDEO_SOURCE_CAMERA = VIDEO_SOURCE_CAMERA_PRIMARY,
+ /** Video captured by the secondary camera.
+ */
+ VIDEO_SOURCE_CAMERA_SECONDARY = 1,
+ /** Video for screen sharing.
+ */
+ VIDEO_SOURCE_SCREEN_PRIMARY = 2,
+ VIDEO_SOURCE_SCREEN = VIDEO_SOURCE_SCREEN_PRIMARY,
+ /** Video for secondary screen sharing.
+ */
+ VIDEO_SOURCE_SCREEN_SECONDARY = 3,
+ /** Not define.
+ */
+ VIDEO_SOURCE_CUSTOM = 4,
+ /** Video for media player sharing.
+ */
+ VIDEO_SOURCE_MEDIA_PLAYER = 5,
+ /** Video for png image.
+ */
+ VIDEO_SOURCE_RTC_IMAGE_PNG = 6,
+ /** Video for png image.
+ */
+ VIDEO_SOURCE_RTC_IMAGE_JPEG = 7,
+ /** Video for png image.
+ */
+ VIDEO_SOURCE_RTC_IMAGE_GIF = 8,
+ /** Remote video received from network.
+ */
+ VIDEO_SOURCE_REMOTE = 9,
+ /** Video for transcoded.
+ */
+ VIDEO_SOURCE_TRANSCODED = 10,
+
+ /** Video captured by the third camera.
+ */
+ VIDEO_SOURCE_CAMERA_THIRD = 11,
+ /** Video captured by the fourth camera.
+ */
+ VIDEO_SOURCE_CAMERA_FOURTH = 12,
+ /** Video for third screen sharing.
+ */
+ VIDEO_SOURCE_SCREEN_THIRD = 13,
+ /** Video for fourth screen sharing.
+ */
+ VIDEO_SOURCE_SCREEN_FOURTH = 14,
+
+ VIDEO_SOURCE_UNKNOWN = 100
+};
+
+/**
+ * Audio routes.
+ */
+enum AudioRoute
+{
+ /**
+ * -1: The default audio route.
+ */
+ ROUTE_DEFAULT = -1,
+ /**
+ * The Headset.
+ */
+ ROUTE_HEADSET = 0,
+ /**
+ * The Earpiece.
+ */
+ ROUTE_EARPIECE = 1,
+ /**
+ * The Headset with no microphone.
+ */
+ ROUTE_HEADSETNOMIC = 2,
+ /**
+ * The Speakerphone.
+ */
+ ROUTE_SPEAKERPHONE = 3,
+ /**
+ * The Loudspeaker.
+ */
+ ROUTE_LOUDSPEAKER = 4,
+ /**
+ * The Bluetooth Headset via HFP.
+ */
+ ROUTE_HEADSETBLUETOOTH = 5,
+ /**
+ * The USB.
+ */
+ ROUTE_USB = 6,
+ /**
+ * The HDMI.
+ */
+ ROUTE_HDMI = 7,
+ /**
+ * The DisplayPort.
+ */
+ ROUTE_DISPLAYPORT = 8,
+ /**
+ * The AirPlay.
+ */
+ ROUTE_AIRPLAY = 9,
+ /**
+ * The Bluetooth Speaker via A2DP.
+ */
+ ROUTE_BLUETOOTH_SPEAKER = 10,
+};
+
+/**
+ * Bytes per sample
+ */
+enum BYTES_PER_SAMPLE {
+ /**
+ * two bytes per sample
+ */
+ TWO_BYTES_PER_SAMPLE = 2,
+};
+
+struct AudioParameters {
+ int sample_rate;
+ size_t channels;
+ size_t frames_per_buffer;
+
+ AudioParameters()
+ : sample_rate(0),
+ channels(0),
+ frames_per_buffer(0) {}
+};
+
+/**
+ * The use mode of the audio data.
+ */
+enum RAW_AUDIO_FRAME_OP_MODE_TYPE {
+ /** 0: Read-only mode: Users only read the data from `AudioFrame` without modifying anything.
+ * For example, when users acquire the data with the Agora SDK, then start the media push.
+ */
+ RAW_AUDIO_FRAME_OP_MODE_READ_ONLY = 0,
+
+ /** 2: Read and write mode: Users read the data from `AudioFrame`, modify it, and then play it.
+ * For example, when users have their own audio-effect processing module and perform some voice pre-processing, such as a voice change.
+ */
+ RAW_AUDIO_FRAME_OP_MODE_READ_WRITE = 2,
+};
+
+} // namespace rtc
+
+namespace media {
+ /**
+ * The type of media device.
+ */
+enum MEDIA_SOURCE_TYPE {
+ /**
+ * 0: The audio playback device.
+ */
+ AUDIO_PLAYOUT_SOURCE = 0,
+ /**
+ * 1: Microphone.
+ */
+ AUDIO_RECORDING_SOURCE = 1,
+ /**
+ * 2: Video captured by primary camera.
+ */
+ PRIMARY_CAMERA_SOURCE = 2,
+ /**
+ * 3: Video captured by secondary camera.
+ */
+ SECONDARY_CAMERA_SOURCE = 3,
+ /**
+ * 4: Video captured by primary screen capturer.
+ */
+ PRIMARY_SCREEN_SOURCE = 4,
+ /**
+ * 5: Video captured by secondary screen capturer.
+ */
+ SECONDARY_SCREEN_SOURCE = 5,
+ /**
+ * 6: Video captured by custom video source.
+ */
+ CUSTOM_VIDEO_SOURCE = 6,
+ /**
+ * 7: Video for media player sharing.
+ */
+ MEDIA_PLAYER_SOURCE = 7,
+ /**
+ * 8: Video for png image.
+ */
+ RTC_IMAGE_PNG_SOURCE = 8,
+ /**
+ * 9: Video for jpeg image.
+ */
+ RTC_IMAGE_JPEG_SOURCE = 9,
+ /**
+ * 10: Video for gif image.
+ */
+ RTC_IMAGE_GIF_SOURCE = 10,
+ /**
+ * 11: Remote video received from network.
+ */
+ REMOTE_VIDEO_SOURCE = 11,
+ /**
+ * 12: Video for transcoded.
+ */
+ TRANSCODED_VIDEO_SOURCE = 12,
+ /**
+ * 100: Internal Usage only.
+ */
+ UNKNOWN_MEDIA_SOURCE = 100
+};
+/** Definition of contentinspect
+ */
+#define MAX_CONTENT_INSPECT_MODULE_COUNT 32
+enum CONTENT_INSPECT_RESULT {
+ CONTENT_INSPECT_NEUTRAL = 1,
+ CONTENT_INSPECT_SEXY = 2,
+ CONTENT_INSPECT_PORN = 3,
+};
+
+enum CONTENT_INSPECT_TYPE {
+/**
+ * (Default) content inspect type invalid
+ */
+CONTENT_INSPECT_INVALID = 0,
+/**
+ * @deprecated
+ * Content inspect type moderation
+ */
+CONTENT_INSPECT_MODERATION __deprecated = 1,
+/**
+ * Content inspect type supervise
+ */
+CONTENT_INSPECT_SUPERVISION = 2,
+/**
+ * Content inspect type image moderation
+ */
+CONTENT_INSPECT_IMAGE_MODERATION = 3
+};
+
+struct ContentInspectModule {
+ /**
+ * The content inspect module type.
+ */
+ CONTENT_INSPECT_TYPE type;
+ /**The content inspect frequency, default is 0 second.
+ * the frequency <= 0 is invalid.
+ */
+ unsigned int interval;
+ ContentInspectModule() {
+ type = CONTENT_INSPECT_INVALID;
+ interval = 0;
+ }
+};
+/** Definition of ContentInspectConfig.
+ */
+struct ContentInspectConfig {
+ const char* extraInfo;
+ /**
+ * The specific server configuration for image moderation. Please contact technical support.
+ */
+ const char* serverConfig;
+ /**The content inspect modules, max length of modules is 32.
+ * the content(snapshot of send video stream, image) can be used to max of 32 types functions.
+ */
+ ContentInspectModule modules[MAX_CONTENT_INSPECT_MODULE_COUNT];
+ /**The content inspect module count.
+ */
+ int moduleCount;
+ ContentInspectConfig& operator=(const ContentInspectConfig& rth)
+ {
+ extraInfo = rth.extraInfo;
+ serverConfig = rth.serverConfig;
+ moduleCount = rth.moduleCount;
+ memcpy(&modules, &rth.modules, MAX_CONTENT_INSPECT_MODULE_COUNT * sizeof(ContentInspectModule));
+ return *this;
+ }
+ ContentInspectConfig() :extraInfo(NULL), serverConfig(NULL), moduleCount(0){}
+};
+
+namespace base {
+
+typedef void* view_t;
+
+typedef const char* user_id_t;
+
+static const uint8_t kMaxCodecNameLength = 50;
+
+/**
+ * The definition of the PacketOptions struct, which contains infomation of the packet
+ * in the RTP (Real-time Transport Protocal) header.
+ */
+struct PacketOptions {
+ /**
+ * The timestamp of the packet.
+ */
+ uint32_t timestamp;
+ // Audio level indication.
+ uint8_t audioLevelIndication;
+ PacketOptions()
+ : timestamp(0),
+ audioLevelIndication(127) {}
+};
+
+/**
+ * The detailed information of the incoming audio encoded frame.
+ */
+
+struct AudioEncodedFrameInfo {
+ /**
+ * The send time of the packet.
+ */
+ uint64_t sendTs;
+ /**
+ * The codec of the packet.
+ */
+ uint8_t codec;
+ AudioEncodedFrameInfo()
+ : sendTs(0),
+ codec(0) {}
+};
+
+/**
+ * The detailed information of the incoming audio frame in the PCM format.
+ */
+struct AudioPcmFrame {
+ /**
+ * The buffer size of the PCM audio frame.
+ */
+ OPTIONAL_ENUM_SIZE_T {
+ // Stereo, 32 kHz, 60 ms (2 * 32 * 60)
+ /**
+ * The max number of the samples of the data.
+ *
+ * When the number of audio channel is two, the sample rate is 32 kHZ,
+ * the buffer length of the data is 60 ms, the number of the samples of the data is 3840 (2 x 32 x 60).
+ */
+ kMaxDataSizeSamples = 3840,
+ /** The max number of the bytes of the data. */
+ kMaxDataSizeBytes = kMaxDataSizeSamples * sizeof(int16_t),
+ };
+
+ /** The timestamp (ms) of the audio frame.
+ */
+ int64_t capture_timestamp;
+ /** The number of samples per channel.
+ */
+ size_t samples_per_channel_;
+ /** The sample rate (Hz) of the audio data.
+ */
+ int sample_rate_hz_;
+ /** The channel number.
+ */
+ size_t num_channels_;
+ /** The number of bytes per sample.
+ */
+ rtc::BYTES_PER_SAMPLE bytes_per_sample;
+ /** The audio frame data. */
+ int16_t data_[kMaxDataSizeSamples];
+
+ AudioPcmFrame& operator=(const AudioPcmFrame& src) {
+ if(this == &src) {
+ return *this;
+ }
+
+ this->capture_timestamp = src.capture_timestamp;
+ this->samples_per_channel_ = src.samples_per_channel_;
+ this->sample_rate_hz_ = src.sample_rate_hz_;
+ this->bytes_per_sample = src.bytes_per_sample;
+ this->num_channels_ = src.num_channels_;
+
+ size_t length = src.samples_per_channel_ * src.num_channels_;
+ if (length > kMaxDataSizeSamples) {
+ length = kMaxDataSizeSamples;
+ }
+
+ memcpy(this->data_, src.data_, length * sizeof(int16_t));
+
+ return *this;
+ }
+
+ AudioPcmFrame()
+ : capture_timestamp(0),
+ samples_per_channel_(0),
+ sample_rate_hz_(0),
+ num_channels_(0),
+ bytes_per_sample(rtc::TWO_BYTES_PER_SAMPLE) {
+ memset(data_, 0, sizeof(data_));
+ }
+
+ AudioPcmFrame(const AudioPcmFrame& src)
+ : capture_timestamp(src.capture_timestamp),
+ samples_per_channel_(src.samples_per_channel_),
+ sample_rate_hz_(src.sample_rate_hz_),
+ num_channels_(src.num_channels_),
+ bytes_per_sample(src.bytes_per_sample) {
+ size_t length = src.samples_per_channel_ * src.num_channels_;
+ if (length > kMaxDataSizeSamples) {
+ length = kMaxDataSizeSamples;
+ }
+
+ memcpy(this->data_, src.data_, length * sizeof(int16_t));
+ }
+};
+
+/** Audio dual-mono output mode
+ */
+enum AUDIO_DUAL_MONO_MODE {
+ /**< ChanLOut=ChanLin, ChanRout=ChanRin */
+ AUDIO_DUAL_MONO_STEREO = 0,
+ /**< ChanLOut=ChanRout=ChanLin */
+ AUDIO_DUAL_MONO_L = 1,
+ /**< ChanLOut=ChanRout=ChanRin */
+ AUDIO_DUAL_MONO_R = 2,
+ /**< ChanLout=ChanRout=(ChanLin+ChanRin)/2 */
+ AUDIO_DUAL_MONO_MIX = 3
+};
+
+/**
+ * Video pixel formats.
+ */
+enum VIDEO_PIXEL_FORMAT {
+ /**
+ * 0: Default format.
+ */
+ VIDEO_PIXEL_DEFAULT = 0,
+ /**
+ * 1: I420.
+ */
+ VIDEO_PIXEL_I420 = 1,
+ /**
+ * 2: BGRA.
+ */
+ VIDEO_PIXEL_BGRA = 2,
+ /**
+ * 3: NV21.
+ */
+ VIDEO_PIXEL_NV21 = 3,
+ /**
+ * 4: RGBA.
+ */
+ VIDEO_PIXEL_RGBA = 4,
+ /**
+ * 8: NV12.
+ */
+ VIDEO_PIXEL_NV12 = 8,
+ /**
+ * 10: GL_TEXTURE_2D
+ */
+ VIDEO_TEXTURE_2D = 10,
+ /**
+ * 11: GL_TEXTURE_OES
+ */
+ VIDEO_TEXTURE_OES = 11,
+ /*
+ 12: pixel format for iOS CVPixelBuffer NV12
+ */
+ VIDEO_CVPIXEL_NV12 = 12,
+ /*
+ 13: pixel format for iOS CVPixelBuffer I420
+ */
+ VIDEO_CVPIXEL_I420 = 13,
+ /*
+ 14: pixel format for iOS CVPixelBuffer BGRA
+ */
+ VIDEO_CVPIXEL_BGRA = 14,
+ /**
+ * 16: I422.
+ */
+ VIDEO_PIXEL_I422 = 16,
+ /**
+ * 17: ID3D11Texture2D, only support DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_NV12 texture format
+ */
+ VIDEO_TEXTURE_ID3D11TEXTURE2D = 17,
+};
+
+/**
+ * The video display mode.
+ */
+enum RENDER_MODE_TYPE {
+ /**
+ * 1: Uniformly scale the video until it fills the visible boundaries
+ * (cropped). One dimension of the video may have clipped contents.
+ */
+ RENDER_MODE_HIDDEN = 1,
+ /**
+ * 2: Uniformly scale the video until one of its dimension fits the boundary
+ * (zoomed to fit). Areas that are not filled due to the disparity in the
+ * aspect ratio will be filled with black.
+ */
+ RENDER_MODE_FIT = 2,
+ /**
+ * @deprecated
+ * 3: This mode is deprecated.
+ */
+ RENDER_MODE_ADAPTIVE __deprecated = 3,
+};
+
+/**
+ * The camera video source type
+ */
+enum CAMERA_VIDEO_SOURCE_TYPE {
+ /**
+ * 0: the video frame comes from the front camera
+ */
+ CAMERA_SOURCE_FRONT = 0,
+ /**
+ * 1: the video frame comes from the back camera
+ */
+ CAMERA_SOURCE_BACK = 1,
+ /**
+ * 1: the video frame source is unsepcified
+ */
+ VIDEO_SOURCE_UNSPECIFIED = 2,
+};
+
+/**
+ * The IVideoFrameMetaInfo class.
+ * This interface provides access to metadata information.
+ */
+class IVideoFrameMetaInfo {
+ public:
+ enum META_INFO_KEY {
+ KEY_FACE_CAPTURE = 0,
+ };
+ virtual ~IVideoFrameMetaInfo() {};
+ virtual const char* getMetaInfoStr(META_INFO_KEY key) const = 0;
+};
+
+/**
+ * The definition of the ExternalVideoFrame struct.
+ */
+struct ExternalVideoFrame {
+ ExternalVideoFrame()
+ : type(VIDEO_BUFFER_RAW_DATA),
+ format(VIDEO_PIXEL_DEFAULT),
+ buffer(NULL),
+ stride(0),
+ height(0),
+ cropLeft(0),
+ cropTop(0),
+ cropRight(0),
+ cropBottom(0),
+ rotation(0),
+ timestamp(0),
+ eglContext(NULL),
+ eglType(EGL_CONTEXT10),
+ textureId(0),
+ metadata_buffer(NULL),
+ metadata_size(0),
+ alphaBuffer(NULL),
+ d3d11_texture_2d(NULL),
+ texture_slice_index(0){}
+
+ /**
+ * The EGL context type.
+ */
+ enum EGL_CONTEXT_TYPE {
+ /**
+ * 0: When using the OpenGL interface (javax.microedition.khronos.egl.*) defined by Khronos
+ */
+ EGL_CONTEXT10 = 0,
+ /**
+ * 0: When using the OpenGL interface (android.opengl.*) defined by Android
+ */
+ EGL_CONTEXT14 = 1,
+ };
+
+ /**
+ * Video buffer types.
+ */
+ enum VIDEO_BUFFER_TYPE {
+ /**
+ * 1: Raw data.
+ */
+ VIDEO_BUFFER_RAW_DATA = 1,
+ /**
+ * 2: The same as VIDEO_BUFFER_RAW_DATA.
+ */
+ VIDEO_BUFFER_ARRAY = 2,
+ /**
+ * 3: The video buffer in the format of texture.
+ */
+ VIDEO_BUFFER_TEXTURE = 3,
+ };
+
+ /**
+ * The buffer type: #VIDEO_BUFFER_TYPE.
+ */
+ VIDEO_BUFFER_TYPE type;
+ /**
+ * The pixel format: #VIDEO_PIXEL_FORMAT
+ */
+ VIDEO_PIXEL_FORMAT format;
+ /**
+ * The video buffer.
+ */
+ void* buffer;
+ /**
+ * The line spacing of the incoming video frame (px). For
+ * texture, it is the width of the texture.
+ */
+ int stride;
+ /**
+ * The height of the incoming video frame.
+ */
+ int height;
+ /**
+ * [Raw data related parameter] The number of pixels trimmed from the left. The default value is
+ * 0.
+ */
+ int cropLeft;
+ /**
+ * [Raw data related parameter] The number of pixels trimmed from the top. The default value is
+ * 0.
+ */
+ int cropTop;
+ /**
+ * [Raw data related parameter] The number of pixels trimmed from the right. The default value is
+ * 0.
+ */
+ int cropRight;
+ /**
+ * [Raw data related parameter] The number of pixels trimmed from the bottom. The default value
+ * is 0.
+ */
+ int cropBottom;
+ /**
+ * [Raw data related parameter] The clockwise rotation information of the video frame. You can set the
+ * rotation angle as 0, 90, 180, or 270. The default value is 0.
+ */
+ int rotation;
+ /**
+ * The timestamp (ms) of the incoming video frame. An incorrect timestamp results in a frame loss or
+ * unsynchronized audio and video.
+ *
+ * Please refer to getAgoraCurrentMonotonicTimeInMs or getCurrentMonotonicTimeInMs
+ * to determine how to fill this filed.
+ */
+ long long timestamp;
+ /**
+ * [Texture-related parameter]
+ * When using the OpenGL interface (javax.microedition.khronos.egl.*) defined by Khronos, set EGLContext to this field.
+ * When using the OpenGL interface (android.opengl.*) defined by Android, set EGLContext to this field.
+ */
+ void *eglContext;
+ /**
+ * [Texture related parameter] Texture ID used by the video frame.
+ */
+ EGL_CONTEXT_TYPE eglType;
+ /**
+ * [Texture related parameter] Incoming 4 × 4 transformational matrix. The typical value is a unit matrix.
+ */
+ int textureId;
+ /**
+ * [Texture related parameter] Incoming 4 × 4 transformational matrix. The typical value is a unit matrix.
+ */
+ float matrix[16];
+ /**
+ * [Texture related parameter] The MetaData buffer.
+ * The default value is NULL
+ */
+ uint8_t* metadata_buffer;
+ /**
+ * [Texture related parameter] The MetaData size.
+ * The default value is 0
+ */
+ int metadata_size;
+ /**
+ * Indicates the output data of the portrait segmentation algorithm, which is consistent with the size of the video frame.
+ * The value range of each pixel is [0,255], where 0 represents the background; 255 represents the foreground (portrait).
+ * The default value is NULL
+ */
+ uint8_t* alphaBuffer;
+
+ /**
+ * [For Windows only] The pointer of ID3D11Texture2D used by the video frame.
+ */
+ void *d3d11_texture_2d;
+
+ /**
+ * [For Windows only] The index of ID3D11Texture2D array used by the video frame.
+ */
+ int texture_slice_index;
+};
+
+/**
+ * The definition of the VideoFrame struct.
+ */
+struct VideoFrame {
+ VideoFrame():
+ type(VIDEO_PIXEL_DEFAULT),
+ width(0),
+ height(0),
+ yStride(0),
+ uStride(0),
+ vStride(0),
+ yBuffer(NULL),
+ uBuffer(NULL),
+ vBuffer(NULL),
+ rotation(0),
+ renderTimeMs(0),
+ avsync_type(0),
+ metadata_buffer(NULL),
+ metadata_size(0),
+ sharedContext(0),
+ textureId(0),
+ d3d11Texture2d(NULL),
+ alphaBuffer(NULL),
+ pixelBuffer(NULL),
+ metaInfo(NULL){
+ memset(matrix, 0, sizeof(matrix));
+ }
+ /**
+ * The video pixel format: #VIDEO_PIXEL_FORMAT.
+ */
+ VIDEO_PIXEL_FORMAT type;
+ /**
+ * The width of the video frame.
+ */
+ int width;
+ /**
+ * The height of the video frame.
+ */
+ int height;
+ /**
+ * The line span of Y buffer in the YUV data.
+ */
+ int yStride;
+ /**
+ * The line span of U buffer in the YUV data.
+ */
+ int uStride;
+ /**
+ * The line span of V buffer in the YUV data.
+ */
+ int vStride;
+ /**
+ * The pointer to the Y buffer in the YUV data.
+ */
+ uint8_t* yBuffer;
+ /**
+ * The pointer to the U buffer in the YUV data.
+ */
+ uint8_t* uBuffer;
+ /**
+ * The pointer to the V buffer in the YUV data.
+ */
+ uint8_t* vBuffer;
+ /**
+ * The clockwise rotation information of this frame. You can set it as 0, 90, 180 or 270.
+ */
+ int rotation;
+ /**
+ * The timestamp to render the video stream. Use this parameter for audio-video synchronization when
+ * rendering the video.
+ *
+ * @note This parameter is for rendering the video, not capturing the video.
+ */
+ int64_t renderTimeMs;
+ /**
+ * The type of audio-video synchronization.
+ */
+ int avsync_type;
+ /**
+ * [Texture related parameter] The MetaData buffer.
+ * The default value is NULL
+ */
+ uint8_t* metadata_buffer;
+ /**
+ * [Texture related parameter] The MetaData size.
+ * The default value is 0
+ */
+ int metadata_size;
+ /**
+ * [Texture related parameter], egl context.
+ */
+ void* sharedContext;
+ /**
+ * [Texture related parameter], Texture ID used by the video frame.
+ */
+ int textureId;
+ /**
+ * [Texture related parameter] The pointer of ID3D11Texture2D used by the video frame,for Windows only.
+ */
+ void* d3d11Texture2d;
+ /**
+ * [Texture related parameter], Incoming 4 × 4 transformational matrix.
+ */
+ float matrix[16];
+ /**
+ * Indicates the output data of the portrait segmentation algorithm, which is consistent with the size of the video frame.
+ * The value range of each pixel is [0,255], where 0 represents the background; 255 represents the foreground (portrait).
+ * The default value is NULL
+ */
+ uint8_t* alphaBuffer;
+ /**
+ *The type of CVPixelBufferRef, for iOS and macOS only.
+ */
+ void* pixelBuffer;
+ /**
+ * The pointer to IVideoFrameMetaInfo, which is the interface to get metainfo contents from VideoFrame.
+ */
+ IVideoFrameMetaInfo* metaInfo;
+};
+
+/**
+ * The IVideoFrameObserver class.
+ */
+class IVideoFrameObserver {
+ public:
+ /**
+ * Occurs each time the player receives a video frame.
+ *
+ * After registering the video frame observer,
+ * the callback occurs each time the player receives a video frame to report the detailed information of the video frame.
+ * @param frame The detailed information of the video frame. See {@link VideoFrame}.
+ */
+ virtual void onFrame(const VideoFrame* frame) = 0;
+ virtual ~IVideoFrameObserver() {}
+ virtual bool isExternal() { return true; }
+ virtual VIDEO_PIXEL_FORMAT getVideoFormatPreference() { return VIDEO_PIXEL_DEFAULT; }
+};
+
+enum MEDIA_PLAYER_SOURCE_TYPE {
+ /**
+ * The real type of media player when use MEDIA_PLAYER_SOURCE_DEFAULT is decided by the
+ * type of SDK package. It is full feature media player in full-featured SDK, or simple
+ * media player in others.
+ */
+ MEDIA_PLAYER_SOURCE_DEFAULT,
+ /**
+ * Full featured media player is designed to support more codecs and media format, which
+ * requires more package size than simple player. If you need this player enabled, you
+ * might need to download a full-featured SDK.
+ */
+ MEDIA_PLAYER_SOURCE_FULL_FEATURED,
+ /**
+ * Simple media player with limit codec supported, which requires minimal package size
+ * requirement and is enabled by default
+ */
+ MEDIA_PLAYER_SOURCE_SIMPLE,
+};
+
+enum VIDEO_MODULE_POSITION {
+ POSITION_POST_CAPTURER = 1 << 0,
+ POSITION_PRE_RENDERER = 1 << 1,
+ POSITION_PRE_ENCODER = 1 << 2,
+ POSITION_POST_CAPTURER_ORIGIN = 1 << 3,
+};
+
+} // namespace base
+
+/**
+ * The audio frame observer.
+ */
+class IAudioPcmFrameSink {
+ public:
+ /**
+ * Occurs when each time the player receives an audio frame.
+ *
+ * After registering the audio frame observer,
+ * the callback occurs when each time the player receives an audio frame,
+ * reporting the detailed information of the audio frame.
+ * @param frame The detailed information of the audio frame. See {@link AudioPcmFrame}.
+ */
+ virtual void onFrame(agora::media::base::AudioPcmFrame* frame) = 0;
+ virtual ~IAudioPcmFrameSink() {}
+};
+
+/**
+ * The IAudioFrameObserverBase class.
+ */
+class IAudioFrameObserverBase {
+ public:
+ /**
+ * Audio frame types.
+ */
+ enum AUDIO_FRAME_TYPE {
+ /**
+ * 0: 16-bit PCM.
+ */
+ FRAME_TYPE_PCM16 = 0,
+ };
+ enum { MAX_HANDLE_TIME_CNT = 10 };
+ /**
+ * The definition of the AudioFrame struct.
+ */
+ struct AudioFrame {
+ /**
+ * The audio frame type: #AUDIO_FRAME_TYPE.
+ */
+ AUDIO_FRAME_TYPE type;
+ /**
+ * The number of samples per channel in this frame.
+ */
+ int samplesPerChannel;
+ /**
+ * The number of bytes per sample: #BYTES_PER_SAMPLE
+ */
+ agora::rtc::BYTES_PER_SAMPLE bytesPerSample;
+ /**
+ * The number of audio channels (data is interleaved, if stereo).
+ * - 1: Mono.
+ * - 2: Stereo.
+ */
+ int channels;
+ /**
+ * The sample rate
+ */
+ int samplesPerSec;
+ /**
+ * The data buffer of the audio frame. When the audio frame uses a stereo channel, the data
+ * buffer is interleaved.
+ *
+ * Buffer data size: buffer = samplesPerChannel × channels × bytesPerSample.
+ */
+ void* buffer;
+ /**
+ * The timestamp to render the audio data.
+ *
+ * You can use this timestamp to restore the order of the captured audio frame, and synchronize
+ * audio and video frames in video scenarios, including scenarios where external video sources
+ * are used.
+ */
+ int64_t renderTimeMs;
+ /**
+ * A reserved parameter.
+ *
+ * You can use this presentationMs parameter to indicate the presenation milisecond timestamp,
+ * this will then filled into audio4 extension part, the remote side could use this pts in av
+ * sync process with video frame.
+ */
+ int avsync_type;
+ /**
+ * The pts timestamp of this audio frame.
+ *
+ * This timestamp is used to indicate the origin pts time of the frame, and sync with video frame by
+ * the pts time stamp
+ */
+ int64_t presentationMs;
+ /**
+ * The number of the audio track.
+ */
+ int audioTrackNumber;
+
+ AudioFrame() : type(FRAME_TYPE_PCM16),
+ samplesPerChannel(0),
+ bytesPerSample(rtc::TWO_BYTES_PER_SAMPLE),
+ channels(0),
+ samplesPerSec(0),
+ buffer(NULL),
+ renderTimeMs(0),
+ avsync_type(0),
+ presentationMs(0),
+ audioTrackNumber(0) {}
+ };
+
+ enum AUDIO_FRAME_POSITION {
+ AUDIO_FRAME_POSITION_NONE = 0x0000,
+ /** The position for observing the playback audio of all remote users after mixing
+ */
+ AUDIO_FRAME_POSITION_PLAYBACK = 0x0001,
+ /** The position for observing the recorded audio of the local user
+ */
+ AUDIO_FRAME_POSITION_RECORD = 0x0002,
+ /** The position for observing the mixed audio of the local user and all remote users
+ */
+ AUDIO_FRAME_POSITION_MIXED = 0x0004,
+ /** The position for observing the audio of a single remote user before mixing
+ */
+ AUDIO_FRAME_POSITION_BEFORE_MIXING = 0x0008,
+ /** The position for observing the ear monitoring audio of the local user
+ */
+ AUDIO_FRAME_POSITION_EAR_MONITORING = 0x0010,
+ };
+
+ struct AudioParams {
+ /** The audio sample rate (Hz), which can be set as one of the following values:
+
+ - `8000`
+ - `16000` (Default)
+ - `32000`
+ - `44100 `
+ - `48000`
+ */
+ int sample_rate;
+
+ /* The number of audio channels, which can be set as either of the following values:
+
+ - `1`: Mono (Default)
+ - `2`: Stereo
+ */
+ int channels;
+
+ /* The use mode of the audio data. See AgoraAudioRawFrameOperationMode.
+ */
+ rtc::RAW_AUDIO_FRAME_OP_MODE_TYPE mode;
+
+ /** The number of samples. For example, set it as 1024 for RTMP or RTMPS
+ streaming.
+ */
+ int samples_per_call;
+
+ AudioParams() : sample_rate(0), channels(0), mode(rtc::RAW_AUDIO_FRAME_OP_MODE_READ_ONLY), samples_per_call(0) {}
+ AudioParams(int samplerate, int channel, rtc::RAW_AUDIO_FRAME_OP_MODE_TYPE type, int samplesPerCall) : sample_rate(samplerate), channels(channel), mode(type), samples_per_call(samplesPerCall) {}
+ };
+
+ public:
+ virtual ~IAudioFrameObserverBase() {}
+
+ /**
+ * Occurs when the recorded audio frame is received.
+ * @param channelId The channel name
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The recorded audio frame is valid and is encoded and sent.
+ * - false: The recorded audio frame is invalid and is not encoded or sent.
+ */
+ virtual bool onRecordAudioFrame(const char* channelId, AudioFrame& audioFrame) = 0;
+ /**
+ * Occurs when the playback audio frame is received.
+ * @param channelId The channel name
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The playback audio frame is valid and is encoded and sent.
+ * - false: The playback audio frame is invalid and is not encoded or sent.
+ */
+ virtual bool onPlaybackAudioFrame(const char* channelId, AudioFrame& audioFrame) = 0;
+ /**
+ * Occurs when the mixed audio data is received.
+ * @param channelId The channel name
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The mixed audio data is valid and is encoded and sent.
+ * - false: The mixed audio data is invalid and is not encoded or sent.
+ */
+ virtual bool onMixedAudioFrame(const char* channelId, AudioFrame& audioFrame) = 0;
+ /**
+ * Occurs when the ear monitoring audio frame is received.
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The ear monitoring audio data is valid and is encoded and sent.
+ * - false: The ear monitoring audio data is invalid and is not encoded or sent.
+ */
+ virtual bool onEarMonitoringAudioFrame(AudioFrame& audioFrame) = 0;
+ /**
+ * Occurs when the before-mixing playback audio frame is received.
+ * @param channelId The channel name
+ * @param userId ID of the remote user.
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The before-mixing playback audio frame is valid and is encoded and sent.
+ * - false: The before-mixing playback audio frame is invalid and is not encoded or sent.
+ */
+ virtual bool onPlaybackAudioFrameBeforeMixing(const char* channelId, base::user_id_t userId, AudioFrame& audioFrame) {
+ (void) channelId;
+ (void) userId;
+ (void) audioFrame;
+ return true;
+ }
+
+ /**
+ * Sets the frame position for the audio observer.
+ * @return A bit mask that controls the frame position of the audio observer.
+ * @note - Use '|' (the OR operator) to observe multiple frame positions.
+ *
+ * After you successfully register the audio observer, the SDK triggers this callback each time it receives a audio frame. You can determine which position to observe by setting the return value.
+ * The SDK provides 4 positions for observer. Each position corresponds to a callback function:
+ * - `AUDIO_FRAME_POSITION_PLAYBACK (1 << 0)`: The position for playback audio frame is received, which corresponds to the \ref onPlaybackFrame "onPlaybackFrame" callback.
+ * - `AUDIO_FRAME_POSITION_RECORD (1 << 1)`: The position for record audio frame is received, which corresponds to the \ref onRecordFrame "onRecordFrame" callback.
+ * - `AUDIO_FRAME_POSITION_MIXED (1 << 2)`: The position for mixed audio frame is received, which corresponds to the \ref onMixedFrame "onMixedFrame" callback.
+ * - `AUDIO_FRAME_POSITION_BEFORE_MIXING (1 << 3)`: The position for playback audio frame before mixing is received, which corresponds to the \ref onPlaybackFrameBeforeMixing "onPlaybackFrameBeforeMixing" callback.
+ * @return The bit mask that controls the audio observation positions.
+ * See AUDIO_FRAME_POSITION.
+ */
+
+ virtual int getObservedAudioFramePosition() = 0;
+
+ /** Sets the audio playback format
+ **Note**:
+
+ - The SDK calculates the sample interval according to the `AudioParams`
+ you set in the return value of this callback and triggers the
+ `onPlaybackAudioFrame` callback at the calculated sample interval.
+ Sample interval (seconds) = `samplesPerCall`/(`sampleRate` × `channel`).
+ Ensure that the value of sample interval is equal to or greater than 0.01.
+
+ @return Sets the audio format. See AgoraAudioParams.
+ */
+ virtual AudioParams getPlaybackAudioParams() = 0;
+
+ /** Sets the audio recording format
+ **Note**:
+ - The SDK calculates the sample interval according to the `AudioParams`
+ you set in the return value of this callback and triggers the
+ `onRecordAudioFrame` callback at the calculated sample interval.
+ Sample interval (seconds) = `samplesPerCall`/(`sampleRate` × `channel`).
+ Ensure that the value of sample interval is equal to or greater than 0.01.
+
+ @return Sets the audio format. See AgoraAudioParams.
+ */
+ virtual AudioParams getRecordAudioParams() = 0;
+
+ /** Sets the audio mixing format
+ **Note**:
+ - The SDK calculates the sample interval according to the `AudioParams`
+ you set in the return value of this callback and triggers the
+ `onMixedAudioFrame` callback at the calculated sample interval.
+ Sample interval (seconds) = `samplesPerCall`/(`sampleRate` × `channel`).
+ Ensure that the value of sample interval is equal to or greater than 0.01.
+
+ @return Sets the audio format. See AgoraAudioParams.
+ */
+ virtual AudioParams getMixedAudioParams() = 0;
+
+ /** Sets the ear monitoring audio format
+ **Note**:
+ - The SDK calculates the sample interval according to the `AudioParams`
+ you set in the return value of this callback and triggers the
+ `onEarMonitoringAudioFrame` callback at the calculated sample interval.
+ Sample interval (seconds) = `samplesPerCall`/(`sampleRate` × `channel`).
+ Ensure that the value of sample interval is equal to or greater than 0.01.
+
+ @return Sets the audio format. See AgoraAudioParams.
+ */
+ virtual AudioParams getEarMonitoringAudioParams() = 0;
+};
+
+/**
+ * The IAudioFrameObserver class.
+ */
+class IAudioFrameObserver : public IAudioFrameObserverBase {
+ public:
+ using IAudioFrameObserverBase::onPlaybackAudioFrameBeforeMixing;
+ /**
+ * Occurs when the before-mixing playback audio frame is received.
+ * @param channelId The channel name
+ * @param uid ID of the remote user.
+ * @param audioFrame The reference to the audio frame: AudioFrame.
+ * @return
+ * - true: The before-mixing playback audio frame is valid and is encoded and sent.
+ * - false: The before-mixing playback audio frame is invalid and is not encoded or sent.
+ */
+ virtual bool onPlaybackAudioFrameBeforeMixing(const char* channelId, rtc::uid_t uid, AudioFrame& audioFrame) = 0;
+};
+
+struct AudioSpectrumData {
+ /**
+ * The audio spectrum data of audio.
+ */
+ const float *audioSpectrumData;
+ /**
+ * The data length of audio spectrum data.
+ */
+ int dataLength;
+
+ AudioSpectrumData() : audioSpectrumData(NULL), dataLength(0) {}
+ AudioSpectrumData(const float *data, int length) :
+ audioSpectrumData(data), dataLength(length) {}
+};
+
+struct UserAudioSpectrumInfo {
+ /**
+ * User ID of the speaker.
+ */
+ agora::rtc::uid_t uid;
+ /**
+ * The audio spectrum data of audio.
+ */
+ struct AudioSpectrumData spectrumData;
+
+ UserAudioSpectrumInfo() : uid(0) {}
+
+ UserAudioSpectrumInfo(agora::rtc::uid_t uid, const float* data, int length) : uid(uid), spectrumData(data, length) {}
+};
+
+/**
+ * The IAudioSpectrumObserver class.
+ */
+class IAudioSpectrumObserver {
+public:
+ virtual ~IAudioSpectrumObserver() {}
+
+ /**
+ * Reports the audio spectrum of local audio.
+ *
+ * This callback reports the audio spectrum data of the local audio at the moment
+ * in the channel.
+ *
+ * You can set the time interval of this callback using \ref ILocalUser::enableAudioSpectrumMonitor "enableAudioSpectrumMonitor".
+ *
+ * @param data The audio spectrum data of local audio.
+ * - true: Processed.
+ * - false: Not processed.
+ */
+ virtual bool onLocalAudioSpectrum(const AudioSpectrumData& data) = 0;
+ /**
+ * Reports the audio spectrum of remote user.
+ *
+ * This callback reports the IDs and audio spectrum data of the loudest speakers at the moment
+ * in the channel.
+ *
+ * You can set the time interval of this callback using \ref ILocalUser::enableAudioSpectrumMonitor "enableAudioSpectrumMonitor".
+ *
+ * @param spectrums The pointer to \ref agora::media::UserAudioSpectrumInfo "UserAudioSpectrumInfo", which is an array containing
+ * the user ID and audio spectrum data for each speaker.
+ * - This array contains the following members:
+ * - `uid`, which is the UID of each remote speaker
+ * - `spectrumData`, which reports the audio spectrum of each remote speaker.
+ * @param spectrumNumber The array length of the spectrums.
+ * - true: Processed.
+ * - false: Not processed.
+ */
+ virtual bool onRemoteAudioSpectrum(const UserAudioSpectrumInfo* spectrums, unsigned int spectrumNumber) = 0;
+};
+
+/**
+ * The IVideoEncodedFrameObserver class.
+ */
+class IVideoEncodedFrameObserver {
+ public:
+ /**
+ * Occurs each time the SDK receives an encoded video image.
+ * @param uid The user id of remote user.
+ * @param imageBuffer The pointer to the video image buffer.
+ * @param length The data length of the video image.
+ * @param videoEncodedFrameInfo The information of the encoded video frame: EncodedVideoFrameInfo.
+ * @return Determines whether to accept encoded video image.
+ * - true: Accept.
+ * - false: Do not accept.
+ */
+ virtual bool onEncodedVideoFrameReceived(rtc::uid_t uid, const uint8_t* imageBuffer, size_t length,
+ const rtc::EncodedVideoFrameInfo& videoEncodedFrameInfo) = 0;
+
+ virtual ~IVideoEncodedFrameObserver() {}
+};
+
+/**
+ * The IVideoFrameObserver class.
+ */
+class IVideoFrameObserver {
+ public:
+ typedef media::base::VideoFrame VideoFrame;
+ /**
+ * The process mode of the video frame:
+ */
+ enum VIDEO_FRAME_PROCESS_MODE {
+ /**
+ * Read-only mode.
+ *
+ * In this mode, you do not modify the video frame. The video frame observer is a renderer.
+ */
+ PROCESS_MODE_READ_ONLY, // Observer works as a pure renderer and will not modify the original frame.
+ /**
+ * Read and write mode.
+ *
+ * In this mode, you modify the video frame. The video frame observer is a video filter.
+ */
+ PROCESS_MODE_READ_WRITE, // Observer works as a filter that will process the video frame and affect the following frame processing in SDK.
+ };
+
+ public:
+ virtual ~IVideoFrameObserver() {}
+
+ /**
+ * Occurs each time the SDK receives a video frame captured by the local camera.
+ *
+ * After you successfully register the video frame observer, the SDK triggers this callback each time
+ * a video frame is received. In this callback, you can get the video data captured by the local
+ * camera. You can then pre-process the data according to your scenarios.
+ *
+ * After pre-processing, you can send the processed video data back to the SDK by setting the
+ * `videoFrame` parameter in this callback.
+ *
+ * @note
+ * - If you get the video data in RGBA color encoding format, Agora does not support using this callback to send the processed data in RGBA color encoding format back to the SDK.
+ * - The video data that this callback gets has not been pre-processed, such as watermarking, cropping content, rotating, or image enhancement.
+ *
+ * @param videoFrame A pointer to the video frame: VideoFrame
+ * @param sourceType source type of video frame. See #VIDEO_SOURCE_TYPE.
+ * @return Determines whether to ignore the current video frame if the pre-processing fails:
+ * - true: Do not ignore.
+ * - false: Ignore, in which case this method does not sent the current video frame to the SDK.
+ */
+ virtual bool onCaptureVideoFrame(agora::rtc::VIDEO_SOURCE_TYPE sourceType, VideoFrame& videoFrame) = 0;
+
+ /**
+ * Occurs each time the SDK receives a video frame before encoding.
+ *
+ * After you successfully register the video frame observer, the SDK triggers this callback each time
+ * when it receives a video frame. In this callback, you can get the video data before encoding. You can then
+ * process the data according to your particular scenarios.
+ *
+ * After processing, you can send the processed video data back to the SDK by setting the
+ * `videoFrame` parameter in this callback.
+ *
+ * @note
+ * - To get the video data captured from the second screen before encoding, you need to set (1 << 2) as a frame position through `getObservedFramePosition`.
+ * - The video data that this callback gets has been pre-processed, such as watermarking, cropping content, rotating, or image enhancement.
+ * - This callback does not support sending processed RGBA video data back to the SDK.
+ *
+ * @param videoFrame A pointer to the video frame: VideoFrame
+ * @param sourceType source type of video frame. See #VIDEO_SOURCE_TYPE.
+ * @return Determines whether to ignore the current video frame if the pre-processing fails:
+ * - true: Do not ignore.
+ * - false: Ignore, in which case this method does not sent the current video frame to the SDK.
+ */
+ virtual bool onPreEncodeVideoFrame(agora::rtc::VIDEO_SOURCE_TYPE sourceType, VideoFrame& videoFrame) = 0;
+
+ /**
+ * Occurs each time the SDK receives a video frame decoded by the MediaPlayer.
+ *
+ * After you successfully register the video frame observer, the SDK triggers this callback each
+ * time a video frame is decoded. In this callback, you can get the video data decoded by the
+ * MediaPlayer. You can then pre-process the data according to your scenarios.
+ *
+ * After pre-processing, you can send the processed video data back to the SDK by setting the
+ * `videoFrame` parameter in this callback.
+ *
+ * @note
+ * - This callback will not be affected by the return values of \ref getVideoFrameProcessMode "getVideoFrameProcessMode", \ref getRotationApplied "getRotationApplied", \ref getMirrorApplied "getMirrorApplied", \ref getObservedFramePosition "getObservedFramePosition".
+ * - On Android, this callback is not affected by the return value of \ref getVideoFormatPreference "getVideoFormatPreference"
+ *
+ * @param videoFrame A pointer to the video frame: VideoFrame
+ * @param mediaPlayerId ID of the mediaPlayer.
+ * @return Determines whether to ignore the current video frame if the pre-processing fails:
+ * - true: Do not ignore.
+ * - false: Ignore, in which case this method does not sent the current video frame to the SDK.
+ */
+ virtual bool onMediaPlayerVideoFrame(VideoFrame& videoFrame, int mediaPlayerId) = 0;
+
+ /**
+ * Occurs each time the SDK receives a video frame sent by the remote user.
+ *
+ * After you successfully register the video frame observer, the SDK triggers this callback each time a
+ * video frame is received. In this callback, you can get the video data sent by the remote user. You
+ * can then post-process the data according to your scenarios.
+ *
+ * After post-processing, you can send the processed data back to the SDK by setting the `videoFrame`
+ * parameter in this callback.
+ *
+ * @note This callback does not support sending processed RGBA video data back to the SDK.
+ *
+ * @param channelId The channel name
+ * @param remoteUid ID of the remote user who sends the current video frame.
+ * @param videoFrame A pointer to the video frame: VideoFrame
+ * @return Determines whether to ignore the current video frame if the post-processing fails:
+ * - true: Do not ignore.
+ * - false: Ignore, in which case this method does not sent the current video frame to the SDK.
+ */
+ virtual bool onRenderVideoFrame(const char* channelId, rtc::uid_t remoteUid, VideoFrame& videoFrame) = 0;
+
+ virtual bool onTranscodedVideoFrame(VideoFrame& videoFrame) = 0;
+
+ /**
+ * Occurs each time the SDK receives a video frame and prompts you to set the process mode of the video frame.
+ *
+ * After you successfully register the video frame observer, the SDK triggers this callback each time it receives
+ * a video frame. You need to set your preferred process mode in the return value of this callback.
+ * @return VIDEO_FRAME_PROCESS_MODE.
+ */
+ virtual VIDEO_FRAME_PROCESS_MODE getVideoFrameProcessMode() {
+ return PROCESS_MODE_READ_ONLY;
+ }
+
+ /**
+ * Sets the format of the raw video data output by the SDK.
+ *
+ * If you want to get raw video data in a color encoding format other than YUV 420, register this callback when
+ * calling `registerVideoFrameObserver`. After you successfully register the video frame observer, the SDK triggers
+ * this callback each time it receives a video frame. You need to set your preferred video data in the return value
+ * of this callback.
+ *
+ * @note If you want the video captured by the sender to be the original format, set the original video data format
+ * to VIDEO_PIXEL_DEFAULT in the return value. On different platforms, the original video pixel format is also
+ * different, for the actual video pixel format, see `VideoFrame`.
+ *
+ * @return Sets the video format. See VIDEO_PIXEL_FORMAT.
+ */
+ virtual base::VIDEO_PIXEL_FORMAT getVideoFormatPreference() { return base::VIDEO_PIXEL_DEFAULT; }
+
+ /**
+ * Occurs each time the SDK receives a video frame, and prompts you whether to rotate the captured video.
+ *
+ * If you want to rotate the captured video according to the rotation member in the `VideoFrame` class, register this
+ * callback by calling `registerVideoFrameObserver`. After you successfully register the video frame observer, the
+ * SDK triggers this callback each time it receives a video frame. You need to set whether to rotate the video frame
+ * in the return value of this callback.
+ *
+ * @note This function only supports video data in RGBA or YUV420.
+ *
+ * @return Determines whether to rotate.
+ * - `true`: Rotate the captured video.
+ * - `false`: (Default) Do not rotate the captured video.
+ */
+ virtual bool getRotationApplied() { return false; }
+
+ /**
+ * Occurs each time the SDK receives a video frame and prompts you whether or not to mirror the captured video.
+ *
+ * If the video data you want to obtain is a mirror image of the original video, you need to register this callback
+ * when calling `registerVideoFrameObserver`. After you successfully register the video frame observer, the SDK
+ * triggers this callback each time it receives a video frame. You need to set whether or not to mirror the video
+ * frame in the return value of this callback.
+ *
+ * @note This function only supports video data in RGBA and YUV420 formats.
+ *
+ * @return Determines whether to mirror.
+ * - `true`: Mirror the captured video.
+ * - `false`: (Default) Do not mirror the captured video.
+ */
+ virtual bool getMirrorApplied() { return false; }
+
+ /**
+ * Sets the frame position for the video observer.
+ *
+ * After you successfully register the video observer, the SDK triggers this callback each time it receives
+ * a video frame. You can determine which position to observe by setting the return value. The SDK provides
+ * 3 positions for observer. Each position corresponds to a callback function:
+ *
+ * POSITION_POST_CAPTURER(1 << 0): The position after capturing the video data, which corresponds to the onCaptureVideoFrame callback.
+ * POSITION_PRE_RENDERER(1 << 1): The position before receiving the remote video data, which corresponds to the onRenderVideoFrame callback.
+ * POSITION_PRE_ENCODER(1 << 2): The position before encoding the video data, which corresponds to the onPreEncodeVideoFrame callback.
+ *
+ * To observe multiple frame positions, use '|' (the OR operator).
+ * This callback observes POSITION_POST_CAPTURER(1 << 0) and POSITION_PRE_RENDERER(1 << 1) by default.
+ * To conserve the system consumption, you can reduce the number of frame positions that you want to observe.
+ *
+ * @return A bit mask that controls the frame position of the video observer: VIDEO_OBSERVER_POSITION.
+ */
+ virtual uint32_t getObservedFramePosition() {
+ return base::POSITION_POST_CAPTURER | base::POSITION_PRE_RENDERER;
+ }
+
+ /**
+ * Indicate if the observer is for internal use.
+ * Note: Never override this function
+ * @return
+ * - true: the observer is for external use
+ * - false: the observer is for internal use
+ */
+ virtual bool isExternal() { return true; }
+};
+
+/**
+ * The external video source type.
+ */
+enum EXTERNAL_VIDEO_SOURCE_TYPE {
+ /**
+ * 0: non-encoded video frame.
+ */
+ VIDEO_FRAME = 0,
+ /**
+ * 1: encoded video frame.
+ */
+ ENCODED_VIDEO_FRAME,
+};
+
+/**
+ * The format of the recording file.
+ *
+ * @since v3.5.2
+ */
+enum MediaRecorderContainerFormat {
+ /**
+ * 1: (Default) MP4.
+ */
+ FORMAT_MP4 = 1,
+};
+/**
+ * The recording content.
+ *
+ * @since v3.5.2
+ */
+enum MediaRecorderStreamType {
+ /**
+ * Only audio.
+ */
+ STREAM_TYPE_AUDIO = 0x01,
+ /**
+ * Only video.
+ */
+ STREAM_TYPE_VIDEO = 0x02,
+ /**
+ * (Default) Audio and video.
+ */
+ STREAM_TYPE_BOTH = STREAM_TYPE_AUDIO | STREAM_TYPE_VIDEO,
+};
+/**
+ * The current recording state.
+ *
+ * @since v3.5.2
+ */
+enum RecorderState {
+ /**
+ * -1: An error occurs during the recording. See RecorderReasonCode for the reason.
+ */
+ RECORDER_STATE_ERROR = -1,
+ /**
+ * 2: The audio and video recording is started.
+ */
+ RECORDER_STATE_START = 2,
+ /**
+ * 3: The audio and video recording is stopped.
+ */
+ RECORDER_STATE_STOP = 3,
+};
+/**
+ * The reason for the state change
+ *
+ * @since v3.5.2
+ */
+enum RecorderReasonCode {
+ /**
+ * 0: No error occurs.
+ */
+ RECORDER_REASON_NONE = 0,
+ /**
+ * 1: The SDK fails to write the recorded data to a file.
+ */
+ RECORDER_REASON_WRITE_FAILED = 1,
+ /**
+ * 2: The SDK does not detect audio and video streams to be recorded, or audio and video streams are interrupted for more than five seconds during recording.
+ */
+ RECORDER_REASON_NO_STREAM = 2,
+ /**
+ * 3: The recording duration exceeds the upper limit.
+ */
+ RECORDER_REASON_OVER_MAX_DURATION = 3,
+ /**
+ * 4: The recording configuration changes.
+ */
+ RECORDER_REASON_CONFIG_CHANGED = 4,
+};
+/**
+ * Configurations for the local audio and video recording.
+ *
+ * @since v3.5.2
+ */
+struct MediaRecorderConfiguration {
+ /**
+ * The absolute path (including the filename extensions) of the recording file.
+ * For example, `C:\Users\\AppData\Local\Agora\\example.mp4` on Windows,
+ * `/App Sandbox/Library/Caches/example.mp4` on iOS, `/Library/Logs/example.mp4` on macOS, and
+ * `/storage/emulated/0/Android/data//files/example.mp4` on Android.
+ *
+ * @note Ensure that the specified path exists and is writable.
+ */
+ const char* storagePath;
+ /**
+ * The format of the recording file. See \ref agora::rtc::MediaRecorderContainerFormat "MediaRecorderContainerFormat".
+ */
+ MediaRecorderContainerFormat containerFormat;
+ /**
+ * The recording content. See \ref agora::rtc::MediaRecorderStreamType "MediaRecorderStreamType".
+ */
+ MediaRecorderStreamType streamType;
+ /**
+ * The maximum recording duration, in milliseconds. The default value is 120000.
+ */
+ int maxDurationMs;
+ /**
+ * The interval (ms) of updating the recording information. The value range is
+ * [1000,10000]. Based on the set value of `recorderInfoUpdateInterval`, the
+ * SDK triggers the \ref IMediaRecorderObserver::onRecorderInfoUpdated "onRecorderInfoUpdated"
+ * callback to report the updated recording information.
+ */
+ int recorderInfoUpdateInterval;
+
+ MediaRecorderConfiguration() : storagePath(NULL), containerFormat(FORMAT_MP4), streamType(STREAM_TYPE_BOTH), maxDurationMs(120000), recorderInfoUpdateInterval(0) {}
+ MediaRecorderConfiguration(const char* path, MediaRecorderContainerFormat format, MediaRecorderStreamType type, int duration, int interval) : storagePath(path), containerFormat(format), streamType(type), maxDurationMs(duration), recorderInfoUpdateInterval(interval) {}
+};
+/**
+ * Information for the recording file.
+ *
+ * @since v3.5.2
+ */
+struct RecorderInfo {
+ /**
+ * The absolute path of the recording file.
+ */
+ const char* fileName;
+ /**
+ * The recording duration, in milliseconds.
+ */
+ unsigned int durationMs;
+ /**
+ * The size in bytes of the recording file.
+ */
+ unsigned int fileSize;
+
+ RecorderInfo() : fileName(NULL), durationMs(0), fileSize(0) {}
+ RecorderInfo(const char* name, unsigned int dur, unsigned int size) : fileName(name), durationMs(dur), fileSize(size) {}
+};
+
+class IMediaRecorderObserver {
+ public:
+ /**
+ * Occurs when the recording state changes.
+ *
+ * @since v4.0.0
+ *
+ * When the local audio and video recording state changes, the SDK triggers this callback to report the current
+ * recording state and the reason for the change.
+ *
+ * @param channelId The channel name.
+ * @param uid ID of the user.
+ * @param state The current recording state. See \ref agora::media::RecorderState "RecorderState".
+ * @param reason The reason for the state change. See \ref agora::media::RecorderReasonCode "RecorderReasonCode".
+ */
+ virtual void onRecorderStateChanged(const char* channelId, rtc::uid_t uid, RecorderState state, RecorderReasonCode reason) = 0;
+ /**
+ * Occurs when the recording information is updated.
+ *
+ * @since v4.0.0
+ *
+ * After you successfully register this callback and enable the local audio and video recording, the SDK periodically triggers
+ * the `onRecorderInfoUpdated` callback based on the set value of `recorderInfoUpdateInterval`. This callback reports the
+ * filename, duration, and size of the current recording file.
+ *
+ * @param channelId The channel name.
+ * @param uid ID of the user.
+ * @param info Information about the recording file. See \ref agora::media::RecorderInfo "RecorderInfo".
+ *
+ */
+ virtual void onRecorderInfoUpdated(const char* channelId, rtc::uid_t uid, const RecorderInfo& info) = 0;
+
+ virtual ~IMediaRecorderObserver() {}
+};
+
+} // namespace media
+} // namespace agora
diff --git a/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraMediaPlayerTypes.h b/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraMediaPlayerTypes.h
new file mode 100644
index 000000000..3beaba788
--- /dev/null
+++ b/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraMediaPlayerTypes.h
@@ -0,0 +1,516 @@
+//
+// Agora Engine SDK
+//
+// Created by Sting Feng in 2020-05.
+// Copyright (c) 2017 Agora.io. All rights reserved.
+
+#pragma once // NOLINT(build/header_guard)
+
+#include
+#include
+
+#include "AgoraOptional.h"
+
+/**
+ * set analyze duration for real time stream
+ * @example "setPlayerOption(KEY_PLAYER_REAL_TIME_STREAM_ANALYZE_DURATION,1000000)"
+ */
+#define KEY_PLAYER_REAL_TIME_STREAM_ANALYZE_DURATION "analyze_duration"
+
+/**
+ * make the player to enable audio or not
+ * @example "setPlayerOption(KEY_PLAYER_ENABLE_AUDIO,0)"
+ */
+#define KEY_PLAYER_ENABLE_AUDIO "enable_audio"
+
+/**
+ * make the player to enable video or not
+ * @example "setPlayerOption(KEY_PLAYER_ENABLE_VIDEO,0)"
+ */
+#define KEY_PLAYER_ENABLE_VIDEO "enable_video"
+
+/**
+ * set the player enable to search metadata
+ * @example "setPlayerOption(KEY_PLAYER_DISABLE_SEARCH_METADATA,0)"
+ */
+#define KEY_PLAYER_ENABLE_SEARCH_METADATA "enable_search_metadata"
+
+/**
+ * set the player sei filter type
+ * @example "setPlayerOption(KEY_PLAYER_SEI_FILTER_TYPE,"5")"
+ */
+#define KEY_PLAYER_SEI_FILTER_TYPE "set_sei_filter_type"
+
+namespace agora {
+
+namespace media {
+
+namespace base {
+static const uint8_t kMaxCharBufferLength = 50;
+/**
+ * @brief The playback state.
+ *
+ */
+enum MEDIA_PLAYER_STATE {
+ /** Default state.
+ */
+ PLAYER_STATE_IDLE = 0,
+ /** Opening the media file.
+ */
+ PLAYER_STATE_OPENING,
+ /** The media file is opened successfully.
+ */
+ PLAYER_STATE_OPEN_COMPLETED,
+ /** Playing the media file.
+ */
+ PLAYER_STATE_PLAYING,
+ /** The playback is paused.
+ */
+ PLAYER_STATE_PAUSED,
+ /** The playback is completed.
+ */
+ PLAYER_STATE_PLAYBACK_COMPLETED,
+ /** All loops are completed.
+ */
+ PLAYER_STATE_PLAYBACK_ALL_LOOPS_COMPLETED,
+ /** The playback is stopped.
+ */
+ PLAYER_STATE_STOPPED,
+ /** Player pausing (internal)
+ */
+ PLAYER_STATE_PAUSING_INTERNAL = 50,
+ /** Player stopping (internal)
+ */
+ PLAYER_STATE_STOPPING_INTERNAL,
+ /** Player seeking state (internal)
+ */
+ PLAYER_STATE_SEEKING_INTERNAL,
+ /** Player getting state (internal)
+ */
+ PLAYER_STATE_GETTING_INTERNAL,
+ /** None state for state machine (internal)
+ */
+ PLAYER_STATE_NONE_INTERNAL,
+ /** Do nothing state for state machine (internal)
+ */
+ PLAYER_STATE_DO_NOTHING_INTERNAL,
+ /** Player set track state (internal)
+ */
+ PLAYER_STATE_SET_TRACK_INTERNAL,
+ /** The playback fails.
+ */
+ PLAYER_STATE_FAILED = 100,
+};
+/**
+ * @brief Player error code
+ *
+ */
+enum MEDIA_PLAYER_REASON {
+ /** No error.
+ */
+ PLAYER_REASON_NONE = 0,
+ /** The parameter is invalid.
+ */
+ PLAYER_REASON_INVALID_ARGUMENTS = -1,
+ /** Internel error.
+ */
+ PLAYER_REASON_INTERNAL = -2,
+ /** No resource.
+ */
+ PLAYER_REASON_NO_RESOURCE = -3,
+ /** Invalid media source.
+ */
+ PLAYER_REASON_INVALID_MEDIA_SOURCE = -4,
+ /** The type of the media stream is unknown.
+ */
+ PLAYER_REASON_UNKNOWN_STREAM_TYPE = -5,
+ /** The object is not initialized.
+ */
+ PLAYER_REASON_OBJ_NOT_INITIALIZED = -6,
+ /** The codec is not supported.
+ */
+ PLAYER_REASON_CODEC_NOT_SUPPORTED = -7,
+ /** Invalid renderer.
+ */
+ PLAYER_REASON_VIDEO_RENDER_FAILED = -8,
+ /** An error occurs in the internal state of the player.
+ */
+ PLAYER_REASON_INVALID_STATE = -9,
+ /** The URL of the media file cannot be found.
+ */
+ PLAYER_REASON_URL_NOT_FOUND = -10,
+ /** Invalid connection between the player and the Agora server.
+ */
+ PLAYER_REASON_INVALID_CONNECTION_STATE = -11,
+ /** The playback buffer is insufficient.
+ */
+ PLAYER_REASON_SRC_BUFFER_UNDERFLOW = -12,
+ /** The audio mixing file playback is interrupted.
+ */
+ PLAYER_REASON_INTERRUPTED = -13,
+ /** The SDK does not support this function.
+ */
+ PLAYER_REASON_NOT_SUPPORTED = -14,
+ /** The token has expired.
+ */
+ PLAYER_REASON_TOKEN_EXPIRED = -15,
+ /** The ip has expired.
+ */
+ PLAYER_REASON_IP_EXPIRED = -16,
+ /** An unknown error occurs.
+ */
+ PLAYER_REASON_UNKNOWN = -17,
+};
+
+/**
+ * @brief The type of the media stream.
+ *
+ */
+enum MEDIA_STREAM_TYPE {
+ /** The type is unknown.
+ */
+ STREAM_TYPE_UNKNOWN = 0,
+ /** The video stream.
+ */
+ STREAM_TYPE_VIDEO = 1,
+ /** The audio stream.
+ */
+ STREAM_TYPE_AUDIO = 2,
+ /** The subtitle stream.
+ */
+ STREAM_TYPE_SUBTITLE = 3,
+};
+
+/**
+ * @brief The playback event.
+ *
+ */
+enum MEDIA_PLAYER_EVENT {
+ /** The player begins to seek to the new playback position.
+ */
+ PLAYER_EVENT_SEEK_BEGIN = 0,
+ /** The seek operation completes.
+ */
+ PLAYER_EVENT_SEEK_COMPLETE = 1,
+ /** An error occurs during the seek operation.
+ */
+ PLAYER_EVENT_SEEK_ERROR = 2,
+ /** The player changes the audio track for playback.
+ */
+ PLAYER_EVENT_AUDIO_TRACK_CHANGED = 5,
+ /** player buffer low
+ */
+ PLAYER_EVENT_BUFFER_LOW = 6,
+ /** player buffer recover
+ */
+ PLAYER_EVENT_BUFFER_RECOVER = 7,
+ /** The video or audio is interrupted
+ */
+ PLAYER_EVENT_FREEZE_START = 8,
+ /** Interrupt at the end of the video or audio
+ */
+ PLAYER_EVENT_FREEZE_STOP = 9,
+ /** switch source begin
+ */
+ PLAYER_EVENT_SWITCH_BEGIN = 10,
+ /** switch source complete
+ */
+ PLAYER_EVENT_SWITCH_COMPLETE = 11,
+ /** switch source error
+ */
+ PLAYER_EVENT_SWITCH_ERROR = 12,
+ /** An application can render the video to less than a second
+ */
+ PLAYER_EVENT_FIRST_DISPLAYED = 13,
+ /** cache resources exceed the maximum file count
+ */
+ PLAYER_EVENT_REACH_CACHE_FILE_MAX_COUNT = 14,
+ /** cache resources exceed the maximum file size
+ */
+ PLAYER_EVENT_REACH_CACHE_FILE_MAX_SIZE = 15,
+ /** Triggered when a retry is required to open the media
+ */
+ PLAYER_EVENT_TRY_OPEN_START = 16,
+ /** Triggered when the retry to open the media is successful
+ */
+ PLAYER_EVENT_TRY_OPEN_SUCCEED = 17,
+ /** Triggered when retrying to open media fails
+ */
+ PLAYER_EVENT_TRY_OPEN_FAILED = 18,
+};
+
+/**
+ * @brief The play preload another source event.
+ *
+ */
+enum PLAYER_PRELOAD_EVENT {
+ /** preload source begin
+ */
+ PLAYER_PRELOAD_EVENT_BEGIN = 0,
+ /** preload source complete
+ */
+ PLAYER_PRELOAD_EVENT_COMPLETE = 1,
+ /** preload source error
+ */
+ PLAYER_PRELOAD_EVENT_ERROR = 2,
+};
+
+/**
+ * @brief The information of the media stream object.
+ *
+ */
+struct PlayerStreamInfo {
+ /** The index of the media stream. */
+ int streamIndex;
+
+ /** The type of the media stream. See {@link MEDIA_STREAM_TYPE}. */
+ MEDIA_STREAM_TYPE streamType;
+
+ /** The codec of the media stream. */
+ char codecName[kMaxCharBufferLength];
+
+ /** The language of the media stream. */
+ char language[kMaxCharBufferLength];
+
+ /** The frame rate (fps) if the stream is video. */
+ int videoFrameRate;
+
+ /** The video bitrate (bps) if the stream is video. */
+ int videoBitRate;
+
+ /** The video width (pixel) if the stream is video. */
+ int videoWidth;
+
+ /** The video height (pixel) if the stream is video. */
+ int videoHeight;
+
+ /** The rotation angle if the steam is video. */
+ int videoRotation;
+
+ /** The sample rate if the stream is audio. */
+ int audioSampleRate;
+
+ /** The number of audio channels if the stream is audio. */
+ int audioChannels;
+
+ /** The number of bits per sample if the stream is audio. */
+ int audioBitsPerSample;
+
+ /** The total duration (millisecond) of the media stream. */
+ int64_t duration;
+
+ PlayerStreamInfo() : streamIndex(0),
+ streamType(STREAM_TYPE_UNKNOWN),
+ videoFrameRate(0),
+ videoBitRate(0),
+ videoWidth(0),
+ videoHeight(0),
+ videoRotation(0),
+ audioSampleRate(0),
+ audioChannels(0),
+ audioBitsPerSample(0),
+ duration(0) {
+ memset(codecName, 0, sizeof(codecName));
+ memset(language, 0, sizeof(language));
+ }
+};
+
+/**
+ * @brief The information of the media stream object.
+ *
+ */
+struct SrcInfo {
+ /** The bitrate of the media stream. The unit of the number is kbps.
+ *
+ */
+ int bitrateInKbps;
+
+ /** The name of the media stream.
+ *
+ */
+ const char* name;
+
+};
+
+/**
+ * @brief The type of the media metadata.
+ *
+ */
+enum MEDIA_PLAYER_METADATA_TYPE {
+ /** The type is unknown.
+ */
+ PLAYER_METADATA_TYPE_UNKNOWN = 0,
+ /** The type is SEI.
+ */
+ PLAYER_METADATA_TYPE_SEI = 1,
+};
+
+struct CacheStatistics {
+ /** total data size of uri
+ */
+ int64_t fileSize;
+ /** data of uri has cached
+ */
+ int64_t cacheSize;
+ /** data of uri has downloaded
+ */
+ int64_t downloadSize;
+};
+
+/**
+ * @brief The real time statistics of the media stream being played.
+ *
+ */
+struct PlayerPlaybackStats {
+ /** Video fps.
+ */
+ int videoFps;
+ /** Video bitrate (Kbps).
+ */
+ int videoBitrateInKbps;
+ /** Audio bitrate (Kbps).
+ */
+ int audioBitrateInKbps;
+ /** Total bitrate (Kbps).
+ */
+ int totalBitrateInKbps;
+};
+
+/**
+ * @brief The updated information of media player.
+ *
+ */
+struct PlayerUpdatedInfo {
+ /** @technical preview
+ */
+ const char* internalPlayerUuid;
+ /** The device ID of the playback device.
+ */
+ const char* deviceId;
+ /** Video height.
+ */
+ int videoHeight;
+ /** Video width.
+ */
+ int videoWidth;
+ /** Audio sample rate.
+ */
+ int audioSampleRate;
+ /** The audio channel number.
+ */
+ int audioChannels;
+ /** The bit number of each audio sample.
+ */
+ int audioBitsPerSample;
+
+ PlayerUpdatedInfo()
+ : internalPlayerUuid(NULL),
+ deviceId(NULL),
+ videoHeight(0),
+ videoWidth(0),
+ audioSampleRate(0),
+ audioChannels(0),
+ audioBitsPerSample(0) {}
+};
+
+/**
+ * The custom data source provides a data stream input callback, and the player will continue to call back this interface, requesting the user to fill in the data that needs to be played.
+ */
+class IMediaPlayerCustomDataProvider {
+public:
+
+ /**
+ * @brief The player requests to read the data callback, you need to fill the specified length of data into the buffer
+ * @param buffer the buffer pointer that you need to fill data.
+ * @param bufferSize the bufferSize need to fill of the buffer pointer.
+ * @return you need return offset value if succeed. return 0 if failed.
+ */
+ virtual int onReadData(unsigned char *buffer, int bufferSize) = 0;
+
+ /**
+ * @brief The Player seek event callback, you need to operate the corresponding stream seek operation, You can refer to the definition of lseek() at https://man7.org/linux/man-pages/man2/lseek.2.html
+ * @param offset the value of seek offset.
+ * @param whence the postion of start seeking, the directive whence as follows:
+ * 0 - SEEK_SET : The file offset is set to offset bytes.
+ * 1 - SEEK_CUR : The file offset is set to its current location plus offset bytes.
+ * 2 - SEEK_END : The file offset is set to the size of the file plus offset bytes.
+ * 65536 - AVSEEK_SIZE : Optional. Passing this as the "whence" parameter to a seek function causes it to return the filesize without seeking anywhere.
+ * @return
+ * whence == 65536, return filesize if you need.
+ * whence >= 0 && whence < 3 , return offset value if succeed. return -1 if failed.
+ */
+ virtual int64_t onSeek(int64_t offset, int whence) = 0;
+
+ virtual ~IMediaPlayerCustomDataProvider() {}
+};
+
+struct MediaSource {
+ /**
+ * The URL of the media file that you want to play.
+ */
+ const char* url;
+ /**
+ * The URI of the media file
+ *
+ * When caching is enabled, if the url cannot distinguish the cache file name,
+ * the uri must be able to ensure that the cache file name corresponding to the url is unique.
+ */
+ const char* uri;
+ /**
+ * Set the starting position for playback, in ms.
+ */
+ int64_t startPos;
+ /**
+ * Determines whether to autoplay after opening a media resource.
+ * - true: (Default) Autoplay after opening a media resource.
+ * - false: Do not autoplay after opening a media resource.
+ */
+ bool autoPlay;
+ /**
+ * Determines whether to enable cache streaming to local files. If enable cached, the media player will
+ * use the url or uri as the cache index.
+ *
+ * @note
+ * The local cache function only supports on-demand video/audio streams and does not support live streams.
+ * Caching video and audio files based on the HLS protocol (m3u8) to your local device is not supported.
+ *
+ * - true: Enable cache.
+ * - false: (Default) Disable cache.
+ */
+ bool enableCache;
+ /**
+ * Determines whether to enable multi-track audio stream decoding.
+ * Then you can select multi audio track of the media file for playback or publish to channel
+ *
+ * @note
+ * If you use the selectMultiAudioTrack API, you must set enableMultiAudioTrack to true.
+ *
+ * - true: Enable MultiAudioTrack;.
+ * - false: (Default) Disable MultiAudioTrack;.
+ */
+ bool enableMultiAudioTrack;
+ /**
+ * Determines whether the opened media resource is a stream through the Agora Broadcast Streaming Network(CDN).
+ * - true: It is a stream through the Agora Broadcast Streaming Network.
+ * - false: (Default) It is not a stream through the Agora Broadcast Streaming Network.
+ */
+ Optional isAgoraSource;
+ /**
+ * Determines whether the opened media resource is a live stream. If is a live stream, it can speed up the opening of media resources.
+ * - true: It is a live stream.
+ * - false: (Default) It is not is a live stream.
+ */
+ Optional isLiveSource;
+ /**
+ * External custom data source object
+ */
+ IMediaPlayerCustomDataProvider* provider;
+
+ MediaSource() : url(NULL), uri(NULL), startPos(0), autoPlay(true), enableCache(false),
+ enableMultiAudioTrack(false), provider(NULL){
+ }
+};
+
+} // namespace base
+} // namespace media
+} // namespace agora
diff --git a/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraOptional.h b/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraOptional.h
new file mode 100644
index 000000000..97595be45
--- /dev/null
+++ b/Android/APIExample/agora-stream-encrypt/src/main/cpp/include/agora/AgoraOptional.h
@@ -0,0 +1,891 @@
+// Copyright (c) 2019 Agora.io. All rights reserved
+
+// This program is confidential and proprietary to Agora.io.
+// And may not be copied, reproduced, modified, disclosed to others, published
+// or used, in whole or in part, without the express prior written permission
+// of Agora.io.
+#pragma once
+
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+#include
+#endif
+#include
+
+#ifndef CONSTEXPR
+#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+#endif // !CONSTEXPR
+
+#ifndef NOEXCEPT
+#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
+#define NOEXCEPT(Expr) noexcept(Expr)
+#else
+#define NOEXCEPT(Expr)
+#endif
+#endif // !NOEXCEPT
+
+namespace agora {
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
+struct in_place_t {};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
+struct nullopt_t {
+ CONSTEXPR explicit nullopt_t(int) {}
+};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/in_place
+/*CONSTEXPR*/ const in_place_t in_place = {};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt
+/*CONSTEXPR*/ const nullopt_t nullopt(0);
+
+// Forward declaration, which is refered by following helpers.
+template
+class Optional;
+
+namespace internal {
+
+template
+struct OptionalStorageBase {
+ // Initializing |empty_| here instead of using default member initializing
+ // to avoid errors in g++ 4.8.
+ CONSTEXPR OptionalStorageBase() : is_populated_(false), empty_('\0') {}
+
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ template
+ CONSTEXPR explicit OptionalStorageBase(in_place_t, Args&&... args)
+ : is_populated_(true), value_(std::forward(args)...) {}
+#else
+ CONSTEXPR explicit OptionalStorageBase(in_place_t, const T& _value)
+ : is_populated_(true), value_(_value) {}
+#endif
+ // When T is not trivially destructible we must call its
+ // destructor before deallocating its memory.
+ // Note that this hides the (implicitly declared) move constructor, which
+ // would be used for constexpr move constructor in OptionalStorage.
+ // It is needed iff T is trivially move constructible. However, the current
+ // is_trivially_{copy,move}_constructible implementation requires
+ // is_trivially_destructible (which looks a bug, cf:
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
+ // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
+ // necessary for this case at the moment. Please see also the destructor
+ // comment in "is_trivially_destructible = true" specialization below.
+ ~OptionalStorageBase() {
+ if (is_populated_)
+ value_.~T();
+ }
+
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ template
+ void Init(Args&&... args) {
+ ::new (&value_) T(std::forward(args)...);
+ is_populated_ = true;
+ }
+#else
+ void Init(const T& _value) {
+ ::new (&value_) T(_value);
+ is_populated_ = true;
+ }
+#endif
+
+ bool is_populated_;
+
+ union {
+ // |empty_| exists so that the union will always be initialized, even when
+ // it doesn't contain a value. Union members must be initialized for the
+ // constructor to be 'constexpr'.
+ char empty_;
+ T value_;
+ };
+};
+
+// Implement conditional constexpr copy and move constructors. These are
+// constexpr if is_trivially_{copy,move}_constructible::value is true
+// respectively. If each is true, the corresponding constructor is defined as
+// "= default;", which generates a constexpr constructor (In this case,
+// the condition of constexpr-ness is satisfied because the base class also has
+// compiler generated constexpr {copy,move} constructors). Note that
+// placement-new is prohibited in constexpr.
+template
+struct OptionalStorage : OptionalStorageBase {
+ // This is no trivially {copy,move} constructible case. Other cases are
+ // defined below as specializations.
+
+ // Accessing the members of template base class requires explicit
+ // declaration.
+ using OptionalStorageBase::is_populated_;
+ using OptionalStorageBase::value_;
+ using OptionalStorageBase::Init;
+
+ // Inherit constructors (specifically, the in_place constructor).
+ //using OptionalStorageBase::OptionalStorageBase;
+
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ template
+ CONSTEXPR explicit OptionalStorage(in_place_t in_place, Args&&... args)
+ : OptionalStorageBase(in_place, std::forward(args)...) {}
+#else
+ CONSTEXPR explicit OptionalStorage(in_place_t in_place, const T& _value)
+ : OptionalStorageBase(in_place, _value) {}
+#endif
+
+ // User defined constructor deletes the default constructor.
+ // Define it explicitly.
+ OptionalStorage() {}
+
+ OptionalStorage(const OptionalStorage& other) {
+ if (other.is_populated_)
+ Init(other.value_);
+ }
+
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ OptionalStorage(OptionalStorage&& other) NOEXCEPT(std::is_nothrow_move_constructible::value) {
+ if (other.is_populated_)
+ Init(std::move(other.value_));
+ }
+#endif
+};
+
+// Base class to support conditionally usable copy-/move- constructors
+// and assign operators.
+template
+class OptionalBase {
+ // This class provides implementation rather than public API, so everything
+ // should be hidden. Often we use composition, but we cannot in this case
+ // because of C++ language restriction.
+ protected:
+ CONSTEXPR OptionalBase() {}
+ CONSTEXPR OptionalBase(const OptionalBase& other) : storage_(other.storage_) {}
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ CONSTEXPR OptionalBase(OptionalBase&& other) : storage_(std::move(other.storage_)) {}
+
+ template
+ CONSTEXPR explicit OptionalBase(in_place_t, Args&&... args)
+ : storage_(in_place, std::forward