diff --git a/Android/APIExample/README.md b/Android/APIExample/README.md
index c87e7e2d6..58bd1cbce 100644
--- a/Android/APIExample/README.md
+++ b/Android/APIExample/README.md
@@ -55,7 +55,7 @@ The project uses a single app to combine a variety of functionalities. Each func
1. In Android Studio, open `/Android/APIExample`.
2. Sync the project with Gradle files.
-3. Edit the `/Android/APIExample/app/src/main/res/values/string_config.xml` file.
+3. Edit the `/Android/APIExample/app/src/main/res/values/string_configs.xml` file.
- Replace `YOUR APP ID` with your App ID.
- Replace `YOUR ACCESS TOKEN` with the Access Token.
diff --git a/Android/APIExample/app/build.gradle b/Android/APIExample/app/build.gradle
index 6ee743196..5dbeb0161 100644
--- a/Android/APIExample/app/build.gradle
+++ b/Android/APIExample/app/build.gradle
@@ -7,7 +7,7 @@ android {
defaultConfig {
applicationId "io.agora.api.example"
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/ExampleActivity.java b/Android/APIExample/app/src/main/java/io/agora/api/example/ExampleActivity.java
index 3d4907049..2f0ddddcc 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/ExampleActivity.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/ExampleActivity.java
@@ -24,9 +24,9 @@
import io.agora.api.example.examples.advanced.MediaPlayerKit;
import io.agora.api.example.examples.advanced.PlayAudioFiles;
import io.agora.api.example.examples.advanced.PreCallTest;
-import io.agora.api.example.examples.advanced.ProcessAudioRawData;
import io.agora.api.example.examples.advanced.ProcessRawData;
import io.agora.api.example.examples.advanced.PushExternalVideo;
+import io.agora.api.example.examples.advanced.ScreenShare;
import io.agora.api.example.examples.advanced.SendDataStream;
import io.agora.api.example.examples.advanced.SetVideoProfile;
import io.agora.api.example.examples.advanced.SuperResolution;
@@ -156,12 +156,12 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
case R.id.action_mainFragment_senddatastream:
fragment = new SendDataStream();
break;
- case R.id.action_mainFragment_raw_audio:
- fragment = new ProcessAudioRawData();
- break;
case R.id.action_mainFragment_video_enhancement:
fragment = new FaceBeauty();
break;
+ case R.id.action_mainFragment_to_screen_share:
+ fragment = new ScreenShare();
+ break;
default:
fragment = new JoinChannelAudio();
break;
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/FaceBeauty.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/FaceBeauty.java
index 302ea8775..29111fced 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/FaceBeauty.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/FaceBeauty.java
@@ -22,6 +22,8 @@
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
+import org.json.JSONException;
+
import io.agora.api.example.MainApplication;
import io.agora.api.example.R;
import io.agora.api.example.annotation.Example;
@@ -32,8 +34,12 @@
import io.agora.rtc.RtcEngineConfig;
import io.agora.rtc.models.ChannelMediaOptions;
import io.agora.rtc.video.BeautyOptions;
+import io.agora.rtc.video.ColorEnhanceOptions;
+import io.agora.rtc.video.LowLightEnhanceOptions;
import io.agora.rtc.video.VideoCanvas;
+import io.agora.rtc.video.VideoDenoiserOptions;
import io.agora.rtc.video.VideoEncoderConfiguration;
+import io.agora.rtc.video.VirtualBackgroundSource;
import static io.agora.api.example.common.model.Examples.ADVANCED;
import static io.agora.rtc.Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
@@ -56,13 +62,19 @@ public class FaceBeauty extends BaseFragment implements View.OnClickListener, Co
private FrameLayout fl_local, fl_remote;
private LinearLayout controlPanel;
private Button join;
- private Switch beauty;
- private SeekBar seek_lightness, seek_redness, seek_sharpness, seek_smoothness;
+ private Switch beauty, lightness, colorful, noiseReduce, virtualBackground;
+ private SeekBar seek_lightness, seek_redness, seek_sharpness, seek_smoothness, seek_strength, seek_skin;
private EditText et_channel;
private RtcEngine engine;
private int myUid;
private boolean joined = false;
private BeautyOptions beautyOptions = new BeautyOptions();
+ private LowLightEnhanceOptions lowLightEnhanceOptions = new LowLightEnhanceOptions();
+ private ColorEnhanceOptions colorEnhanceOptions = new ColorEnhanceOptions();
+ private VideoDenoiserOptions videoDenoiserOptions = new VideoDenoiserOptions();
+ private VirtualBackgroundSource virtualBackgroundSource = new VirtualBackgroundSource();
+ private float skinProtect = 1.0f;
+ private float strength = 0.5f;
@Nullable
@Override
@@ -84,6 +96,14 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
controlPanel = view.findViewById(R.id.controlPanel);
beauty = view.findViewById(R.id.switch_face_beautify);
beauty.setOnCheckedChangeListener(this);
+ lightness = view.findViewById(R.id.switch_lightness);
+ lightness.setOnCheckedChangeListener(this);
+ colorful = view.findViewById(R.id.switch_color);
+ colorful.setOnCheckedChangeListener(this);
+ virtualBackground = view.findViewById(R.id.switch_virtual_background);
+ virtualBackground.setOnCheckedChangeListener(this);
+ noiseReduce = view.findViewById(R.id.switch_video_noise_reduce);
+ noiseReduce.setOnCheckedChangeListener(this);
seek_lightness = view.findViewById(R.id.lightening);
seek_lightness.setOnSeekBarChangeListener(this);
seek_redness = view.findViewById(R.id.redness);
@@ -92,6 +112,12 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
seek_sharpness.setOnSeekBarChangeListener(this);
seek_smoothness = view.findViewById(R.id.smoothness);
seek_smoothness.setOnSeekBarChangeListener(this);
+ seek_strength = view.findViewById(R.id.strength);
+ seek_strength.setOnSeekBarChangeListener(this);
+ seek_skin = view.findViewById(R.id.skinProtect);
+ seek_skin.setOnSeekBarChangeListener(this);
+
+ virtualBackgroundSource.blur_degree = 2;
}
@Override
@@ -274,9 +300,22 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.getId() == beauty.getId()){
engine.setBeautyEffectOptions(isChecked, beautyOptions);
}
+ else if(buttonView.getId() == lightness.getId()){
+ engine.setLowlightEnhanceOptions(isChecked, lowLightEnhanceOptions);
+ }
+ else if(buttonView.getId() == colorful.getId()){
+ colorEnhanceOptions.skinProtectLevel = skinProtect;
+ colorEnhanceOptions.strengthLevel = strength;
+ engine.setColorEnhanceOptions(isChecked, colorEnhanceOptions);
+ }
+ else if(buttonView.getId() == noiseReduce.getId()){
+ engine.setVideoDenoiserOptions(isChecked, videoDenoiserOptions);
+ }
+ else if(buttonView.getId() == virtualBackground.getId()){
+ engine.enableVirtualBackground(isChecked, virtualBackgroundSource);
+ }
}
-
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float value = ((float) progress) / 10;
@@ -296,6 +335,14 @@ else if(seekBar.getId() == seek_smoothness.getId()){
beautyOptions.smoothnessLevel = value;
engine.setBeautyEffectOptions(beauty.isChecked(), beautyOptions);
}
+ else if(seekBar.getId() == seek_strength.getId()) {
+ colorEnhanceOptions.strengthLevel = value;
+ engine.setColorEnhanceOptions(colorful.isChecked(), colorEnhanceOptions);
+ }
+ else if(seekBar.getId() == seek_skin.getId()) {
+ colorEnhanceOptions.skinProtectLevel = value;
+ engine.setColorEnhanceOptions(colorful.isChecked(), colorEnhanceOptions);
+ }
}
@Override
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MediaPlayerKit.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MediaPlayerKit.java
index b3ac96898..051bfaf9a 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MediaPlayerKit.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MediaPlayerKit.java
@@ -564,13 +564,15 @@ public void run() {
@Override
public void onDestroy() {
super.onDestroy();
- /**leaveChannel and Destroy the RtcEngine instance*/
- agoraMediaPlayerKit.destroy();
if (engine != null) {
- engine.leaveChannel();
+ /**leaveChannel and Destroy the RtcEngine instance*/
+ if (joined) {
+ engine.leaveChannel();
+ }
+ agoraMediaPlayerKit.destroy();
+ handler.post(RtcEngine::destroy);
+ engine = null;
}
- handler.post(RtcEngine::destroy);
- engine = null;
}
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessRawData.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessRawData.java
index dfdaa5cb1..71452bfb6 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessRawData.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessRawData.java
@@ -1,8 +1,15 @@
package io.agora.api.example.examples.advanced;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -10,8 +17,10 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.FrameLayout;
+import android.widget.Switch;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -19,19 +28,27 @@
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
import io.agora.advancedvideo.rawdata.MediaDataAudioObserver;
-import io.agora.advancedvideo.rawdata.MediaDataObserverPlugin;
import io.agora.advancedvideo.rawdata.MediaDataVideoObserver;
-import io.agora.advancedvideo.rawdata.MediaPreProcessing;
import io.agora.api.example.MainApplication;
import io.agora.api.example.R;
import io.agora.api.example.annotation.Example;
import io.agora.api.example.common.BaseFragment;
import io.agora.api.example.utils.CommonUtil;
import io.agora.api.example.utils.YUVUtils;
+import io.agora.rtc.AudioFrame;
import io.agora.rtc.Constants;
+import io.agora.rtc.IAudioFrameObserver;
import io.agora.rtc.IRtcEngineEventHandler;
+import io.agora.rtc.IVideoFrameObserver;
import io.agora.rtc.RtcEngine;
+import io.agora.rtc.audio.AudioParams;
import io.agora.rtc.models.ChannelMediaOptions;
import io.agora.rtc.video.VideoCanvas;
import io.agora.rtc.video.VideoEncoderConfiguration;
@@ -39,10 +56,7 @@
import static io.agora.api.example.common.model.Examples.ADVANCED;
import static io.agora.rtc.Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY;
import static io.agora.rtc.video.VideoCanvas.RENDER_MODE_HIDDEN;
-import static io.agora.rtc.video.VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15;
-import static io.agora.rtc.video.VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE;
import static io.agora.rtc.video.VideoEncoderConfiguration.STANDARD_BITRATE;
-import static io.agora.rtc.video.VideoEncoderConfiguration.VD_640x360;
@Example(
index = 10,
@@ -51,17 +65,22 @@
actionId = R.id.action_mainFragment_to_ProcessRawData,
tipsId = R.string.processrawdata
)
-public class ProcessRawData extends BaseFragment implements View.OnClickListener, MediaDataVideoObserver,
- MediaDataAudioObserver {
+public class ProcessRawData extends BaseFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener{
private static final String TAG = ProcessRawData.class.getSimpleName();
private FrameLayout fl_local, fl_remote;
- private Button join, blurBtn;
+ private Button join, snapshot;
+ private Switch audioMixingBtn;
private EditText et_channel;
private RtcEngine engine;
private int myUid;
- private boolean joined = false, blur = true;
- private MediaDataObserverPlugin mediaDataObserverPlugin;
+ private boolean joined = false, isSnapshot = false, audioMixing = false;
+ private static final Integer SAMPLE_RATE = 44100;
+ private static final Integer SAMPLE_NUM_OF_CHANNEL = 2;
+ private static final Integer BIT_PER_SAMPLE = 16;
+ private static final Integer SAMPLES_PER_CALL = 4410;
+ private static final String AUDIO_FILE = "output.raw";
+ private InputStream inputStream;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -79,6 +98,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
* @param handler IRtcEngineEventHandler is an abstract class providing default implementation.
* The SDK uses this class to report to the app on SDK runtime events.*/
engine = RtcEngine.create(context.getApplicationContext(), getString(R.string.agora_app_id), iRtcEngineEventHandler);
+ openAudioFile();
}
catch (Exception e) {
e.printStackTrace();
@@ -97,10 +117,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
join = view.findViewById(R.id.btn_join);
- blurBtn = view.findViewById(R.id.btn_blur);
+ snapshot = view.findViewById(R.id.btn_snapshot);
+ audioMixingBtn = view.findViewById(R.id.btn_audio_write_back);
et_channel = view.findViewById(R.id.et_channel);
join.setOnClickListener(this);
- blurBtn.setOnClickListener(this);
+ snapshot.setOnClickListener(this);
+ audioMixingBtn.setOnCheckedChangeListener(this);
fl_local = view.findViewById(R.id.fl_local);
fl_remote = view.findViewById(R.id.fl_remote);
}
@@ -108,26 +130,63 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- mediaDataObserverPlugin = MediaDataObserverPlugin.the();
- MediaPreProcessing.setCallback(mediaDataObserverPlugin);
- MediaPreProcessing.setVideoCaptureByteBuffer(mediaDataObserverPlugin.byteBufferCapture);
- mediaDataObserverPlugin.addVideoObserver(this);
}
@Override
public void onDestroy() {
- if (mediaDataObserverPlugin != null) {
- mediaDataObserverPlugin.removeVideoObserver(this);
- mediaDataObserverPlugin.removeAllBuffer();
- }
- MediaPreProcessing.releasePoint();
+ super.onDestroy();
/**leaveChannel and Destroy the RtcEngine instance*/
if (engine != null) {
engine.leaveChannel();
}
handler.post(RtcEngine::destroy);
engine = null;
- super.onDestroy();
+ closeAudioFile();
+ }
+
+ private void openAudioFile(){
+ try {
+ inputStream = this.getResources().getAssets().open(AUDIO_FILE);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void closeAudioFile(){
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private byte[] readBuffer(){
+ int byteSize = SAMPLES_PER_CALL * BIT_PER_SAMPLE / 8;
+ byte[] buffer = new byte[byteSize];
+ try {
+ if(inputStream.read(buffer) < 0){
+ inputStream.reset();
+ return readBuffer();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return buffer;
+ }
+
+ private byte[] audioAggregate(byte[] origin, byte[] buffer) {
+ byte[] output = new byte[origin.length];
+ for (int i = 0; i < origin.length; i++) {
+ output[i] = (byte) ((int) origin[i] + (int) buffer[i] / 2);
+ }
+ return output;
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (buttonView.getId() == R.id.btn_audio_write_back) {
+ audioMixing = isChecked;
+ }
}
@Override
@@ -174,14 +233,9 @@ public void onClick(View v) {
engine.leaveChannel();
join.setText(getString(R.string.join));
}
- } else if (v.getId() == R.id.btn_blur) {
- if (!blur) {
- blur = true;
- blurBtn.setText(getString(R.string.blur));
- } else {
- blur = false;
- blurBtn.setText(getString(R.string.closeblur));
- }
+ }
+ else if (v.getId() == R.id.btn_snapshot) {
+ isSnapshot = true;
}
}
@@ -252,6 +306,8 @@ private void joinChannel(String channelId) {
*/
engine.setMixedAudioFrameParameters(8000, 1024);
+ engine.registerVideoFrameObserver(iVideoFrameObserver);
+
/**Please configure accessToken in the string_config file.
* A temporary token generated in Console. A temporary token is valid for 24 hours. For details, see
* https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token
@@ -278,6 +334,108 @@ private void joinChannel(String channelId) {
}
// Prevent repeated entry
join.setEnabled(false);
+ /** Registers the audio observer object.
+ *
+ * @param observer Audio observer object to be registered. See {@link IAudioFrameObserver IAudioFrameObserver}. Set the value as @p null to cancel registering, if necessary.
+ * @return
+ * - 0: Success.
+ * - < 0: Failure.
+ */
+ engine.registerAudioFrameObserver(audioFrameObserver);
+ }
+
+ private final IVideoFrameObserver iVideoFrameObserver = new IVideoFrameObserver() {
+ @Override
+ public boolean onCaptureVideoFrame(VideoFrame videoFrame) {
+ if (!isSnapshot) {
+ return true;
+ }
+ Log.e(TAG, "onCaptureVideoFrame start blur");
+
+ byte[] i420 = YUVUtils.toWrappedI420(videoFrame.yBuffer, videoFrame.uBuffer, videoFrame.vBuffer, videoFrame.width, videoFrame.height);
+ int chromaWidth = (videoFrame.width + 1) / 2;
+ int chromaHeight = (videoFrame.height + 1) / 2;
+ int lengthY = videoFrame.width * videoFrame.height;
+ int lengthU = chromaWidth * chromaHeight;
+ int lengthV = lengthU;
+ int size = lengthY + lengthU + lengthV;
+ Bitmap bitmap = YUVUtils.i420ToBitmap(videoFrame.width, videoFrame.height, videoFrame.rotation, size, i420, videoFrame.yStride, videoFrame.uStride, videoFrame.vStride);
+
+ Matrix matrix = new Matrix();
+ matrix.setRotate(270);
+ Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, videoFrame.width, videoFrame.height, matrix, false);
+ saveBitmap2Gallery(newBitmap);
+
+ bitmap.recycle();
+ isSnapshot = false;
+ return true;
+ }
+
+ @Override
+ public boolean onRenderVideoFrame(int uid, VideoFrame videoFrame) {
+ return false;
+ }
+ };
+
+
+ public void saveBitmap2Gallery(Bitmap bm){
+ long currentTime = System.currentTimeMillis();
+
+ // name the file
+ String imageFileName = "IMG_AGORA_"+ currentTime + ".jpg";
+ String imageFilePath;
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+ imageFilePath = Environment.DIRECTORY_PICTURES + File.separator + "Agora" + File.separator;
+ else imageFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
+ + File.separator + "Agora"+ File.separator;
+
+ // write to file
+
+ OutputStream outputStream;
+ ContentResolver resolver = requireContext().getContentResolver();
+ ContentValues newScreenshot = new ContentValues();
+ Uri insert;
+ newScreenshot.put(MediaStore.Images.ImageColumns.DATE_ADDED,currentTime);
+ newScreenshot.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, imageFileName);
+ newScreenshot.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpg");
+ newScreenshot.put(MediaStore.Images.ImageColumns.WIDTH, bm.getWidth());
+ newScreenshot.put(MediaStore.Images.ImageColumns.HEIGHT, bm.getHeight());
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ newScreenshot.put(MediaStore.Images.ImageColumns.RELATIVE_PATH,imageFilePath);
+ }else{
+ // make sure the path is existed
+ File imageFileDir = new File(imageFilePath);
+ if(!imageFileDir.exists()){
+ boolean mkdir = imageFileDir.mkdirs();
+ if(!mkdir) {
+ showLongToast("save failed, error: cannot create folder. Make sure app has the permission.");
+ return;
+ }
+ }
+ newScreenshot.put(MediaStore.Images.ImageColumns.DATA, imageFilePath+imageFileName);
+ newScreenshot.put(MediaStore.Images.ImageColumns.TITLE, imageFileName);
+ }
+
+ // insert a new image
+ insert = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, newScreenshot);
+ // write data
+ outputStream = resolver.openOutputStream(insert);
+
+ bm.compress(Bitmap.CompressFormat.PNG, 80, outputStream);
+ outputStream.flush();
+ outputStream.close();
+
+ newScreenshot.clear();
+ newScreenshot.put(MediaStore.Images.ImageColumns.SIZE, new File(imageFilePath).length());
+ resolver.update(insert, newScreenshot, null, null);
+
+ showLongToast("save success, you can view it in gallery");
+ } catch (Exception e) {
+ showLongToast("save failed, error: "+ e.getMessage());
+ e.printStackTrace();
+ }
+
}
/**
@@ -308,6 +466,8 @@ public void onLeaveChannel(RtcStats stats) {
super.onLeaveChannel(stats);
Log.i(TAG, String.format("local user %d leaveChannel!", myUid));
showLongToast(String.format("local user %d leaveChannel!", myUid));
+ snapshot.setEnabled(false);
+ audioMixingBtn.setEnabled(false);
}
/**Occurs when the local user joins a specified channel.
@@ -326,6 +486,8 @@ public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
@Override
public void run() {
join.setEnabled(true);
+ snapshot.setEnabled(true);
+ audioMixingBtn.setEnabled(true);
join.setText(getString(R.string.leave));
}
});
@@ -347,10 +509,6 @@ public void onUserJoined(int uid, int elapsed) {
}
handler.post(() ->
{
- if (mediaDataObserverPlugin != null) {
- mediaDataObserverPlugin.addDecodeBuffer(uid);
- }
-
/**Display remote video stream*/
// Create render view by RtcEngine
SurfaceView surfaceView = RtcEngine.CreateRendererView(context);
@@ -383,9 +541,6 @@ public void onUserOffline(int uid, int reason) {
handler.post(new Runnable() {
@Override
public void run() {
- if (mediaDataObserverPlugin != null) {
- mediaDataObserverPlugin.removeDecodeBuffer(uid);
- }
/**Clear render view
Note: The video will stay at its last frame, to completely remove it you will need to
remove the SurfaceView from its parent*/
@@ -395,99 +550,64 @@ public void run() {
}
};
- @Override
- public void onCaptureVideoFrame(byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
- /**You can do some processing on the video frame here*/
- if (blur) {
- return;
+ private final IAudioFrameObserver audioFrameObserver = new IAudioFrameObserver() {
+ @Override
+ public boolean onRecordFrame(AudioFrame audioFrame) {
+ Log.i(TAG, "onRecordAudioFrame " + audioMixing);
+ if(audioMixing){
+ ByteBuffer byteBuffer = audioFrame.samples;
+ byte[] buffer = readBuffer();
+ byte[] origin = new byte[byteBuffer.remaining()];
+ byteBuffer.get(origin);
+ byteBuffer.flip();
+ byteBuffer.put(audioAggregate(origin, buffer), 0, byteBuffer.remaining());
+ }
+ return true;
}
- Log.e(TAG, "onCaptureVideoFrame start blur");
- Bitmap bitmap = YUVUtils.i420ToBitmap(width, height, rotation, bufferLength, data, yStride, uStride, vStride);
- Bitmap bmp = YUVUtils.blur(getContext(), bitmap, 8f);
- System.arraycopy(YUVUtils.bitmapToI420(width, height, bmp), 0, data, 0, bufferLength);
- }
- @Override
- public void onRenderVideoFrame(int uid, byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
- if (blur) {
- return;
+ @Override
+ public boolean onPlaybackFrame(AudioFrame audioFrame) {
+ return false;
}
- Log.e(TAG, "onRenderVideoFrame start blur");
- Bitmap bmp = YUVUtils.blur(getContext(), YUVUtils.i420ToBitmap(width, height, rotation, bufferLength, data, yStride, uStride, vStride), 8f);
- System.arraycopy(YUVUtils.bitmapToI420(width, height, bmp), 0, data, 0, bufferLength);
- }
-
- @Override
- public void onPreEncodeVideoFrame(byte[] data, int frameType, int width, int height, int bufferLength, int yStride, int uStride, int vStride, int rotation, long renderTimeMs) {
- /**You can do some processing on the video frame here*/
- Log.e(TAG, "onPreEncodeVideoFrame0");
- }
- /**
- * Retrieves the recorded audio frame.
- * @param audioFrameType only support FRAME_TYPE_PCM16
- * @param samples The number of samples per channel in the audio frame.
- * @param bytesPerSample The number of bytes per audio sample, which is usually 16-bit (2-byte).
- * @param channels The number of audio channels.
- * 1: Mono
- * 2: Stereo (the data is interleaved)
- * @param samplesPerSec The sample rate.
- * @param renderTimeMs The timestamp of the external audio frame.
- * @param bufferLength audio frame size*/
- @Override
- public void onRecordAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
-
- }
-
- /**
- * Retrieves the audio playback frame for getting the audio.
- * @param audioFrameType only support FRAME_TYPE_PCM16
- * @param samples The number of samples per channel in the audio frame.
- * @param bytesPerSample The number of bytes per audio sample, which is usually 16-bit (2-byte).
- * @param channels The number of audio channels.
- * 1: Mono
- * 2: Stereo (the data is interleaved)
- * @param samplesPerSec The sample rate.
- * @param renderTimeMs The timestamp of the external audio frame.
- * @param bufferLength audio frame size*/
- @Override
- public void onPlaybackAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
+ @Override
+ public boolean onPlaybackFrameBeforeMixing(AudioFrame audioFrame, int uid) {
+ return false;
+ }
- }
+ @Override
+ public boolean onMixedFrame(AudioFrame audioFrame) {
+ return false;
+ }
+ @Override
+ public boolean isMultipleChannelFrameWanted() {
+ return false;
+ }
- /**
- * Retrieves the audio frame of a specified user before mixing.
- * The SDK triggers this callback if isMultipleChannelFrameWanted returns false.
- * @param uid remote user id
- * @param audioFrameType only support FRAME_TYPE_PCM16
- * @param samples The number of samples per channel in the audio frame.
- * @param bytesPerSample The number of bytes per audio sample, which is usually 16-bit (2-byte).
- * @param channels The number of audio channels.
- * 1: Mono
- * 2: Stereo (the data is interleaved)
- * @param samplesPerSec The sample rate.
- * @param renderTimeMs The timestamp of the external audio frame.
- * @param bufferLength audio frame size*/
- @Override
- public void onPlaybackAudioFrameBeforeMixing(int uid, byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
+ @Override
+ public boolean onPlaybackFrameBeforeMixingEx(AudioFrame audioFrame, int uid, String channelId) {
+ return false;
+ }
- }
+ @Override
+ public int getObservedAudioFramePosition() {
+ return IAudioFrameObserver.POSITION_RECORD | IAudioFrameObserver.POSITION_MIXED;
+ }
- /**
- * Retrieves the mixed recorded and playback audio frame.
- * @param audioFrameType only support FRAME_TYPE_PCM16
- * @param samples The number of samples per channel in the audio frame.
- * @param bytesPerSample The number of bytes per audio sample, which is usually 16-bit (2-byte).
- * @param channels The number of audio channels.
- * 1: Mono
- * 2: Stereo (the data is interleaved)
- * @param samplesPerSec The sample rate.
- * @param renderTimeMs The timestamp of the external audio frame.
- * @param bufferLength audio frame size*/
- @Override
- public void onMixedAudioFrame(byte[] data, int audioFrameType, int samples, int bytesPerSample, int channels, int samplesPerSec, long renderTimeMs, int bufferLength) {
+ @Override
+ public AudioParams getRecordAudioParams() {
+ return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL);
+ }
- }
+ @Override
+ public AudioParams getPlaybackAudioParams() {
+ return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY, SAMPLES_PER_CALL);
+ }
+ @Override
+ public AudioParams getMixedAudioParams() {
+ return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY, SAMPLES_PER_CALL);
+ }
+ };
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessAudioRawData.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ScreenShare.java
old mode 100755
new mode 100644
similarity index 63%
rename from Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessAudioRawData.java
rename to Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ScreenShare.java
index 8f8576503..997f81d3f
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessAudioRawData.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ScreenShare.java
@@ -2,16 +2,16 @@
import android.content.Context;
import android.os.Bundle;
-import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.CompoundButton;
import android.widget.EditText;
-import android.widget.Switch;
+import android.widget.FrameLayout;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -19,177 +19,129 @@
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
+import io.agora.api.example.MainApplication;
import io.agora.api.example.R;
import io.agora.api.example.annotation.Example;
import io.agora.api.example.common.BaseFragment;
import io.agora.api.example.utils.CommonUtil;
-import io.agora.rtc.AudioFrame;
import io.agora.rtc.Constants;
-import io.agora.rtc.IAudioFrameObserver;
import io.agora.rtc.IRtcEngineEventHandler;
import io.agora.rtc.RtcEngine;
-import io.agora.rtc.audio.AudioParams;
+import io.agora.rtc.ScreenCaptureParameters;
import io.agora.rtc.models.ChannelMediaOptions;
+import io.agora.rtc.video.VideoCanvas;
+import io.agora.rtc.video.VideoEncoderConfiguration;
import static io.agora.api.example.common.model.Examples.ADVANCED;
-import static io.agora.rtc.IRtcEngineEventHandler.ClientRole.CLIENT_ROLE_BROADCASTER;
+import static io.agora.rtc.video.VideoCanvas.RENDER_MODE_HIDDEN;
+import static io.agora.rtc.video.VideoEncoderConfiguration.STANDARD_BITRATE;
-/**
- * This demo demonstrates how to make a one-to-one voice call
- *
- * @author cjw
- */
@Example(
- index = 24,
+ index = 6,
group = ADVANCED,
- name = R.string.item_raw_audio,
- actionId = R.id.action_mainFragment_raw_audio,
- tipsId = R.string.rawaudio
+ name = R.string.item_ScreenShare,
+ actionId = R.id.action_mainFragment_to_screen_share,
+ tipsId = R.string.ScreenShare
)
-public class ProcessAudioRawData extends BaseFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
- private static final String TAG = ProcessAudioRawData.class.getSimpleName();
+public class ScreenShare extends BaseFragment implements View.OnClickListener {
+
+ private static final String TAG = ScreenShare.class.getSimpleName();
+
+ private FrameLayout fl_remote;
+ private Button join;
private EditText et_channel;
- private Button mute, join, speaker;
- private Switch writeBackAudio;
+ private TextView description;
private RtcEngine engine;
private int myUid;
private boolean joined = false;
- private boolean isWriteBackAudio = false;
- private static final Integer SAMPLE_RATE = 44100;
- private static final Integer SAMPLE_NUM_OF_CHANNEL = 2;
- private static final Integer BIT_PER_SAMPLE = 16;
- private static final Integer SAMPLES_PER_CALL = 4410;
- private static final String AUDIO_FILE = "output.raw";
- private InputStream inputStream;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- handler = new Handler();
- }
@Nullable
@Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_raw_audio, container, false);
- return view;
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
+ {
+ return inflater.inflate(R.layout.fragment_screen_share, container, false);
}
@Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
+ {
super.onViewCreated(view, savedInstanceState);
join = view.findViewById(R.id.btn_join);
+ description = view.findViewById(R.id.description);
et_channel = view.findViewById(R.id.et_channel);
view.findViewById(R.id.btn_join).setOnClickListener(this);
- mute = view.findViewById(R.id.btn_mute);
- mute.setOnClickListener(this);
- speaker = view.findViewById(R.id.btn_speaker);
- speaker.setOnClickListener(this);
- writeBackAudio = view.findViewById(R.id.audioWriteBack);
- writeBackAudio.setOnCheckedChangeListener(this);
+ fl_remote = view.findViewById(R.id.fl_remote);
}
@Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ public void onActivityCreated(@Nullable Bundle savedInstanceState)
+ {
super.onActivityCreated(savedInstanceState);
// Check if the context is valid
Context context = getContext();
- if (context == null) {
+ if (context == null)
+ {
return;
}
- try {
+ try
+ {
/**Creates an RtcEngine instance.
* @param context The context of Android Activity
* @param appId The App ID issued to you by Agora. See
* How to get the App ID
* @param handler IRtcEngineEventHandler is an abstract class providing default implementation.
* The SDK uses this class to report to the app on SDK runtime events.*/
- String appId = getString(R.string.agora_app_id);
- engine = RtcEngine.create(getContext().getApplicationContext(), appId, iRtcEngineEventHandler);
- openAudioFile();
+ engine = RtcEngine.create(context.getApplicationContext(), getString(R.string.agora_app_id), iRtcEngineEventHandler);
}
- catch (Exception e) {
+ catch (Exception e)
+ {
e.printStackTrace();
getActivity().onBackPressed();
}
}
@Override
- public void onDestroy() {
+ public void onDestroy()
+ {
super.onDestroy();
/**leaveChannel and Destroy the RtcEngine instance*/
- if (engine != null) {
+ if(engine != null)
+ {
engine.leaveChannel();
}
handler.post(RtcEngine::destroy);
engine = null;
- closeAudioFile();
- }
-
- private void openAudioFile(){
- try {
- inputStream = this.getResources().getAssets().open(AUDIO_FILE);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private void closeAudioFile(){
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private byte[] readBuffer(){
- int byteSize = SAMPLES_PER_CALL * BIT_PER_SAMPLE / 8;
- byte[] buffer = new byte[byteSize];
- try {
- if(inputStream.read(buffer) < 0){
- inputStream.reset();
- return readBuffer();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return buffer;
- }
-
- private byte[] audioAggregate(byte[] origin, byte[] buffer) {
- byte[] output = new byte[origin.length];
- for (int i = 0; i < origin.length; i++) {
- output[i] = (byte) ((int) origin[i] + (int) buffer[i] / 2);
- }
- return output;
}
@Override
public void onClick(View v) {
- if (v.getId() == R.id.btn_join) {
- if (!joined) {
+
+ if (v.getId() == R.id.btn_join)
+ {
+ if (!joined)
+ {
CommonUtil.hideInputBoard(getActivity(), et_channel);
// call when join button hit
String channelId = et_channel.getText().toString();
// Check permission
- if (AndPermission.hasPermissions(this, Permission.Group.STORAGE, Permission.Group.MICROPHONE, Permission.Group.CAMERA)) {
+ if (AndPermission.hasPermissions(this, Permission.Group.STORAGE, Permission.Group.MICROPHONE, Permission.Group.CAMERA))
+ {
joinChannel(channelId);
return;
}
// Request permission
AndPermission.with(this).runtime().permission(
Permission.Group.STORAGE,
- Permission.Group.MICROPHONE
+ Permission.Group.MICROPHONE,
+ Permission.Group.CAMERA
).onGranted(permissions ->
{
// Permissions Granted
joinChannel(channelId);
}).start();
- } else {
+ }
+ else
+ {
joined = false;
/**After joining a channel, the user must call the leaveChannel method to end the
* call before joining another channel. This method returns 0 if the user leaves the
@@ -210,29 +162,19 @@ public void onClick(View v) {
* triggers the removeInjectStreamUrl method.*/
engine.leaveChannel();
join.setText(getString(R.string.join));
- speaker.setText(getString(R.string.speaker));
- speaker.setEnabled(false);
- mute.setText(getString(R.string.closemicrophone));
- mute.setEnabled(false);
}
- } else if (v.getId() == R.id.btn_mute) {
- mute.setActivated(!mute.isActivated());
- mute.setText(getString(mute.isActivated() ? R.string.openmicrophone : R.string.closemicrophone));
- /**Turn off / on the microphone, stop / start local audio collection and push streaming.*/
- engine.muteLocalAudioStream(mute.isActivated());
- } else if (v.getId() == R.id.btn_speaker) {
- speaker.setActivated(!speaker.isActivated());
- speaker.setText(getString(speaker.isActivated() ? R.string.earpiece : R.string.speaker));
- /**Turn off / on the speaker and change the audio playback route.*/
- engine.setEnableSpeakerphone(speaker.isActivated());
}
}
- /**
- * @param channelId Specify the channel name that you want to join.
- * Users that input the same channel name join the same channel.
- */
- private void joinChannel(String channelId) {
+ private void joinChannel(String channelId)
+ {
+ // Check if the context is valid
+ Context context = getContext();
+ if (context == null)
+ {
+ return;
+ }
+
/** Sets the channel profile of the Agora RtcEngine.
CHANNEL_PROFILE_COMMUNICATION(0): (Default) The Communication profile.
Use this profile in one-on-one calls or group calls, where all users can talk freely.
@@ -241,62 +183,67 @@ private void joinChannel(String channelId) {
an audience can only receive streams.*/
engine.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING);
/**In the demo, the default is to enter as the anchor.*/
- engine.setClientRole(CLIENT_ROLE_BROADCASTER);
+ engine.setClientRole(IRtcEngineEventHandler.ClientRole.CLIENT_ROLE_BROADCASTER);
+ // Enable video module
+ engine.enableVideo();
+
+ ScreenCaptureParameters screenCaptureParameters = new ScreenCaptureParameters();
+ screenCaptureParameters.captureAudio = true;
+ screenCaptureParameters.captureVideo = true;
+ ScreenCaptureParameters.VideoCaptureParameters videoCaptureParameters = new ScreenCaptureParameters.VideoCaptureParameters();
+ screenCaptureParameters.videoCaptureParameters = videoCaptureParameters;
+ engine.startScreenCapture(screenCaptureParameters);
+ description.setText("Screen Sharing Starting");
+
/**Please configure accessToken in the string_config file.
* A temporary token generated in Console. A temporary token is valid for 24 hours. For details, see
* https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token
* A token generated at the server. This applies to scenarios with high-security requirements. For details, see
* https://docs.agora.io/en/cloud-recording/token_server_java?platform=Java*/
String accessToken = getString(R.string.agora_access_token);
- if (TextUtils.equals(accessToken, "") || TextUtils.equals(accessToken, "<#YOUR ACCESS TOKEN#>")) {
+ if (TextUtils.equals(accessToken, "") || TextUtils.equals(accessToken, "<#YOUR ACCESS TOKEN#>"))
+ {
accessToken = null;
}
/** Allows a user to join a channel.
if you do not specify the uid, we will generate the uid for you*/
- engine.enableAudioVolumeIndication(1000, 3, true);
ChannelMediaOptions option = new ChannelMediaOptions();
option.autoSubscribeAudio = true;
option.autoSubscribeVideo = true;
int res = engine.joinChannel(accessToken, channelId, "Extra Optional Data", 0, option);
- if (res != 0) {
+ if (res != 0)
+ {
// Usually happens with invalid parameters
// Error code description can be found at:
// en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
// cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
showAlert(RtcEngine.getErrorDescription(Math.abs(res)));
- Log.e(TAG, RtcEngine.getErrorDescription(Math.abs(res)));
return;
}
// Prevent repeated entry
join.setEnabled(false);
- /** Registers the audio observer object.
- *
- * @param observer Audio observer object to be registered. See {@link IAudioFrameObserver IAudioFrameObserver}. Set the value as @p null to cancel registering, if necessary.
- * @return
- * - 0: Success.
- * - < 0: Failure.
- */
- engine.registerAudioFrameObserver(audioFrameObserver);
}
/**
* IRtcEngineEventHandler is an abstract class providing default implementation.
* The SDK uses this class to report to the app on SDK runtime events.
*/
- private final IRtcEngineEventHandler iRtcEngineEventHandler = new IRtcEngineEventHandler() {
-
+ private final IRtcEngineEventHandler iRtcEngineEventHandler = new IRtcEngineEventHandler()
+ {
/**Reports a warning during SDK runtime.
* Warning code: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_warn_code.html*/
@Override
- public void onWarning(int warn) {
+ public void onWarning(int warn)
+ {
Log.w(TAG, String.format("onWarning code %d message %s", warn, RtcEngine.getErrorDescription(warn)));
}
/**Reports an error during SDK runtime.
* Error code: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html*/
@Override
- public void onError(int err) {
+ public void onError(int err)
+ {
Log.e(TAG, String.format("onError code %d message %s", err, RtcEngine.getErrorDescription(err)));
showAlert(String.format("onError code %d message %s", err, RtcEngine.getErrorDescription(err)));
}
@@ -305,7 +252,8 @@ public void onError(int err) {
* @param stats With this callback, the application retrieves the channel information,
* such as the call duration and statistics.*/
@Override
- public void onLeaveChannel(RtcStats stats) {
+ public void onLeaveChannel(RtcStats stats)
+ {
super.onLeaveChannel(stats);
Log.i(TAG, String.format("local user %d leaveChannel!", myUid));
showLongToast(String.format("local user %d leaveChannel!", myUid));
@@ -318,23 +266,28 @@ public void onLeaveChannel(RtcStats stats) {
* @param uid User ID
* @param elapsed Time elapsed (ms) from the user calling joinChannel until this callback is triggered*/
@Override
- public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
+ public void onJoinChannelSuccess(String channel, int uid, int elapsed)
+ {
Log.i(TAG, String.format("onJoinChannelSuccess channel %s uid %d", channel, uid));
showLongToast(String.format("onJoinChannelSuccess channel %s uid %d", channel, uid));
myUid = uid;
joined = true;
- handler.post(new Runnable() {
+ handler.post(new Runnable()
+ {
@Override
- public void run() {
- speaker.setEnabled(true);
- mute.setEnabled(true);
+ public void run()
+ {
join.setEnabled(true);
join.setText(getString(R.string.leave));
- writeBackAudio.setEnabled(true);
}
});
}
+ @Override
+ public void onFirstLocalVideoFramePublished(int elapsed) {
+ description.setText("Screen Sharing started");
+ }
+
/**Since v2.9.0.
* This callback indicates the state change of the remote audio stream.
* PS: This callback does not work properly when the number of users (in the Communication profile) or
@@ -365,23 +318,91 @@ public void run() {
* REMOTE_AUDIO_REASON_REMOTE_UNMUTED(6): The remote user resumes sending the audio stream
* or enables the audio module.
* REMOTE_AUDIO_REASON_REMOTE_OFFLINE(7): The remote user leaves the channel.
- * @param elapsed Time elapsed (ms) from the local user calling the joinChannel method
+ * @param elapsed Time elapsed (ms) from the local user calling the joinChannel method
* until the SDK triggers this callback.*/
@Override
- public void onRemoteAudioStateChanged(int uid, int state, int reason, int elapsed) {
+ public void onRemoteAudioStateChanged(int uid, int state, int reason, int elapsed)
+ {
super.onRemoteAudioStateChanged(uid, state, reason, elapsed);
Log.i(TAG, "onRemoteAudioStateChanged->" + uid + ", state->" + state + ", reason->" + reason);
}
+ /**Since v2.9.0.
+ * Occurs when the remote video state changes.
+ * PS: This callback does not work properly when the number of users (in the Communication
+ * profile) or broadcasters (in the Live-broadcast profile) in the channel exceeds 17.
+ * @param uid ID of the remote user whose video state changes.
+ * @param state State of the remote video:
+ * REMOTE_VIDEO_STATE_STOPPED(0): The remote video is in the default state, probably due
+ * to REMOTE_VIDEO_STATE_REASON_LOCAL_MUTED(3), REMOTE_VIDEO_STATE_REASON_REMOTE_MUTED(5),
+ * or REMOTE_VIDEO_STATE_REASON_REMOTE_OFFLINE(7).
+ * REMOTE_VIDEO_STATE_STARTING(1): The first remote video packet is received.
+ * REMOTE_VIDEO_STATE_DECODING(2): The remote video stream is decoded and plays normally,
+ * probably due to REMOTE_VIDEO_STATE_REASON_NETWORK_RECOVERY (2),
+ * REMOTE_VIDEO_STATE_REASON_LOCAL_UNMUTED(4), REMOTE_VIDEO_STATE_REASON_REMOTE_UNMUTED(6),
+ * or REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK_RECOVERY(9).
+ * REMOTE_VIDEO_STATE_FROZEN(3): The remote video is frozen, probably due to
+ * REMOTE_VIDEO_STATE_REASON_NETWORK_CONGESTION(1) or REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK(8).
+ * REMOTE_VIDEO_STATE_FAILED(4): The remote video fails to start, probably due to
+ * REMOTE_VIDEO_STATE_REASON_INTERNAL(0).
+ * @param reason The reason of the remote video state change:
+ * REMOTE_VIDEO_STATE_REASON_INTERNAL(0): Internal reasons.
+ * REMOTE_VIDEO_STATE_REASON_NETWORK_CONGESTION(1): Network congestion.
+ * REMOTE_VIDEO_STATE_REASON_NETWORK_RECOVERY(2): Network recovery.
+ * REMOTE_VIDEO_STATE_REASON_LOCAL_MUTED(3): The local user stops receiving the remote
+ * video stream or disables the video module.
+ * REMOTE_VIDEO_STATE_REASON_LOCAL_UNMUTED(4): The local user resumes receiving the remote
+ * video stream or enables the video module.
+ * REMOTE_VIDEO_STATE_REASON_REMOTE_MUTED(5): The remote user stops sending the video
+ * stream or disables the video module.
+ * REMOTE_VIDEO_STATE_REASON_REMOTE_UNMUTED(6): The remote user resumes sending the video
+ * stream or enables the video module.
+ * REMOTE_VIDEO_STATE_REASON_REMOTE_OFFLINE(7): The remote user leaves the channel.
+ * REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK(8): The remote media stream falls back to the
+ * audio-only stream due to poor network conditions.
+ * REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK_RECOVERY(9): The remote media stream switches
+ * back to the video stream after the network conditions improve.
+ * @param elapsed Time elapsed (ms) from the local user calling the joinChannel method until
+ * the SDK triggers this callback.*/
+ @Override
+ public void onRemoteVideoStateChanged(int uid, int state, int reason, int elapsed)
+ {
+ super.onRemoteVideoStateChanged(uid, state, reason, elapsed);
+ Log.i(TAG, "onRemoteVideoStateChanged->" + uid + ", state->" + state + ", reason->" + reason);
+ }
+
/**Occurs when a remote user (Communication)/host (Live Broadcast) joins the channel.
* @param uid ID of the user whose audio state changes.
* @param elapsed Time delay (ms) from the local user calling joinChannel/setClientRole
* until this callback is triggered.*/
@Override
- public void onUserJoined(int uid, int elapsed) {
+ public void onUserJoined(int uid, int elapsed)
+ {
super.onUserJoined(uid, elapsed);
Log.i(TAG, "onUserJoined->" + uid);
showLongToast(String.format("user %d joined!", uid));
+ /**Check if the context is correct*/
+ Context context = getContext();
+ if (context == null) {
+ return;
+ }
+ handler.post(() ->
+ {
+ /**Display remote video stream*/
+ SurfaceView surfaceView = null;
+ if (fl_remote.getChildCount() > 0)
+ {
+ fl_remote.removeAllViews();
+ }
+ // Create render view by RtcEngine
+ surfaceView = RtcEngine.CreateRendererView(context);
+ surfaceView.setZOrderMediaOverlay(true);
+ // Add to the remote container
+ fl_remote.addView(surfaceView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+ // Setup remote video to render
+ engine.setupRemoteVideo(new VideoCanvas(surfaceView, RENDER_MODE_HIDDEN, uid));
+ });
}
/**Occurs when a remote user (Communication)/host (Live Broadcast) leaves the channel.
@@ -395,81 +416,19 @@ public void onUserJoined(int uid, int elapsed) {
* USER_OFFLINE_BECOME_AUDIENCE(2): (Live broadcast only.) The client role switched from
* the host to the audience.*/
@Override
- public void onUserOffline(int uid, int reason) {
+ public void onUserOffline(int uid, int reason)
+ {
Log.i(TAG, String.format("user %d offline! reason:%d", uid, reason));
showLongToast(String.format("user %d offline! reason:%d", uid, reason));
- }
-
- @Override
- public void onActiveSpeaker(int uid) {
- super.onActiveSpeaker(uid);
- Log.i(TAG, String.format("onActiveSpeaker:%d", uid));
- }
- };
-
- private final IAudioFrameObserver audioFrameObserver = new IAudioFrameObserver() {
- @Override
- public boolean onRecordFrame(AudioFrame audioFrame) {
- Log.i(TAG, "onRecordAudioFrame " + isWriteBackAudio);
- if(isWriteBackAudio){
- ByteBuffer byteBuffer = audioFrame.samples;
- byte[] buffer = readBuffer();
- byte[] origin = new byte[byteBuffer.remaining()];
- byteBuffer.get(origin);
- byteBuffer.flip();
- byteBuffer.put(audioAggregate(origin, buffer), 0, byteBuffer.remaining());
- }
- return true;
- }
-
- @Override
- public boolean onPlaybackFrame(AudioFrame audioFrame) {
- return false;
- }
-
- @Override
- public boolean onPlaybackFrameBeforeMixing(AudioFrame audioFrame, int uid) {
- return false;
- }
-
- @Override
- public boolean onMixedFrame(AudioFrame audioFrame) {
- return false;
- }
-
- @Override
- public boolean isMultipleChannelFrameWanted() {
- return false;
- }
-
- @Override
- public boolean onPlaybackFrameBeforeMixingEx(AudioFrame audioFrame, int uid, String channelId) {
- return false;
- }
-
- @Override
- public int getObservedAudioFramePosition() {
- return IAudioFrameObserver.POSITION_RECORD | IAudioFrameObserver.POSITION_MIXED;
- }
-
- @Override
- public AudioParams getRecordAudioParams() {
- return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL);
- }
-
- @Override
- public AudioParams getPlaybackAudioParams() {
- return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY, SAMPLES_PER_CALL);
- }
-
- @Override
- public AudioParams getMixedAudioParams() {
- return new AudioParams(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY, SAMPLES_PER_CALL);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ /**Clear render view
+ Note: The video will stay at its last frame, to completely remove it you will need to
+ remove the SurfaceView from its parent*/
+ engine.setupRemoteVideo(new VideoCanvas(null, RENDER_MODE_HIDDEN, uid));
+ }
+ });
}
};
-
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- isWriteBackAudio = b;
- }
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SuperResolution.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SuperResolution.java
index df3d2c78e..48e40eec4 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SuperResolution.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/SuperResolution.java
@@ -50,7 +50,7 @@ public class SuperResolution extends BaseFragment implements View.OnClickListene
private static final String TAG = SuperResolution.class.getSimpleName();
private FrameLayout fl_local, fl_remote;
- private Button join, btnSuperResolution;
+ private Button join, btnSuperResolution, switchCamera;
private EditText et_channel;
private RtcEngine engine;
private int myUid;
@@ -73,9 +73,12 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
join = view.findViewById(R.id.btn_join);
btnSuperResolution = view.findViewById(R.id.btn_super_resolution);
btnSuperResolution.setEnabled(false);
+ switchCamera = view.findViewById(R.id.btn_switch);
+ switchCamera.setEnabled(false);
et_channel = view.findViewById(R.id.et_channel);
view.findViewById(R.id.btn_join).setOnClickListener(this);
view.findViewById(R.id.btn_super_resolution).setOnClickListener(this);
+ view.findViewById(R.id.btn_switch).setOnClickListener(this);
fl_local = view.findViewById(R.id.fl_local);
fl_remote = view.findViewById(R.id.fl_remote);
}
@@ -172,7 +175,17 @@ public void onClick(View v)
}
}
else if(v.getId() == R.id.btn_super_resolution){
- engine.enableRemoteSuperResolution(remoteUid, !enableSuperResolution);
+ int ret = engine.enableRemoteSuperResolution(remoteUid, !enableSuperResolution);
+ if(enableSuperResolution){
+ enableSuperResolution = false;
+ btnSuperResolution.setText(getText(R.string.opensuperr));
+ }
+ if(ret!=0){
+ Log.w(TAG, String.format("onWarning code %d ", ret));
+ }
+ }
+ else if(v.getId() == R.id.btn_switch){
+ engine.switchCamera();
}
}
@@ -259,6 +272,7 @@ private void joinChannel(String channelId)
public void onWarning(int warn)
{
Log.w(TAG, String.format("onWarning code %d message %s", warn, RtcEngine.getErrorDescription(warn)));
+ showAlert(String.format("onWarning code %d message %s", warn, RtcEngine.getErrorDescription(warn)));
}
/**Reports an error during SDK runtime.
@@ -421,6 +435,7 @@ public void onUserJoined(int uid, int elapsed)
engine.setupRemoteVideo(new VideoCanvas(surfaceView, RENDER_MODE_HIDDEN, uid));
remoteUid = uid;
btnSuperResolution.setEnabled(true);
+ switchCamera.setEnabled(true);
});
}
@@ -447,6 +462,7 @@ public void run() {
remove the SurfaceView from its parent*/
engine.setupRemoteVideo(new VideoCanvas(null, RENDER_MODE_HIDDEN, uid));
btnSuperResolution.setEnabled(false);
+ switchCamera.setEnabled(false);
}
});
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelAudio.java b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelAudio.java
index 78a4c2a13..45187ee4e 100755
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelAudio.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/examples/basic/JoinChannelAudio.java
@@ -116,7 +116,7 @@ public void onClick(View v) {
// call when join button hit
String channelId = et_channel.getText().toString();
// Check permission
- if (AndPermission.hasPermissions(this, Permission.Group.STORAGE, Permission.Group.MICROPHONE, Permission.Group.CAMERA)) {
+ if (AndPermission.hasPermissions(this, Permission.Group.STORAGE, Permission.Group.MICROPHONE)) {
joinChannel(channelId);
return;
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/api/example/utils/YUVUtils.java b/Android/APIExample/app/src/main/java/io/agora/api/example/utils/YUVUtils.java
index 41dd89583..e3da4472a 100644
--- a/Android/APIExample/app/src/main/java/io/agora/api/example/utils/YUVUtils.java
+++ b/Android/APIExample/app/src/main/java/io/agora/api/example/utils/YUVUtils.java
@@ -14,6 +14,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
public class YUVUtils {
@@ -145,4 +146,30 @@ public static byte[] bitmapToI420(int inputWidth, int inputHeight, Bitmap scaled
return yuv;
}
+ public static byte[] toWrappedI420(ByteBuffer bufferY,
+ ByteBuffer bufferU,
+ ByteBuffer bufferV,
+ int width,
+ int height) {
+ int chromaWidth = (width + 1) / 2;
+ int chromaHeight = (height + 1) / 2;
+ int lengthY = width * height;
+ int lengthU = chromaWidth * chromaHeight;
+ int lengthV = lengthU;
+
+
+ int size = lengthY + lengthU + lengthV;
+
+ byte[] out = new byte[size];
+
+ int readY = Math.min(lengthY, bufferY.remaining());
+ bufferY.get(out, 0 , readY);
+ int readU = Math.min(lengthU, bufferU.remaining());
+ bufferU.get(out, lengthY, readU);
+ int readV = Math.min(lengthV, bufferV.remaining());
+ bufferV.get(out, lengthY + lengthU, readV);
+
+ return out;
+ }
+
}
diff --git a/Android/APIExample/app/src/main/res/layout/fragment_process_rawdata.xml b/Android/APIExample/app/src/main/res/layout/fragment_process_rawdata.xml
index fc51abf6b..eb157c553 100644
--- a/Android/APIExample/app/src/main/res/layout/fragment_process_rawdata.xml
+++ b/Android/APIExample/app/src/main/res/layout/fragment_process_rawdata.xml
@@ -44,12 +44,25 @@
+ android:enabled="false"
+ android:text="@string/snapshot" />
+
+
diff --git a/Android/APIExample/app/src/main/res/layout/fragment_raw_audio.xml b/Android/APIExample/app/src/main/res/layout/fragment_raw_audio.xml
deleted file mode 100755
index 900f44df0..000000000
--- a/Android/APIExample/app/src/main/res/layout/fragment_raw_audio.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Android/APIExample/app/src/main/res/layout/fragment_screen_share.xml b/Android/APIExample/app/src/main/res/layout/fragment_screen_share.xml
new file mode 100644
index 000000000..1143d2246
--- /dev/null
+++ b/Android/APIExample/app/src/main/res/layout/fragment_screen_share.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Android/APIExample/app/src/main/res/layout/fragment_super_resolution.xml b/Android/APIExample/app/src/main/res/layout/fragment_super_resolution.xml
index 06893e21e..71aef713f 100644
--- a/Android/APIExample/app/src/main/res/layout/fragment_super_resolution.xml
+++ b/Android/APIExample/app/src/main/res/layout/fragment_super_resolution.xml
@@ -45,6 +45,22 @@
android:enabled="false"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Android/APIExample/app/src/main/res/navigation/nav_graph.xml b/Android/APIExample/app/src/main/res/navigation/nav_graph.xml
index 2085c0933..ad54d7a5c 100755
--- a/Android/APIExample/app/src/main/res/navigation/nav_graph.xml
+++ b/Android/APIExample/app/src/main/res/navigation/nav_graph.xml
@@ -92,15 +92,15 @@
+
-
@@ -242,6 +242,11 @@
android:name="io.agora.api.example.examples.advanced.MultiProcess"
android:label="TwoProcess"
tools:layout="@layout/fragment_two_process_screen_share" />
+
-
diff --git a/Android/APIExample/app/src/main/res/values-zh/strings.xml b/Android/APIExample/app/src/main/res/values-zh/strings.xml
index 33692089d..9bc7a825d 100644
--- a/Android/APIExample/app/src/main/res/values-zh/strings.xml
+++ b/Android/APIExample/app/src/main/res/values-zh/strings.xml
@@ -133,6 +133,7 @@
姝ょず渚嬫紨绀轰簡鍦ㄩ煶棰戦氳瘽杩囩▼涓浣曢氳繃鍥炶皟鑾峰彇瑁告暟鎹殑鍔熻兘銆
闊抽鑰宠繑
姝ょず渚嬫紨绀轰簡闊抽閫氳瘽杩囩▼涓璖DK鍐呯疆鐨勫悇绫昏棰戝寮哄姛鑳姐
+ 姝ょず渚嬫紨绀轰簡闊抽閫氳瘽杩囩▼涓娇鐢⊿DK鎻愪緵鐨勬墜鏈哄睆骞曞叡浜姛鑳姐
娣烽煶鎺у埗
寮濮
鎭㈠鎾斁
@@ -178,4 +179,8 @@
瑙嗛闄嶅櫔
寮哄害
鑲よ壊淇濇姢
+ 灞忓箷鍏变韩
+ 铏氭嫙鑳屾櫙
+ 鎽勫儚澶村垏鎹
+ 鎴睆
\ No newline at end of file
diff --git a/Android/APIExample/app/src/main/res/values/colors.xml b/Android/APIExample/app/src/main/res/values/colors.xml
index 030098fe0..e5fc74bc9 100644
--- a/Android/APIExample/app/src/main/res/values/colors.xml
+++ b/Android/APIExample/app/src/main/res/values/colors.xml
@@ -3,4 +3,5 @@
#6200EE
#3700B3
#03DAC5
+ #939393
diff --git a/Android/APIExample/app/src/main/res/values/strings.xml b/Android/APIExample/app/src/main/res/values/strings.xml
index c7813b111..e73d03eac 100644
--- a/Android/APIExample/app/src/main/res/values/strings.xml
+++ b/Android/APIExample/app/src/main/res/values/strings.xml
@@ -135,6 +135,7 @@
This example shows how to use RTC Engine to share Artifactial Reality App to remote audience. AR module is based on Google ARCore in this Example.
This example shows how to use sendDataStream API to send your custom data along with Video Frame in Channel.
This example shows how to register Audio Observer to engine for extract raw audio data during RTC communication
+ This example shows how to use startScreenCapture API to publish phone screen content during RTC communication
Audio Loopback
This example shows the features for video enhancement for RTC communication.
Audio Mixing Control
@@ -182,4 +183,8 @@
Video Denoise
Strength
Skin Protect
+ Screen Share
+ Virtual Background
+ switch camera
+ Snapshot
diff --git a/Android/APIExample/lib-component/build.gradle b/Android/APIExample/lib-component/build.gradle
index f410b0573..ac4ede6df 100644
--- a/Android/APIExample/lib-component/build.gradle
+++ b/Android/APIExample/lib-component/build.gradle
@@ -5,7 +5,7 @@ android {
buildToolsVersion "29.0.3"
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
@@ -23,14 +23,15 @@ android {
}
dependencies {
- api fileTree(dir: 'libs', include: ['*.jar'])
+ api fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
- api 'io.agora.rtc:full-sdk:3.6.0.1'
+ api 'io.agora.rtc:full-sdk:3.6.2'
api 'io.agora:player:1.3.0'
+ api 'io.agora.rtc:full-screen-sharing:3.6.2'
}
diff --git a/Android/APIExample/lib-push-externalvideo/build.gradle b/Android/APIExample/lib-push-externalvideo/build.gradle
index 0580f8882..f6c630945 100644
--- a/Android/APIExample/lib-push-externalvideo/build.gradle
+++ b/Android/APIExample/lib-push-externalvideo/build.gradle
@@ -5,7 +5,7 @@ android {
buildToolsVersion "29.0.3"
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/Android/APIExample/lib-raw-data/build.gradle b/Android/APIExample/lib-raw-data/build.gradle
index e04fd9311..0dd78834c 100644
--- a/Android/APIExample/lib-raw-data/build.gradle
+++ b/Android/APIExample/lib-raw-data/build.gradle
@@ -5,7 +5,7 @@ android {
buildToolsVersion "29.0.2"
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/Android/APIExample/lib-screensharing/build.gradle b/Android/APIExample/lib-screensharing/build.gradle
index 5f7ffb803..d64cd28c5 100644
--- a/Android/APIExample/lib-screensharing/build.gradle
+++ b/Android/APIExample/lib-screensharing/build.gradle
@@ -5,7 +5,7 @@ android {
buildToolsVersion "29.0.2"
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/Android/APIExample/lib-stream-encrypt/build.gradle b/Android/APIExample/lib-stream-encrypt/build.gradle
index df5ab811e..2ae9d5223 100644
--- a/Android/APIExample/lib-stream-encrypt/build.gradle
+++ b/Android/APIExample/lib-stream-encrypt/build.gradle
@@ -5,7 +5,7 @@ android {
buildToolsVersion "29.0.3"
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/Android/APIExample/lib-switch-external-video/build.gradle b/Android/APIExample/lib-switch-external-video/build.gradle
index d5db48e45..b46e70a88 100644
--- a/Android/APIExample/lib-switch-external-video/build.gradle
+++ b/Android/APIExample/lib-switch-external-video/build.gradle
@@ -6,7 +6,7 @@ android {
defaultConfig {
- minSdkVersion 19
+ minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
diff --git a/iOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard b/iOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard
index 7575139b5..5d82513ed 100644
--- a/iOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard
+++ b/iOS/APIExample/Examples/Advanced/VideoProcess/Base.lproj/VideoProcess.storyboard
@@ -1,9 +1,9 @@
-
+
-
+
@@ -72,7 +72,6 @@
-
@@ -95,25 +94,28 @@
-
+
-
+
@@ -121,14 +123,8 @@
-
-
+
@@ -137,13 +133,13 @@
-
+
@@ -152,13 +148,13 @@
-
+
@@ -166,42 +162,252 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/iOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift b/iOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift
index 6ceea24c7..7659853cf 100644
--- a/iOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift
+++ b/iOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift
@@ -12,9 +12,7 @@ import AGEVideoLayout
class VideoProcessEntry : UIViewController
{
- @IBOutlet weak var joinButton: AGButton!
@IBOutlet weak var channelTextField: AGTextField!
- let identifier = "VideoProcess"
override func viewDidLoad() {
super.viewDidLoad()
@@ -22,11 +20,10 @@ class VideoProcessEntry : UIViewController
@IBAction func doJoinPressed(sender: AGButton) {
guard let channelName = channelTextField.text else {return}
- //resign channel text field
channelTextField.resignFirstResponder()
+ let identifier = "VideoProcess"
let storyBoard: UIStoryboard = UIStoryboard(name: identifier, bundle: nil)
- // create new view controller every time to ensure we get a clean vc
guard let newViewController = storyBoard.instantiateViewController(withIdentifier: identifier) as? BaseViewController else {return}
newViewController.title = channelName
newViewController.configs = ["channelName":channelName]
@@ -34,37 +31,35 @@ class VideoProcessEntry : UIViewController
}
}
+
class VideoProcessMain : BaseViewController
{
- var localVideo = Bundle.loadVideoView(type: .local, audioOnly: false)
- var remoteVideo = Bundle.loadVideoView(type: .remote, audioOnly: false)
-
@IBOutlet weak var container: AGEVideoContainer!
- var agoraKit: AgoraRtcEngineKit!
-
- @IBOutlet weak var beauty: UISwitch!
- @IBOutlet weak var lightness: UISwitch!
- @IBOutlet weak var colorful: UISwitch!
- @IBOutlet weak var denoiser: UISwitch!
-
+ @IBOutlet weak var beautySwitch: UISwitch!
+ @IBOutlet weak var colorEnhanceSwitch: UISwitch!
+ @IBOutlet weak var virtualBgSwitch: UISwitch!
+ @IBOutlet weak var virtualBgSegment: UISegmentedControl!
@IBOutlet weak var lightenSlider: UISlider!
@IBOutlet weak var rednessSlider: UISlider!
@IBOutlet weak var sharpnessSlider: UISlider!
@IBOutlet weak var smoothSlider: UISlider!
+ @IBOutlet weak var strengthSlider: UISlider!
+ @IBOutlet weak var skinProtectSlider: UISlider!
+
+
+ var agoraKit: AgoraRtcEngineKit!
+ var localVideo = Bundle.loadVideoView(type: .local, audioOnly: false)
+ var remoteVideo = Bundle.loadVideoView(type: .remote, audioOnly: false)
// indicate if current instance has joined channel
var isJoined: Bool = false
var beautifyOption = AgoraBeautyOptions()
- var skinProtect = 1.0
- var strength = 0.5
-
+ var colorEnhanceOption = AgoraColorEnhanceOptions()
+
override func viewDidLoad(){
super.viewDidLoad()
- // layout render view
- localVideo.setPlaceholder(text: "Local Host".localized)
- remoteVideo.setPlaceholder(text: "Remote Host".localized)
- container.layoutStream(views: [localVideo, remoteVideo])
-
+ setupUI()
+
// set up agora instance when view loaded
let config = AgoraRtcEngineConfig()
config.appId = KeyCenter.AppId
@@ -74,7 +69,7 @@ class VideoProcessMain : BaseViewController
let logConfig = AgoraLogConfig()
logConfig.level = .info
config.logConfig = logConfig
-
+
agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
// get channel name from configs
@@ -82,7 +77,7 @@ class VideoProcessMain : BaseViewController
let resolution = GlobalSettings.shared.getSetting(key: "resolution")?.selectedOption().value as? CGSize,
let fps = GlobalSettings.shared.getSetting(key: "fps")?.selectedOption().value as? AgoraVideoFrameRate,
let orientation = GlobalSettings.shared.getSetting(key: "orientation")?.selectedOption().value as? AgoraVideoOutputOrientationMode else {return}
-
+
// make myself a broadcaster
agoraKit.setChannelProfile(.liveBroadcasting)
agoraKit.setClientRole(.broadcaster)
@@ -90,10 +85,10 @@ class VideoProcessMain : BaseViewController
// enable video module and set up video encoding configs
agoraKit.enableVideo()
agoraKit.setVideoEncoderConfiguration(AgoraVideoEncoderConfiguration(size: resolution,
- frameRate: fps,
- bitrate: AgoraVideoBitrateStandard,
- orientationMode: orientation))
-
+ frameRate: fps,
+ bitrate: AgoraVideoBitrateStandard,
+ orientationMode: orientation))
+
// set up local video to render your local camera preview
let videoCanvas = AgoraRtcVideoCanvas()
videoCanvas.uid = 0
@@ -133,24 +128,97 @@ class VideoProcessMain : BaseViewController
}
}
+ // MARK: - UI
+
+ func setupUI() {
+ // layout render view
+ localVideo.setPlaceholder(text: "Local Host".localized)
+ remoteVideo.setPlaceholder(text: "Remote Host".localized)
+ container.layoutStream(views: [localVideo, remoteVideo])
+
+ lightenSlider.value = beautifyOption.lighteningLevel
+ rednessSlider.value = beautifyOption.rednessLevel
+ sharpnessSlider.value = beautifyOption.sharpnessLevel
+ smoothSlider.value = beautifyOption.smoothnessLevel
+ strengthSlider.value = colorEnhanceOption.strengthLevel
+ skinProtectSlider.value = colorEnhanceOption.skinProtectLevel
+ }
+
+
+ @IBAction func onChangeBeauty(_ sender:UISwitch){
+ agoraKit.setBeautyEffectOptions(sender.isOn, options: beautifyOption)
+ }
+
@IBAction func onLightenSlider(_ sender:UISlider){
beautifyOption.lighteningLevel = sender.value
- agoraKit.setBeautyEffectOptions(beauty.isOn, options: beautifyOption)
+ agoraKit.setBeautyEffectOptions(beautySwitch.isOn, options: beautifyOption)
}
+
@IBAction func onRednessSlider(_ sender:UISlider){
beautifyOption.rednessLevel = sender.value
- agoraKit.setBeautyEffectOptions(beauty.isOn, options: beautifyOption)
+ agoraKit.setBeautyEffectOptions(beautySwitch.isOn, options: beautifyOption)
}
+
@IBAction func onSharpnessSlider(_ sender:UISlider){
beautifyOption.sharpnessLevel = sender.value
- agoraKit.setBeautyEffectOptions(beauty.isOn, options: beautifyOption)
+ agoraKit.setBeautyEffectOptions(beautySwitch.isOn, options: beautifyOption)
}
+
@IBAction func onSmoothSlider(_ sender:UISlider){
beautifyOption.smoothnessLevel = sender.value
- agoraKit.setBeautyEffectOptions(beauty.isOn, options: beautifyOption)
+ agoraKit.setBeautyEffectOptions(beautySwitch.isOn, options: beautifyOption)
}
- @IBAction func onChangeBeauty(_ sender:UISwitch){
- agoraKit.setBeautyEffectOptions(sender.isOn, options: beautifyOption)
+
+ @IBAction func onChangeLowLightEnhance(_ sender: UISwitch) {
+ agoraKit.setLowlightEnhanceOptions(sender.isOn, options: nil)
+ }
+
+ @IBAction func onChangeVideoDenoise(_ sender: UISwitch) {
+ agoraKit.setVideoDenoiserOptions(sender.isOn, options: nil)
+ }
+
+ @IBAction func onChangeColorEnhance(_ sender: UISwitch) {
+ agoraKit.setColorEnhanceOptions(sender.isOn, options: colorEnhanceOption)
+ }
+
+ @IBAction func onStrengthSlider(_ sender:UISlider){
+ colorEnhanceOption.strengthLevel = sender.value;
+ agoraKit.setColorEnhanceOptions(colorEnhanceSwitch.isOn, options: colorEnhanceOption)
+ }
+
+ @IBAction func onSkinProtectSlider(_ sender:UISlider){
+ colorEnhanceOption.skinProtectLevel = sender.value;
+ agoraKit.setColorEnhanceOptions(colorEnhanceSwitch.isOn, options: colorEnhanceOption)
+ }
+
+ @IBAction func onChangeVirtualBgSwtich(_ sender: UISwitch) {
+ changeVirtualBackground()
+ }
+
+ @IBAction func onChangeVirtualBgSegment(_ sender: UISegmentedControl) {
+ changeVirtualBackground()
+ }
+
+ func changeVirtualBackground() {
+ let source = AgoraVirtualBackgroundSource()
+ switch virtualBgSegment.selectedSegmentIndex {
+ case 0:
+ let imgPath = Bundle.main.path(forResource: "agora-logo", ofType: "png")
+ source.backgroundSourceType = .img
+ source.source = imgPath
+ break
+ case 1:
+ source.backgroundSourceType = .color
+ source.color = 0xFFFFFF
+ break
+ case 2:
+ source.backgroundSourceType = .blur
+ source.blur_degree = .high;
+ break
+ default:
+ break
+ }
+ agoraKit.enableVirtualBackground(virtualBgSwitch.isOn, backData: source)
}
}
diff --git a/iOS/APIExample/Examples/Advanced/VideoProcess/zh-Hans.lproj/VideoProcess.strings b/iOS/APIExample/Examples/Advanced/VideoProcess/zh-Hans.lproj/VideoProcess.strings
index fc209274c..76621ad69 100644
--- a/iOS/APIExample/Examples/Advanced/VideoProcess/zh-Hans.lproj/VideoProcess.strings
+++ b/iOS/APIExample/Examples/Advanced/VideoProcess/zh-Hans.lproj/VideoProcess.strings
@@ -1,51 +1,47 @@
-
-/* Class = "UISwitch"; title = "Face Beautify"; ObjectID = "0lt-yn-0yl"; */
-"0lt-yn-0yl.title" = "缇庨";
+/* Class = "UITextField"; placeholder = "Enter channel name"; ObjectID = "moa-hL-hhA"; */
+"moa-hL-hhA.placeholder" = "璇疯緭鍏ラ閬撳悕";
/* Class = "UIButton"; normalTitle = "Join"; ObjectID = "1Vr-cE-fQI"; */
"1Vr-cE-fQI.normalTitle" = "鍔犲叆";
-/* Class = "UILabel"; text = "Lightening Enhance"; ObjectID = "2y0-8E-3Er"; */
-"2y0-8E-3Er.text" = "鏆楀厜澧炲己";
+/* Class = "UILabel"; text = "Face Beautify"; ObjectID = "Ty6-YP-tus"; */
+"Ty6-YP-tus.text" = "缇庨";
/* Class = "UILabel"; text = "Smoothness"; ObjectID = "3Cr-C9-PWm"; */
"3Cr-C9-PWm.text" = "骞虫粦";
-/* Class = "UISwitch"; title = "Face Beautify"; ObjectID = "3jT-PF-fry"; */
-"3jT-PF-fry.title" = "缇庨";
-
/* Class = "UILabel"; text = "Lightening"; ObjectID = "6Yy-cm-VP3"; */
"6Yy-cm-VP3.text" = "缇庣櫧";
-/* Class = "UIViewController"; title = "Simple Filter"; ObjectID = "8Zn-pj-gkm"; */
-"8Zn-pj-gkm.title" = "瑙嗛澧炲己";
+/* Class = "UILabel"; text = "Redness"; ObjectID = "c7I-oU-1Ty"; */
+"c7I-oU-1Ty.text" = "绾㈡鼎";
-/* Class = "UISwitch"; title = "Face Beautify"; ObjectID = "HJK-u9-Pbi"; */
-"HJK-u9-Pbi.title" = "缇庨";
+/* Class = "UILabel"; text = "Sharpness"; ObjectID = "nxu-z3-DfB"; */
+"nxu-z3-DfB.text" = "閿愬埄";
-/* Class = "UILabel"; text = "Video Denoiser"; ObjectID = "IK4-hW-gbx"; */
-"IK4-hW-gbx.text" = "瑙嗛闄嶅櫔";
+/* Class = "UILabel"; text = "Low light Enhancement"; ObjectID = "tw2-gf-2I6"; */
+"tw2-gf-2I6.text" = "鏆楀厜澧炲己";
-/* Class = "UILabel"; text = "Colorful Enhance"; ObjectID = "Ijy-ys-cZf"; */
-"Ijy-ys-cZf.text" = "鑹插僵澧炲己";
+/* Class = "UILabel"; text = "Video Denoiser"; ObjectID = "147-rT-JTP"; */
+"147-rT-JTP.text" = "瑙嗛闄嶅櫔";
-/* Class = "UILabel"; text = "Face Beautify"; ObjectID = "Ty6-YP-tus"; */
-"Ty6-YP-tus.text" = "缇庨";
+/* Class = "UILabel"; text = "Color Enhancement"; ObjectID = "uW9-fr-9eC"; */
+"uW9-fr-9eC.text" = "鑹插僵澧炲己";
-/* Class = "UISwitch"; title = "Face Beautify"; ObjectID = "YBf-iq-ZSD"; */
-"YBf-iq-ZSD.title" = "缇庨";
+/* Class = "UILabel"; text = "Strength"; ObjectID = "Tim-Kh-axW"; */
+"Tim-Kh-axW.text" = "寮哄害";
-/* Class = "UILabel"; text = "Redness"; ObjectID = "c7I-oU-1Ty"; */
-"c7I-oU-1Ty.text" = "绾㈡鼎";
+/* Class = "UILabel"; text = "Skin Protect"; ObjectID = "OAR-9q-CrU"; */
+"OAR-9q-CrU.text" = "鑲よ壊淇濇姢";
-/* Class = "UITextField"; placeholder = "Enter channel name"; ObjectID = "moa-hL-hhA"; */
-"moa-hL-hhA.placeholder" = "璇疯緭鍏ラ閬撳悕";
+/* Class = "UILabel"; text = "Virtual Background"; ObjectID = "0N7-qv-24q"; */
+"0N7-qv-24q.text" = "铏氭嫙鑳屾櫙";
-/* Class = "UILabel"; text = "Sharpness"; ObjectID = "nxu-z3-DfB"; */
-"nxu-z3-DfB.text" = "閿愬埄";
+/* Class = "UISegmentedControl"; 64G-UU-8yO.segmentTitles[0] = "Image"; ObjectID = "64G-UU-8yO"; */
+"64G-UU-8yO.segmentTitles[0]" = "鍥剧墖";
-/* Class = "UILabel"; text = "Strength"; ObjectID = "OIO-FL-y7u"; */
-"OIO-FL-y7u.text" = "寮哄害";
+/* Class = "UISegmentedControl"; 64G-UU-8yO.segmentTitles[1] = "Color"; ObjectID = "64G-UU-8yO"; */
+"64G-UU-8yO.segmentTitles[1]" = "棰滆壊";
-/* Class = "UILabel"; text = "Skin Protect"; ObjectID = "C1K-xQ-TKU"; */
-"C1K-xQ-TKU.text" = "鑲よ壊淇濇姢";
+/* Class = "UISegmentedControl"; 64G-UU-8yO.segmentTitles[2] = "Blur"; ObjectID = "64G-UU-8yO"; */
+"64G-UU-8yO.segmentTitles[2]" = "姣涚幓鐠";
diff --git a/iOS/Podfile b/iOS/Podfile
index 5e4de0606..ff1960c95 100644
--- a/iOS/Podfile
+++ b/iOS/Podfile
@@ -5,7 +5,7 @@ target 'APIExample' do
use_frameworks!
pod 'Floaty', '~> 4.2.0'
- pod 'AGEVideoLayout', '~> 1.0.2'
+ pod 'AGEVideoLayout', '~> 1.0.4'
pod 'AgoraRtcEngine_iOS', '3.6.0.1'
pod 'AgoraMediaPlayer_iOS', '1.2.2'
end
diff --git a/macOS/APIExample.xcodeproj/project.pbxproj b/macOS/APIExample.xcodeproj/project.pbxproj
index 691d22a03..04fc8faf0 100644
--- a/macOS/APIExample.xcodeproj/project.pbxproj
+++ b/macOS/APIExample.xcodeproj/project.pbxproj
@@ -87,6 +87,8 @@
57AF397B259B31AA00601E02 /* RawAudioData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57AF397A259B31AA00601E02 /* RawAudioData.swift */; };
57AF3981259B329B00601E02 /* RawAudioData.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 57AF3980259B329B00601E02 /* RawAudioData.storyboard */; };
596A9F79AF0CD8DC1CA93253 /* Pods_APIExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F65EF2B97B89DE4581B426B /* Pods_APIExample.framework */; };
+ 67C3646427980E600080DB3A /* VideoProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67C3646327980E600080DB3A /* VideoProcess.swift */; };
+ 67C3646A27993A580080DB3A /* VideoProcess.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67C3646927993A580080DB3A /* VideoProcess.storyboard */; };
8B6F4EAD276ECC370097E67E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8B6F4EAF276ECC370097E67E /* Localizable.strings */; };
8B733B8C267B1C0B00CC3DE3 /* bg.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 8B733B8B267B1C0B00CC3DE3 /* bg.jpg */; };
EBDD0209B272C276B21B6270 /* Pods_APIExample_APIExampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC2BAB0AC82140B7CEEA31DA /* Pods_APIExample_APIExampleUITests.framework */; };
@@ -227,6 +229,8 @@
57A635F32593544600EDC2F7 /* effectA.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = effectA.wav; sourceTree = ""; };
57AF397A259B31AA00601E02 /* RawAudioData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawAudioData.swift; sourceTree = ""; };
57AF3980259B329B00601E02 /* RawAudioData.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = RawAudioData.storyboard; sourceTree = ""; };
+ 67C3646327980E600080DB3A /* VideoProcess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoProcess.swift; sourceTree = ""; };
+ 67C3646927993A580080DB3A /* VideoProcess.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = VideoProcess.storyboard; sourceTree = ""; };
6F65EF2B97B89DE4581B426B /* Pods_APIExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_APIExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
84C863718A380DFD36ABF19F /* Pods-APIExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-APIExample.debug.xcconfig"; path = "Target Support Files/Pods-APIExample/Pods-APIExample.debug.xcconfig"; sourceTree = ""; };
8B6F4EAE276ECC370097E67E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; };
@@ -475,6 +479,7 @@
036D3AA524FB797700B1D8DC /* Advanced */ = {
isa = PBXGroup;
children = (
+ 67C3646227980E1F0080DB3A /* VideoProcess */,
57AF3979259B30BB00601E02 /* RawAudioData */,
576459FD259B1C22007B1E30 /* CreateDataStream */,
033A9F95252EA86A00BC26E1 /* CustomAudioRender */,
@@ -639,6 +644,15 @@
path = RawAudioData;
sourceTree = "";
};
+ 67C3646227980E1F0080DB3A /* VideoProcess */ = {
+ isa = PBXGroup;
+ children = (
+ 67C3646327980E600080DB3A /* VideoProcess.swift */,
+ 67C3646927993A580080DB3A /* VideoProcess.storyboard */,
+ );
+ path = VideoProcess;
+ sourceTree = "";
+ };
72510F6AF209B24C1F66A819 /* Pods */ = {
isa = PBXGroup;
children = (
@@ -790,6 +804,7 @@
033A9FBD252EB02600BC26E1 /* CustomAudioRender.storyboard in Resources */,
034C62A025297ABB00296ECF /* audioeffect.mp3 in Resources */,
03896D3424F8A011008593CD /* Assets.xcassets in Resources */,
+ 67C3646A27993A580080DB3A /* VideoProcess.storyboard in Resources */,
03896D3724F8A011008593CD /* Main.storyboard in Resources */,
033A9FE0252EB58600BC26E1 /* CustomVideoSourceMediaIO.storyboard in Resources */,
8B733B8C267B1C0B00CC3DE3 /* bg.jpg in Resources */,
@@ -944,6 +959,7 @@
034C629C25295F2800296ECF /* AudioMixing.swift in Sources */,
03267E222500C265004A91A6 /* AgoraMediaDataPlugin.mm in Sources */,
036D3AA224FAA00A00B1D8DC /* Configs.swift in Sources */,
+ 67C3646427980E600080DB3A /* VideoProcess.swift in Sources */,
03267E1C24FF3AF4004A91A6 /* AgoraCameraSourcePush.swift in Sources */,
034C626C25259FC200296ECF /* JoinChannelVideo.swift in Sources */,
033A9FA5252EA86A00BC26E1 /* RawMediaData.swift in Sources */,
diff --git a/macOS/APIExample/Examples/Advanced/AudioMixing/AudioMixing.swift b/macOS/APIExample/Examples/Advanced/AudioMixing/AudioMixing.swift
index b1551d603..9c0630aab 100644
--- a/macOS/APIExample/Examples/Advanced/AudioMixing/AudioMixing.swift
+++ b/macOS/APIExample/Examples/Advanced/AudioMixing/AudioMixing.swift
@@ -91,7 +91,7 @@ class AudioMixing: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift b/macOS/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift
index 5479f782c..cdc53e4e0 100644
--- a/macOS/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift
+++ b/macOS/APIExample/Examples/Advanced/CustomAudioRender/CustomAudioRender.swift
@@ -23,7 +23,7 @@ class CustomAudioRender: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics: [AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift
index 02c4cdf8a..5e094a599 100644
--- a/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift
+++ b/macOS/APIExample/Examples/Advanced/CustomAudioSource/CustomAudioSource.swift
@@ -22,7 +22,7 @@ class CustomAudioSource: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics: [AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Advanced/PrecallTest/PrecallTest.swift b/macOS/APIExample/Examples/Advanced/PrecallTest/PrecallTest.swift
index 1dd491038..4ed062e88 100644
--- a/macOS/APIExample/Examples/Advanced/PrecallTest/PrecallTest.swift
+++ b/macOS/APIExample/Examples/Advanced/PrecallTest/PrecallTest.swift
@@ -37,7 +37,7 @@ class PrecallTest: BaseViewController {
@IBOutlet weak var echoValidatePopover: NSView!
var cameras:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.cameraPicker.addItems(withTitles: self.cameras.map({ (device: AgoraRtcDeviceInfo) -> String in
return (device.deviceName ?? "")
}))
@@ -46,7 +46,7 @@ class PrecallTest: BaseViewController {
}
var mics:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.micPicker.addItems(withTitles: self.mics.map({ (device: AgoraRtcDeviceInfo) -> String in
return (device.deviceName ?? "")
}))
@@ -55,7 +55,7 @@ class PrecallTest: BaseViewController {
}
var speakers:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.speakerPicker.addItems(withTitles: self.speakers.map({ (device: AgoraRtcDeviceInfo) -> String in
return (device.deviceName ?? "")
}))
@@ -303,6 +303,7 @@ extension PrecallTest: AgoraRtcEngineDelegate {
/// @params totalVolume Total volume after audio mixing. The value range is [0,255].
func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) {
for speaker in speakers {
+ print("reportAudioVolumeIndicationOfSpeakers:\(speaker.uid), \(speaker.volume)")
if(speaker.uid == 0) {
micTestingVolumeIndicator.doubleValue = Double(speaker.volume)
}
diff --git a/macOS/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift b/macOS/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift
index f72bb4016..8e9754189 100644
--- a/macOS/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift
+++ b/macOS/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift
@@ -23,7 +23,7 @@ class RawAudioData: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics: [AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.storyboard b/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.storyboard
new file mode 100644
index 000000000..0bb772625
--- /dev/null
+++ b/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.storyboard
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift b/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift
new file mode 100644
index 000000000..48b894707
--- /dev/null
+++ b/macOS/APIExample/Examples/Advanced/VideoProcess/VideoProcess.swift
@@ -0,0 +1,444 @@
+//
+// VideoProcess.swift
+// APIExample
+//
+// Created by Arlin on 2022/1/19.
+// Copyright 漏 2022 Agora Corp. All rights reserved.
+//
+
+import Cocoa
+import AgoraRtcKit
+import AGEVideoLayout
+
+class VideoProcess: BaseViewController {
+
+ @IBOutlet weak var Container: AGEVideoContainer!
+ @IBOutlet weak var selectResolutionPicker: Picker!
+ @IBOutlet weak var selectFpsPicker: Picker!
+ @IBOutlet weak var selectLayoutPicker: Picker!
+ @IBOutlet weak var virtualBackgroundSwitch: NSSwitch!
+ @IBOutlet weak var selectVirtualBackgroundPicker: Picker!
+ @IBOutlet weak var channelField: Input!
+ @IBOutlet weak var joinChannelButton: NSButton!
+ @IBOutlet weak var colorEnhanceSwitch: NSSwitch!
+
+ @IBOutlet weak var lowlightEnhanceLabel: NSTextField!
+ @IBOutlet weak var videoDenoiseLabel: NSTextField!
+ @IBOutlet weak var colorEnhanceLabel: NSTextField!
+ @IBOutlet weak var strenghtLabel: NSTextField!
+ @IBOutlet weak var skinProtectLabel: NSTextField!
+
+ var videos: [VideoView] = []
+ let layouts = [Layout("1v1", 2), Layout("1v3", 4), Layout("1v8", 9), Layout("1v15", 16)]
+ let backgroundTypes = AgoraVirtualBackgroundSourceType.allValues()
+ var agoraKit: AgoraRtcEngineKit!
+ var colorEnhanceOptions = AgoraColorEnhanceOptions()
+
+ // indicate if current instance has joined channel
+ var isJoined: Bool = false {
+ didSet {
+ channelField.isEnabled = !isJoined
+ selectLayoutPicker.isEnabled = !isJoined
+ joinChannelButton.title = isJoined ? "Leave Channel".localized : "Join Channel".localized
+ }
+ }
+
+ // MARK: - LifeCycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.setupUI()
+ self.setupAgoraKit()
+ }
+
+ func setupAgoraKit() {
+ let config = AgoraRtcEngineConfig()
+ config.appId = KeyCenter.AppId
+ config.areaCode = GlobalSettings.shared.area.rawValue
+ agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
+
+ agoraKit.setChannelProfile(.liveBroadcasting)
+ agoraKit.setClientRole(.broadcaster)
+
+ agoraKit.enableVideo()
+ }
+
+ override func viewWillBeRemovedFromSplitView() {
+ if isJoined {
+ agoraKit.disableVideo()
+ agoraKit.leaveChannel { (stats:AgoraChannelStats) in
+ LogUtils.log(message: "Left channel", level: .info)
+ }
+ }
+ AgoraRtcEngineKit.destroy()
+ }
+
+ // MARK: - UI
+ func setupUI() {
+ channelField.label.stringValue = "Channel".localized
+ channelField.field.placeholderString = "Channel Name".localized
+ joinChannelButton.title = isJoined ? "Leave Channel".localized : "Join Channel".localized
+ lowlightEnhanceLabel.stringValue = "Low light Enhancement".localized
+ videoDenoiseLabel.stringValue = "Video Denoise".localized
+ colorEnhanceLabel.stringValue = "Color Enhancement".localized
+ strenghtLabel.stringValue = "Strength".localized
+ skinProtectLabel.stringValue = "Skin Protect".localized
+
+ initSelectResolutionPicker()
+ initSelectFpsPicker()
+ initSelectLayoutPicker()
+ initSelectBackgroundPicker()
+ }
+
+ @IBAction func onJoinButtonPressed(_ sender: NSButton) {
+ if !isJoined {
+ let channel = channelField.stringValue
+ guard !channel.isEmpty,
+ let resolution = selectedResolution(),
+ let fps = selectedFps() else {
+ return
+ }
+
+ agoraKit.setVideoEncoderConfiguration(
+ AgoraVideoEncoderConfiguration(
+ size: resolution.size(),
+ frameRate: AgoraVideoFrameRate(rawValue: fps) ?? .fps15,
+ bitrate: AgoraVideoBitrateStandard,
+ orientationMode: .adaptative
+ )
+ )
+
+ // set up local video to render your local camera preview
+ let localVideo = videos[0]
+ let videoCanvas = AgoraRtcVideoCanvas()
+ videoCanvas.uid = 0
+ // the view to be binded
+ videoCanvas.view = localVideo.videocanvas
+ videoCanvas.renderMode = .hidden
+ agoraKit.setupLocalVideo(videoCanvas)
+
+ setVirtualBackground()
+
+ // start joining channel
+ // 1. Users can only see each other after they join the
+ // same channel successfully using the same app id.
+ // 2. If app certificate is turned on at dashboard, token is needed
+ // when joining channel. The channel name and uid used to calculate
+ // the token has to match the ones used for channel join
+ let option = AgoraRtcChannelMediaOptions()
+ let result = agoraKit.joinChannel(byToken: KeyCenter.Token, channelId: channel, info: nil, uid: 0, options: option)
+ if result != 0 {
+ // Usually happens with invalid parameters
+ // Error code description can be found at:
+ // en: https://docs.agora.io/en/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
+ // cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
+ self.showAlert(title: "Error", message: "joinChannel call failed: \(result), please check your params")
+ }
+ } else {
+ agoraKit.leaveChannel { (stats:AgoraChannelStats) in
+ LogUtils.log(message: "Left channel", level: .info)
+ self.videos[0].uid = nil
+ self.isJoined = false
+ self.videos.forEach {
+ $0.uid = nil
+ $0.statsLabel.stringValue = ""
+ }
+ }
+ }
+ }
+
+ @IBAction func onLowLightEnhanceSwitchChange(_ sender: NSSwitch) {
+ agoraKit.setLowlightEnhanceOptions(sender.state.rawValue != 0, options: nil)
+ }
+
+ @IBAction func onVideoDenoiseSwitchChange(_ sender: NSSwitch) {
+ agoraKit.setVideoDenoiserOptions(sender.state.rawValue != 0, options: nil)
+ }
+
+ @IBAction func onColorEnhanceSwitchChange(_ sender: NSSwitch) {
+ agoraKit.setColorEnhanceOptions(colorEnhanceSwitch.state.rawValue != 0, options: colorEnhanceOptions)
+ }
+
+ @IBAction func onStrengthSliderChange(_ sender: NSSlider) {
+ colorEnhanceOptions.strengthLevel = sender.floatValue
+ agoraKit.setColorEnhanceOptions(colorEnhanceSwitch.state.rawValue != 0, options: colorEnhanceOptions)
+ }
+
+ @IBAction func onSkinProtectSliderChange(_ sender: NSSlider) {
+ colorEnhanceOptions.skinProtectLevel = sender.floatValue
+ agoraKit.setColorEnhanceOptions(colorEnhanceSwitch.state.rawValue != 0, options: colorEnhanceOptions)
+ }
+
+ @IBAction func onVirtualBackgroundSwitchChange(_ sender: NSSwitch) {
+ setVirtualBackground()
+ }
+
+ func setVirtualBackground(){
+ let backgroundSource = AgoraVirtualBackgroundSource()
+ backgroundSource.backgroundSourceType = selectedBackgroundType() ?? .img
+ switch backgroundSource.backgroundSourceType {
+ case .color:
+ backgroundSource.color = 0xFFFFFF
+ break
+ case .img:
+ if let resourcePath = Bundle.main.resourcePath {
+ let imgPath = resourcePath + "/" + "bg.jpg"
+ backgroundSource.source = imgPath
+ }
+ break
+ case .blur:
+ backgroundSource.blur_degree = .high
+ break
+ default:
+ break
+ }
+ agoraKit.enableVirtualBackground(virtualBackgroundSwitch.state.rawValue != 0, backData: backgroundSource)
+ }
+
+ func initSelectBackgroundPicker() {
+ selectVirtualBackgroundPicker.label.stringValue = "Virtual Background".localized
+ selectVirtualBackgroundPicker.picker.addItems(withTitles: backgroundTypes.map { $0.description() })
+
+ selectVirtualBackgroundPicker.onSelectChanged {
+ guard self.selectedBackgroundType() != nil else { return }
+ self.setVirtualBackground()
+ }
+ }
+
+ func selectedBackgroundType() ->AgoraVirtualBackgroundSourceType? {
+ let index = selectVirtualBackgroundPicker.indexOfSelectedItem
+ if index >= 0 && index < backgroundTypes.count {
+ return backgroundTypes[index]
+ } else {
+ return nil
+ }
+ }
+
+ // MARK: Vedio Setting
+ func initSelectResolutionPicker() {
+ selectResolutionPicker.label.stringValue = "Resolution".localized
+ selectResolutionPicker.picker.addItems(withTitles: Configs.Resolutions.map { $0.name() })
+ selectResolutionPicker.picker.selectItem(at: GlobalSettings.shared.resolutionSetting.selectedOption().value)
+
+ selectResolutionPicker.onSelectChanged {
+ if !self.isJoined {
+ return
+ }
+
+ guard let resolution = self.selectedResolution(),
+ let fps = self.selectedFps() else {
+ return
+ }
+ self.agoraKit.setVideoEncoderConfiguration(
+ AgoraVideoEncoderConfiguration(
+ size: resolution.size(),
+ frameRate: AgoraVideoFrameRate(rawValue: fps) ?? .fps15,
+ bitrate: AgoraVideoBitrateStandard,
+ orientationMode: .adaptative
+ )
+ )
+ }
+ }
+
+ func selectedResolution() -> Resolution? {
+ let index = self.selectResolutionPicker.indexOfSelectedItem
+ if index >= 0 && index < Configs.Resolutions.count {
+ return Configs.Resolutions[index]
+ } else {
+ return nil
+ }
+ }
+
+ func initSelectFpsPicker() {
+ selectFpsPicker.label.stringValue = "Frame Rate".localized
+ selectFpsPicker.picker.addItems(withTitles: Configs.Fps.map { "\($0)fps" })
+ selectFpsPicker.picker.selectItem(at: GlobalSettings.shared.fpsSetting.selectedOption().value)
+
+ selectFpsPicker.onSelectChanged {
+ if !self.isJoined {
+ return
+ }
+
+ guard let resolution = self.selectedResolution(),
+ let fps = self.selectedFps() else {
+ return
+ }
+ self.agoraKit.setVideoEncoderConfiguration(
+ AgoraVideoEncoderConfiguration(
+ size: resolution.size(),
+ frameRate: AgoraVideoFrameRate(rawValue: fps) ?? .fps15,
+ bitrate: AgoraVideoBitrateStandard,
+ orientationMode: .adaptative
+ )
+ )
+ }
+ }
+
+ func selectedFps() -> Int? {
+ let index = self.selectFpsPicker.indexOfSelectedItem
+ if index >= 0 && index < Configs.Fps.count {
+ return Configs.Fps[index]
+ } else {
+ return nil
+ }
+ }
+
+ func initSelectLayoutPicker() {
+ layoutVideos(2)
+ selectLayoutPicker.label.stringValue = "Layout".localized
+ selectLayoutPicker.picker.addItems(withTitles: layouts.map { $0.label })
+ selectLayoutPicker.onSelectChanged {
+ if self.isJoined {
+ return
+ }
+ guard let layout = self.selectedLayout() else { return }
+ self.layoutVideos(layout.value)
+ }
+ }
+
+ func selectedLayout() ->Layout? {
+ let index = self.selectLayoutPicker.indexOfSelectedItem
+ if index >= 0 && index < layouts.count {
+ return layouts[index]
+ } else {
+ return nil
+ }
+ }
+
+ func layoutVideos(_ count: Int) {
+ videos = []
+ for i in 0...count - 1 {
+ let view = VideoView.createFromNib()!
+ if(i == 0) {
+ view.placeholder.stringValue = "Local"
+ view.type = .local
+ view.statsInfo = StatisticsInfo(type: .local(StatisticsInfo.LocalInfo()))
+ } else {
+ view.placeholder.stringValue = "Remote \(i)"
+ view.type = .remote
+ view.statsInfo = StatisticsInfo(type: .remote(StatisticsInfo.RemoteInfo()))
+ }
+ videos.append(view)
+ }
+ // layout render view
+ Container.layoutStream(views: videos)
+ }
+}
+
+/// agora rtc engine delegate events
+extension VideoProcess: AgoraRtcEngineDelegate {
+ /// callback when warning occured for agora sdk, warning can usually be ignored, still it's nice to check out
+ /// what is happening
+ /// Warning code description can be found at:
+ /// en: https://docs.agora.io/en/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html
+ /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraWarningCode.html
+ /// @param warningCode warning code of the problem
+ func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurWarning warningCode: AgoraWarningCode) {
+ LogUtils.log(message: "warning: \(warningCode.rawValue)", level: .warning)
+ }
+
+ /// callback when error occured for agora sdk, you are recommended to display the error descriptions on demand
+ /// to let user know something wrong is happening
+ /// Error code description can be found at:
+ /// en: https://docs.agora.io/en/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
+ /// cn: https://docs.agora.io/cn/Voice/API%20Reference/oc/Constants/AgoraErrorCode.html
+ /// @param errorCode error code of the problem
+ func rtcEngine(_ engine: AgoraRtcEngineKit, didOccurError errorCode: AgoraErrorCode) {
+ LogUtils.log(message: "error: \(errorCode)", level: .error)
+ self.showAlert(title: "Error", message: "Error \(errorCode.rawValue) occur")
+ }
+
+ /// callback when the local user joins a specified channel.
+ /// @param channel
+ /// @param uid uid of local user
+ /// @param elapsed time elapse since current sdk instance join the channel in ms
+ func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinChannel channel: String, withUid uid: UInt, elapsed: Int) {
+ isJoined = true
+ let localVideo = videos[0]
+ localVideo.uid = uid
+ LogUtils.log(message: "Join \(channel) with uid \(uid) elapsed \(elapsed)ms", level: .info)
+ }
+
+ /// callback when a remote user is joinning the channel, note audience in live broadcast mode will NOT trigger this event
+ /// @param uid uid of remote joined user
+ /// @param elapsed time elapse since current sdk instance join the channel in ms
+ func rtcEngine(_ engine: AgoraRtcEngineKit, didJoinedOfUid uid: UInt, elapsed: Int) {
+ LogUtils.log(message: "remote user join: \(uid) \(elapsed)ms", level: .info)
+
+ // find a VideoView w/o uid assigned
+ if let remoteVideo = videos.first(where: { $0.uid == nil }) {
+ let videoCanvas = AgoraRtcVideoCanvas()
+ videoCanvas.uid = uid
+ // the view to be binded
+ videoCanvas.view = remoteVideo.videocanvas
+ videoCanvas.renderMode = .hidden
+ agoraKit.setupRemoteVideo(videoCanvas)
+ remoteVideo.uid = uid
+ } else {
+ LogUtils.log(message: "no video canvas available for \(uid), cancel bind", level: .warning)
+ }
+ }
+
+ /// callback when a remote user is leaving the channel, note audience in live broadcast mode will NOT trigger this event
+ /// @param uid uid of remote joined user
+ /// @param reason reason why this user left, note this event may be triggered when the remote user
+ /// become an audience in live broadcasting profile
+ func rtcEngine(_ engine: AgoraRtcEngineKit, didOfflineOfUid uid: UInt, reason: AgoraUserOfflineReason) {
+ LogUtils.log(message: "remote user left: \(uid) reason \(reason)", level: .info)
+
+ // to unlink your view from sdk, so that your view reference will be released
+ // note the video will stay at its last frame, to completely remove it
+ // you will need to remove the EAGL sublayer from your binded view
+ if let remoteVideo = videos.first(where: { $0.uid == uid }) {
+ let videoCanvas = AgoraRtcVideoCanvas()
+ videoCanvas.uid = uid
+ // the view to be binded
+ videoCanvas.view = nil
+ videoCanvas.renderMode = .hidden
+ agoraKit.setupRemoteVideo(videoCanvas)
+ remoteVideo.uid = nil
+ } else {
+ LogUtils.log(message: "no matching video canvas for \(uid), cancel unbind", level: .warning)
+ }
+ }
+
+ /// Reports the statistics of the current call. The SDK triggers this callback once every two seconds after the user joins the channel.
+ /// @param stats stats struct
+ func rtcEngine(_ engine: AgoraRtcEngineKit, reportRtcStats stats: AgoraChannelStats) {
+ videos[0].statsInfo?.updateChannelStats(stats)
+ }
+
+ /// Reports the statistics of the uploading local video streams once every two seconds.
+ /// @param stats stats struct
+ func rtcEngine(_ engine: AgoraRtcEngineKit, localVideoStats stats: AgoraRtcLocalVideoStats) {
+ videos[0].statsInfo?.updateLocalVideoStats(stats)
+ }
+
+ /// Reports the statistics of the uploading local audio streams once every two seconds.
+ /// @param stats stats struct
+ func rtcEngine(_ engine: AgoraRtcEngineKit, localAudioStats stats: AgoraRtcLocalAudioStats) {
+ videos[0].statsInfo?.updateLocalAudioStats(stats)
+ }
+
+ /// Reports the statistics of the video stream from each remote user/host.
+ /// @param stats stats struct
+ func rtcEngine(_ engine: AgoraRtcEngineKit, remoteVideoStats stats: AgoraRtcRemoteVideoStats) {
+ videos.first(where: { $0.uid == stats.uid })?.statsInfo?.updateVideoStats(stats)
+ }
+
+ /// Reports the statistics of the audio stream from each remote user/host.
+ /// @param stats stats struct for current call statistics
+ func rtcEngine(_ engine: AgoraRtcEngineKit, remoteAudioStats stats: AgoraRtcRemoteAudioStats) {
+ videos.first(where: { $0.uid == stats.uid })?.statsInfo?.updateAudioStats(stats)
+ }
+
+ /// Reports the video background substitution success or failed.
+ /// @param enabled whether background substitution is enabled.
+ /// @param reason The reason of the background substitution callback. See [AgoraVideoBackgroundSourceStateReason](AgoraVideoBackgroundSourceStateReason).
+
+ func rtcEngine(_ engine: AgoraRtcEngineKit, virtualBackgroundSourceEnabled enabled: Bool, reason: AgoraVirtualBackgroundSourceStateReason) {
+ if reason != .vbsStateReasonSuccess {
+ LogUtils.log(message: "background substitution failed to enabled for \(reason.rawValue)", level: .warning)
+ }
+ }
+}
+
diff --git a/macOS/APIExample/Examples/Advanced/VoiceChanger/VoiceChanger.swift b/macOS/APIExample/Examples/Advanced/VoiceChanger/VoiceChanger.swift
index 30e3896aa..954b860dd 100644
--- a/macOS/APIExample/Examples/Advanced/VoiceChanger/VoiceChanger.swift
+++ b/macOS/APIExample/Examples/Advanced/VoiceChanger/VoiceChanger.swift
@@ -57,7 +57,7 @@ class VoiceChanger: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift b/macOS/APIExample/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift
index 10613f478..6f7853644 100644
--- a/macOS/APIExample/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift
+++ b/macOS/APIExample/Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift
@@ -79,7 +79,7 @@ class JoinChannelAudioMain: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics:[AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
diff --git a/macOS/APIExample/Examples/Basic/JoinChannelVideo/Base.lproj/JoinChannelVideo.storyboard b/macOS/APIExample/Examples/Basic/JoinChannelVideo/Base.lproj/JoinChannelVideo.storyboard
index 9ff1bbc31..383683219 100644
--- a/macOS/APIExample/Examples/Basic/JoinChannelVideo/Base.lproj/JoinChannelVideo.storyboard
+++ b/macOS/APIExample/Examples/Basic/JoinChannelVideo/Base.lproj/JoinChannelVideo.storyboard
@@ -1,8 +1,8 @@
-
+
-
+
@@ -52,21 +52,10 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -137,14 +126,12 @@
-
-
diff --git a/macOS/APIExample/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift b/macOS/APIExample/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift
index 3ed6c67be..5feda8e3c 100644
--- a/macOS/APIExample/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift
+++ b/macOS/APIExample/Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift
@@ -15,17 +15,14 @@ class JoinChannelVideoMain: BaseViewController {
var videos: [VideoView] = []
@IBOutlet weak var Container: AGEVideoContainer!
-
- var isVirtualBackgroundEnabled: Bool = false
- @IBOutlet weak var virtualBackgroundSwitch: NSSwitch!
-
+
/**
--- Cameras Picker ---
*/
@IBOutlet weak var selectCameraPicker: Picker!
var cameras: [AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectCameraPicker.picker.addItems(withTitles: self.cameras.map {$0.deviceName ?? "unknown"})
}
}
@@ -138,7 +135,7 @@ class JoinChannelVideoMain: BaseViewController {
@IBOutlet weak var selectMicsPicker: Picker!
var mics: [AgoraRtcDeviceInfo] = [] {
didSet {
- DispatchQueue.main.async {[unowned self] in
+ DispatchQueue.main.async {
self.selectMicsPicker.picker.addItems(withTitles: self.mics.map {$0.deviceName ?? "unknown"})
}
}
@@ -220,29 +217,7 @@ class JoinChannelVideoMain: BaseViewController {
}
}
}
-
- /**
- --- Background Picker ---
- */
- @IBOutlet weak var selectBackgroundPicker: Picker!
- private let backgroundTypes = AgoraVirtualBackgroundSourceType.allValues()
- var selectedBackgroundType: AgoraVirtualBackgroundSourceType? {
- let index = self.selectBackgroundPicker.indexOfSelectedItem
- if index >= 0 && index < backgroundTypes.count {
- return backgroundTypes[index]
- } else {
- return nil
- }
- }
- func initSelectBackgroundPicker() {
- selectBackgroundPicker.label.stringValue = "Virtual Background".localized
- selectBackgroundPicker.picker.addItems(withTitles: backgroundTypes.map { $0.description() })
- selectBackgroundPicker.onSelectChanged {
- guard self.selectedBackgroundType != nil else { return }
- self.setBackground()
- }
- }
-
+
/**
--- Channel TextField ---
*/
@@ -284,36 +259,16 @@ class JoinChannelVideoMain: BaseViewController {
config.areaCode = GlobalSettings.shared.area.rawValue
agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
agoraKit.enableVideo()
- setBackground()
initSelectCameraPicker()
initSelectResolutionPicker()
initSelectFpsPicker()
initSelectMicsPicker()
initSelectLayoutPicker()
initSelectRolePicker()
- initSelectBackgroundPicker()
initChannelField()
initJoinChannelButton()
}
-
- private func setBackground(){
- let backgroundSource = AgoraVirtualBackgroundSource()
- backgroundSource.backgroundSourceType = selectedBackgroundType ?? .img
- switch self.selectedBackgroundType {
- case .color:
- backgroundSource.color = 0x000000
- case .img:
- if let resourcePath = Bundle.main.resourcePath {
- let imgName = "bg.jpg"
- let path = resourcePath + "/" + imgName
- backgroundSource.source = path
- }
- default:
- break
- }
- agoraKit.enableVirtualBackground(isVirtualBackgroundEnabled, backData: backgroundSource)
- }
-
+
func layoutVideos(_ count: Int) {
videos = []
for i in 0...count - 1 {
@@ -333,11 +288,6 @@ class JoinChannelVideoMain: BaseViewController {
Container.layoutStream(views: videos)
}
- @IBAction func onSwitchVirtualBackground(_ sender: NSSwitch) {
- isVirtualBackgroundEnabled = (sender.state.rawValue != 0)
- setBackground()
- }
-
@IBAction func onVideoCallButtonPressed(_ sender: NSButton) {
if !isJoined {
// check configuration
diff --git a/macOS/APIExample/ViewController.swift b/macOS/APIExample/ViewController.swift
index d57fbdea3..328e2ef9d 100644
--- a/macOS/APIExample/ViewController.swift
+++ b/macOS/APIExample/ViewController.swift
@@ -39,7 +39,8 @@ class MenuController: NSViewController {
MenuItem(name: "Voice Changer".localized, identifier: "menuCell", controller: "VoiceChanger", storyboard: "VoiceChanger"),
MenuItem(name: "Create Data Stream".localized, identifier: "menuCell", controller: "CreateDataStream", storyboard: "CreateDataStream"),
MenuItem(name: "Raw Audio Data".localized, identifier: "menuCell", controller: "RawAudioData", storyboard: "RawAudioData"),
- MenuItem(name: "Precall Test".localized, identifier: "menuCell", controller: "PrecallTest", storyboard: "PrecallTest")
+ MenuItem(name: "Precall Test".localized, identifier: "menuCell", controller: "PrecallTest", storyboard: "PrecallTest"),
+ MenuItem(name: "Video Process".localized, identifier: "menuCell", controller: "Video Process", storyboard: "VideoProcess")
]
@IBOutlet weak var tableView:NSTableView!
@@ -109,7 +110,6 @@ extension MenuController: NSTableViewDataSource, NSTableViewDelegate {
func tableViewSelectionDidChange(_ notification: Notification) {
if tableView.selectedRow >= 0 && tableView.selectedRow < menus.count {
- Thread.sleep(forTimeInterval: 1)
loadSplitViewItem(item: menus[tableView.selectedRow])
}
}
diff --git a/macOS/APIExample/zh-Hans.lproj/Localizable.strings b/macOS/APIExample/zh-Hans.lproj/Localizable.strings
index b52135e82..2b1774163 100644
--- a/macOS/APIExample/zh-Hans.lproj/Localizable.strings
+++ b/macOS/APIExample/zh-Hans.lproj/Localizable.strings
@@ -158,9 +158,16 @@
"Video Source" = "瑙嗛婧愰夋嫨";
"Sending" = "鍙戦佷腑";
"None" = "鏃犺儗鏅";
+"Start Video/Audio Echo Test" = "寮濮嬮煶瑙嗛鍥炶矾娴嬭瘯";
+"Stop Video/Audio Echo Test" = "鍋滄闊宠棰戝洖璺祴璇";
+"Video Process" = "瑙嗛澧炲己";
+"Low light Enhancement" = "鏆楀厜澧炲己";
+"Video Denoise" = "瑙嗛闄嶅櫔";
+"Color Enhancement" = "鑹插僵澧炲己";
+"Strength" = "寮哄害";
+"Skin Protect" = "鑲よ壊淇濇姢";
"Colored Background" = "绾壊鑳屾櫙";
"Image Background" = "鍥剧墖鑳屾櫙";
"Virtual Background" = "铏氭嫙鑳屾櫙";
"Blur Background" = "鑳屾櫙铏氬寲";
-"Start Video/Audio Echo Test" = "寮濮嬮煶瑙嗛鍥炶矾娴嬭瘯";
-"Stop Video/Audio Echo Test" = "鍋滄闊宠棰戝洖璺祴璇";
+
diff --git a/macOS/Podfile b/macOS/Podfile
index c75c54009..f21e3feac 100644
--- a/macOS/Podfile
+++ b/macOS/Podfile
@@ -6,7 +6,7 @@ target 'APIExample' do
use_frameworks!
# Pods for APIExample
- pod 'AGEVideoLayout', '~> 1.0.2'
+ pod 'AGEVideoLayout', '~> 1.0.4'
pod 'AgoraRtcEngine_macOS', '3.6.0.1'
target 'APIExampleTests' do
@@ -18,4 +18,4 @@ target 'APIExample' do
# Pods for testing
end
-end
+end
\ No newline at end of file
diff --git a/windows/.gitignore b/windows/.gitignore
index 46405cfc5..8b4e2695e 100644
--- a/windows/.gitignore
+++ b/windows/.gitignore
@@ -258,4 +258,5 @@ libs/
ThirdParty/
-MediaPlayerPart/
\ No newline at end of file
+MediaPlayerPart/
+MediaPlayerPart64/
\ No newline at end of file
diff --git a/windows/APIExample/APIExample.sln b/windows/APIExample/APIExample.sln
index f4809a6b7..c0c9a6862 100644
--- a/windows/APIExample/APIExample.sln
+++ b/windows/APIExample/APIExample.sln
@@ -25,10 +25,12 @@ Global
{DB16CA2F-3910-4449-A5BD-6A602B33BE0F}.Release|x64.Build.0 = Release|x64
{2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Debug|Win32.ActiveCfg = Debug|Win32
{2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Debug|Win32.Build.0 = Debug|Win32
- {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Debug|x64.ActiveCfg = Debug|Win32
+ {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Debug|x64.ActiveCfg = Debug|x64
+ {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Debug|x64.Build.0 = Debug|x64
{2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Release|Win32.ActiveCfg = Release|Win32
{2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Release|Win32.Build.0 = Release|Win32
- {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Release|x64.ActiveCfg = Release|Win32
+ {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Release|x64.ActiveCfg = Debug|x64
+ {2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}.Release|x64.Build.0 = Debug|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/windows/APIExample/APIExample/APIExample.rc b/windows/APIExample/APIExample/APIExample.rc
index 84419dc2b..c4e252285 100644
--- a/windows/APIExample/APIExample/APIExample.rc
+++ b/windows/APIExample/APIExample/APIExample.rc
@@ -437,27 +437,6 @@ BEGIN
LTEXT "vloume",IDC_STATIC_AUDIO_VLOUME,327,386,42,8
END
-IDD_DIALOG_BEAUTY DIALOGEX 0, 0, 632, 400
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "",IDC_STATIC_VIDEO,1,0,483,310,NOT WS_VISIBLE
- LISTBOX IDC_LIST_INFO_BROADCASTING,491,0,139,312,LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
- LTEXT "Channel Name",IDC_STATIC_CHANNELNAME,11,328,48,8
- EDITTEXT IDC_EDIT_CHANNELNAME,71,326,218,13,ES_AUTOHSCROLL
- PUSHBUTTON "JoinChannel",IDC_BUTTON_JOINCHANNEL,307,326,50,14
- LTEXT "lightening contrast",IDC_STATIC_BEAUTY_LIGHTENING_CONTRAST_LEVEL,11,353,93,8
- COMBOBOX IDC_COMBO_BEAUTE_LIGHTENING_CONTRAST_LEVEL,80,352,79,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "",IDC_STATIC_DETAIL,442,325,181,58
- LTEXT "lightening",IDC_STATIC_BEAUTY_LIGHTENING,11,370,48,8
- EDITTEXT IDC_EDIT_LIGHTENING,79,369,80,13,ES_AUTOHSCROLL
- LTEXT "redness",IDC_STATIC_BEAUTY_REDNESS,166,353,48,8
- LTEXT "smoothness",IDC_STATIC_BEAUTY_SMOOTHNESS,166,371,48,8
- EDITTEXT IDC_EDIT_BEAUTY_REDNESS,222,351,80,13,ES_AUTOHSCROLL
- EDITTEXT IDC_EDIT_BEAUTY_SMOOTHNESS,222,370,80,13,ES_AUTOHSCROLL
- CONTROL "Beauty Enable",IDC_CHECK_BEAUTY_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,310,358,62,10
-END
-
IDD_DIALOG_PERCALL_TEST DIALOGEX 0, 0, 632, 400
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
@@ -602,6 +581,7 @@ BEGIN
COMBOBOX IDC_COMBO_COLOR,411,331,76,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Image File Path",IDC_BUTTON_IMAGE,331,329,73,14
EDITTEXT IDC_EDIT_IMAGE_PATH,411,329,144,14,ES_AUTOHSCROLL
+ CONTROL "Report",IDC_CHECK_REPORT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,570,325,38,10
END
IDD_DIALOG_MUTI_SOURCE DIALOGEX 0, 0, 632, 400
@@ -619,6 +599,37 @@ BEGIN
LTEXT "Share Info",IDC_STATIC_SHARE,17,370,38,8
END
+IDD_DIALOG_BEAUTY DIALOGEX 0, 0, 632, 400
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_STATIC_VIDEO,0,0,483,289,NOT WS_VISIBLE
+ LISTBOX IDC_LIST_INFO_BROADCASTING,491,0,139,286,LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LTEXT "Channel Name",IDC_STATIC_CHANNELNAME,12,309,48,8
+ EDITTEXT IDC_EDIT_CHANNELNAME,72,307,115,13,ES_AUTOHSCROLL
+ PUSHBUTTON "JoinChannel",IDC_BUTTON_JOINCHANNEL,194,306,50,14
+ LTEXT "lightening contrast",IDC_STATIC_BEAUTY_LIGHTENING_CONTRAST_LEVEL,12,334,64,8
+ COMBOBOX IDC_COMBO_BEAUTE_LIGHTENING_CONTRAST_LEVEL,81,333,79,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "",IDC_STATIC_DETAIL,485,297,132,56
+ LTEXT "lightening",IDC_STATIC_BEAUTY_LIGHTENING,12,351,45,8
+ LTEXT "redness",IDC_STATIC_BEAUTY_REDNESS,167,334,41,8
+ LTEXT "smoothness",IDC_STATIC_BEAUTY_SMOOTHNESS,167,352,42,8
+ CONTROL "Beauty Enable",IDC_CHECK_BEAUTY_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,251,307,62,10
+ GROUPBOX "Beauty",IDC_STATIC_BEaUTY,0,300,352,67
+ GROUPBOX "Enhance",IDC_STATIC,0,373,412,24
+ CONTROL "Colorful Enhance",IDC_CHECK_ENHANCE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,384,75,13
+ CONTROL "",IDC_SLIDER_STRENGTH,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,130,382,104,15
+ LTEXT "Strength",IDC_STATIC_STRENTH,92,389,29,8
+ LTEXT "Skin Protect",IDC_STATIC_SKIN_PROTECT,241,389,40,8
+ LTEXT "Strength",IDC_STATIC_STRENTH2,95,389,29,8
+ LTEXT "Static",IDC_STATIC,267,389,19,8
+ CONTROL "",IDC_SLIDER_SKIN_PROTECT,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,294,382,110,15
+ CONTROL "Video Denoise",IDC_CHECK_VIDEO_DENOISE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,370,299,58,10
+ CONTROL "",IDC_SLIDER_REDNESS,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,219,330,121,15
+ CONTROL "",IDC_SLIDER_LIGHTENING,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,55,348,100,15
+ CONTROL "",IDC_SLIDER_SMOOTHNESS,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,222,346,117,15
+END
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -731,12 +742,6 @@ BEGIN
BOTTOMMARGIN, 397
END
- IDD_DIALOG_BEAUTY, DIALOG
- BEGIN
- RIGHTMARGIN, 630
- BOTTOMMARGIN, 397
- END
-
IDD_DIALOG_PERCALL_TEST, DIALOG
BEGIN
RIGHTMARGIN, 630
@@ -778,6 +783,12 @@ BEGIN
RIGHTMARGIN, 630
BOTTOMMARGIN, 397
END
+
+ IDD_DIALOG_BEAUTY, DIALOG
+ BEGIN
+ RIGHTMARGIN, 630
+ BOTTOMMARGIN, 397
+ END
END
#endif // APSTUDIO_INVOKED
@@ -872,11 +883,6 @@ BEGIN
0
END
-IDD_DIALOG_BEAUTY AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
IDD_DIALOG_PERCALL_TEST AFX_DIALOG_LAYOUT
BEGIN
0
@@ -912,6 +918,11 @@ BEGIN
0
END
+IDD_DIALOG_BEAUTY AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/windows/APIExample/APIExample/APIExample.vcxproj b/windows/APIExample/APIExample/APIExample.vcxproj
index 31411bbaa..80db3b8fe 100644
--- a/windows/APIExample/APIExample/APIExample.vcxproj
+++ b/windows/APIExample/APIExample/APIExample.vcxproj
@@ -23,7 +23,7 @@
{DB16CA2F-3910-4449-A5BD-6A602B33BE0F}
MFCProj
APIExample
- 8.1
+ 10.0.17134.0
@@ -93,8 +93,8 @@
Level3
Disabled
false
- WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);
- $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);$(ProjectDir)RtcChannelHelperPlugin;$(solutionDir)MediaPlayerPart\include
+ WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);$(ProjectDir)RtcChannelHelperPlugin;$(solutionDir)MediaPlayerPart\high_level_api\include
MultiThreadedDLL
@@ -118,7 +118,8 @@
if exist $(SolutionDir)libs (copy $(SolutionDir)libs\x86\*.dll $(SolutionDir)$(Configuration))
if exist zh-cn.ini (copy zh-cn.ini $(SolutionDir)$(Configuration))
if exist en.ini (copy en.ini $(SolutionDir)$(Configuration))
-if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\AgoraMediaPlayer.dll $(SolutionDir)$(Configuration))
+if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\AgoraMediaPlayer.dll $(SolutionDir)$(Configuration))
+if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\libagora-player-ffmpeg.dll $(SolutionDir)$(Configuration))
@@ -130,23 +131,24 @@ if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\A
$(IntDir)$(TargetName)$(TargetExt).embed.manifest.res
- $(SolutionDir)installThirdParty.bat
+ $(SolutionDir)installThirdParty.bat x86
- Use
+ NotUsing
Level3
Disabled
true
- _WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);_WIN32_WINNT
- $(SolutionDir)\libs\include;..\libs\include;
+ _WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);$(ProjectDir)RtcChannelHelperPlugin;$(solutionDir)MediaPlayerPart64\high_level_api\include
MultiThreadedDLL
Windows
- $(SolutionDir)\libs\x86_64
+ $(SolutionDir)\libs\x86_64;$(SolutionDir)ThirdParty\libyuv\debug\x64;$(SolutionDir)ThirdParty\DShow\x64;$(SolutionDir)MediaPlayerPart64\lib
libcmt.lib
+ AgoraMediaPlayer.lib;d3d9.lib;dsound.lib;winmm.lib;dxguid.lib
false
@@ -159,14 +161,20 @@ if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\A
$(IntDir);%(AdditionalIncludeDirectories)
- if exist $(SolutionDir)\libs (copy $(SolutionDir)libs\x86_64\agora_rtc_sdk.dll $(SolutionDir)$(Platform)\$(Configuration))
+ if exist $(SolutionDir)\libs (copy $(SolutionDir)libs\x86_64\*.dll $(SolutionDir)$(Platform)\$(Configuration))
if exist zh-cn.ini (copy zh-cn.ini $(SolutionDir)$(Platform)\$(Configuration))
if exist en.ini (copy en.ini $(SolutionDir)$(Platform)\$(Configuration))
+copy Advanced\MediaIOCustomVideoCaptrue\screen.yuv $(SolutionDir)$(Platform)\$(Configuration)
+if exist $(SolutionDir)MediaPlayerPart64 (copy $(SolutionDir)MediaPlayerPart64\dll\AgoraMediaPlayer.dll $(SolutionDir)$(Platform)\$(Configuration))
+if exist $(SolutionDir)MediaPlayerPart64 (copy $(SolutionDir)MediaPlayerPart64\dll\libagora-player-ffmpeg.dll $(SolutionDir)$(Platform)\$(Configuration))
PerMonitorHighDPIAware
+
+ $(SolutionDir)installThirdParty.bat x64
+
@@ -212,25 +220,29 @@ if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\A
PerMonitorHighDPIAware
+
+ $(SolutionDir)installThirdParty) x86
+
- Use
+ NotUsing
Level3
MaxSpeed
true
true
true
- _WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions);_WIN32_WINNT
- $(SolutionDir)libs\include
+ _WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);$(ProjectDir)RtcChannelHelperPlugin;$(solutionDir)MediaPlayerPart64\high_level_api\include
MultiThreadedDLL
Windows
true
true
- $(SolutionDir)\libs\x86_64
+ $(SolutionDir)\libs\x86_64;$(SolutionDir)ThirdParty\libyuv\Release\x64;$(SolutionDir)ThirdParty\DShow\x64;$(SolutionDir)MediaPlayerPart64\lib
libcmt.lib
+ AgoraMediaPlayer.lib;d3d9.lib;dsound.lib;winmm.lib;dxguid.lib
false
@@ -243,14 +255,20 @@ if exist $(SolutionDir)MediaPlayerPart (copy $(SolutionDir)MediaPlayerPart\dll\A
$(IntDir);%(AdditionalIncludeDirectories)
- if exist $(SolutionDir)\libs (copy $(SolutionDir)libs\x86_64\agora_rtc_sdk.dll $(SolutionDir)$(Platform)\$(Configuration))
+ if exist $(SolutionDir)\libs (copy $(SolutionDir)libs\x86_64\*.dll $(SolutionDir)$(Platform)\$(Configuration))
if exist zh-cn.ini (copy zh-cn.ini $(SolutionDir)$(Platform)\$(Configuration))
if exist en.ini (copy en.ini $(SolutionDir)$(Platform)\$(Configuration))
+copy Advanced\MediaIOCustomVideoCaptrue\screen.yuv $(SolutionDir)$(Platform)\$(Configuration)
+if exist $(SolutionDir)MediaPlayerPart64 (copy $(SolutionDir)MediaPlayerPart64\dll\AgoraMediaPlayer.dll $(SolutionDir)$(Platform)\$(Configuration))
+if exist $(SolutionDir)MediaPlayerPart64 (copy $(SolutionDir)MediaPlayerPart64\dll\libagora-player-ffmpeg.dll $(SolutionDir)$(Platform)\$(Configuration))
PerMonitorHighDPIAware
+
+ $(SolutionDir)installThirdParty.bat x64
+
diff --git a/windows/APIExample/APIExample/Advanced/AudioVolume/CAgoraAudioVolumeDlg.cpp b/windows/APIExample/APIExample/Advanced/AudioVolume/CAgoraAudioVolumeDlg.cpp
index 738134749..b5961c55f 100644
--- a/windows/APIExample/APIExample/Advanced/AudioVolume/CAgoraAudioVolumeDlg.cpp
+++ b/windows/APIExample/APIExample/Advanced/AudioVolume/CAgoraAudioVolumeDlg.cpp
@@ -166,6 +166,8 @@ BEGIN_MESSAGE_MAP(CAgoraAudioVolumeDlg, CDialogEx)
ON_MESSAGE(WM_MSGID(EID_USER_JOINED), &CAgoraAudioVolumeDlg::OnEIDUserJoined)
ON_MESSAGE(WM_MSGID(EID_USER_OFFLINE), &CAgoraAudioVolumeDlg::OnEIDUserOffline)
ON_MESSAGE(WM_MSGID(EID_AUDIO_VOLUME_INDICATION), &CAgoraAudioVolumeDlg::OnEIDAudioVolumeIndication)
+ ON_MESSAGE(WM_MSGID(EID_AUDIO_VOLUME_TEST_INDICATION), &CAgoraAudioVolumeDlg::OnEIDAudioVolumeTestIndication)
+
ON_BN_CLICKED(IDC_BUTTON_JOINCHANNEL, &CAgoraAudioVolumeDlg::OnBnClickedButtonJoinchannel)
ON_LBN_SELCHANGE(IDC_LIST_INFO_BROADCASTING, &CAgoraAudioVolumeDlg::OnSelchangeListInfoBroadcasting)
ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_CAP_VOLUME, &CAgoraAudioVolumeDlg::OnReleasedcaptureSliderCapVolume)
@@ -321,6 +323,17 @@ LRESULT CAgoraAudioVolumeDlg::OnEIDActiveSpeaker(WPARAM wparam, LPARAM lparam)
return TRUE;
}
+LRESULT CAgoraAudioVolumeDlg::OnEIDAudioVolumeTestIndication(WPARAM wparam, LPARAM lparam)
+{
+ CString strInfo;
+ strInfo.Format(_T("onAudioVolumeTestIndication"));
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("type:%s"), wparam == AudioTestRecordingVolume? L"recording":L"playback");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("volume:%d"), lparam);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return TRUE;
+}
//audio volume indication
void CAudioVolumeEventHandler::onAudioVolumeIndication(const AudioVolumeInfo * speakers, unsigned int speakerNumber, int totalVolume)
@@ -334,6 +347,12 @@ void CAudioVolumeEventHandler::onAudioVolumeIndication(const AudioVolumeInfo * s
::PostMessage(m_hMsgHanlder, WM_MSGID(EID_AUDIO_VOLUME_INDICATION), (WPARAM)p, 0);
}
+void CAudioVolumeEventHandler::onAudioDeviceTestVolumeIndication(AudioDeviceTestVolumeType volumeType, int volume)
+{
+ if (m_hMsgHanlder)
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_AUDIO_VOLUME_TEST_INDICATION), (WPARAM)volumeType, volume);
+}
+
//active speaker
void CAudioVolumeEventHandler::onActiveSpeaker(uid_t uid)
{
diff --git a/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.cpp b/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.cpp
index cb8ef1ea2..ec16a5305 100644
--- a/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.cpp
+++ b/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.cpp
@@ -111,9 +111,7 @@ void CAgoraBeautyDlg::RenderLocalVideo()
void CAgoraBeautyDlg::ResumeStatus()
{
m_edtChannel.SetWindowText(_T(""));
- m_edtLightLevel.SetWindowText(_T(""));
- m_edtReadness.SetWindowText(_T(""));
- m_edtSmoothness.SetWindowText(_T(""));
+
m_staDetail.SetWindowText(_T(""));
m_chkBeauty.SetCheck(BST_UNCHECKED);
@@ -122,6 +120,18 @@ void CAgoraBeautyDlg::ResumeStatus()
SetBeauty(false);
m_joinChannel = false;
m_initialize = false;
+
+ m_sldStrength.SetRange(0, 100);
+ m_sldStrength.SetPos(50);
+ m_sldSkin.SetRange(0, 100);
+ m_sldSkin.SetPos(100);
+
+ m_sdlLightening.SetRange(0, 100);
+ m_sdlLightening.SetPos(0);
+ m_sldRedness.SetRange(0, 100);
+ m_sldRedness.SetPos(0);
+ m_sldSmoothness.SetRange(0, 100);
+ m_sldSmoothness.SetPos(0);
}
@@ -133,16 +143,24 @@ void CAgoraBeautyDlg::DoDataExchange(CDataExchange* pDX)
DDX_Control(pDX, IDC_CHECK_BEAUTY_ENABLE, m_chkBeauty);
DDX_Control(pDX, IDC_BUTTON_JOINCHANNEL, m_btnJoinChannel);
DDX_Control(pDX, IDC_COMBO_BEAUTE_LIGHTENING_CONTRAST_LEVEL, m_cmbBeautyLevel);
- DDX_Control(pDX, IDC_EDIT_LIGHTENING, m_edtLightLevel);
+
DDX_Control(pDX, IDC_STATIC_BEAUTY_REDNESS, m_staRedness);
DDX_Control(pDX, IDC_STATIC_BEAUTY_SMOOTHNESS, m_staSoomthness);
- DDX_Control(pDX, IDC_EDIT_BEAUTY_REDNESS, m_edtReadness);
- DDX_Control(pDX, IDC_EDIT_BEAUTY_SMOOTHNESS, m_edtSmoothness);
+
DDX_Control(pDX, IDC_STATIC_VIDEO, m_staVideoArea);
DDX_Control(pDX, IDC_LIST_INFO_BROADCASTING, m_lstInfo);
DDX_Control(pDX, IDC_STATIC_BEAUTY_LIGHTENING_CONTRAST_LEVEL, m_staLightContrast);
DDX_Control(pDX, IDC_STATIC_BEAUTY_LIGHTENING, m_staLight);
DDX_Control(pDX, IDC_STATIC_DETAIL, m_staDetail);
+ DDX_Control(pDX, IDC_CHECK_ENHANCE, m_chkEnhance);
+ DDX_Control(pDX, IDC_SLIDER_STRENGTH, m_sldStrength);
+ DDX_Control(pDX, IDC_STATIC_SKIN_PROTECT, m_staSkin);
+ DDX_Control(pDX, IDC_SLIDER_SKIN_PROTECT, m_sldSkin);
+ DDX_Control(pDX, IDC_CHECK_VIDEO_DENOISE, m_chkVideoDenoise);
+
+ DDX_Control(pDX, IDC_SLIDER_LIGHTENING, m_sdlLightening);
+ DDX_Control(pDX, IDC_SLIDER_REDNESS, m_sldRedness);
+ DDX_Control(pDX, IDC_SLIDER_SMOOTHNESS, m_sldSmoothness);
}
@@ -156,9 +174,36 @@ BEGIN_MESSAGE_MAP(CAgoraBeautyDlg, CDialogEx)
ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_CHECK_BEAUTY_ENABLE, &CAgoraBeautyDlg::OnBnClickedCheckbeautyCtrlEnable)
ON_LBN_SELCHANGE(IDC_LIST_INFO_BROADCASTING, &CAgoraBeautyDlg::OnSelchangeListInfoBroadcasting)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_REDNESS, &CAgoraBeautyDlg::OnNMCustomdrawSliderRedness)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_LIGHTENING, &CAgoraBeautyDlg::OnNMCustomdrawSliderLightening)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_SMOOTHNESS, &CAgoraBeautyDlg::OnNMCustomdrawSliderSmoothness)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_STRENGTH, &CAgoraBeautyDlg::OnNMCustomdrawSliderStrength)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_SLIDER_SKIN_PROTECT, &CAgoraBeautyDlg::OnNMCustomdrawSliderSkinProtect)
+ ON_BN_CLICKED(IDC_CHECK_ENHANCE, &CAgoraBeautyDlg::OnBnClickedCheckEnhance)
+ ON_BN_CLICKED(IDC_CHECK_VIDEO_DENOISE, &CAgoraBeautyDlg::OnBnClickedCheckVideoDenoise)
+ ON_CBN_SELCHANGE(IDC_COMBO_BEAUTE_LIGHTENING_CONTRAST_LEVEL, &CAgoraBeautyDlg::OnSelchangeComboBeauteLighteningContrastLevel)
END_MESSAGE_MAP()
+void CAgoraBeautyDlg::SetBeauty()
+{
+ if (!m_rtcEngine) return;
+ BeautyOptions option;
+ option.rednessLevel = m_sldRedness.GetPos() / 100.0f;
+ option.lighteningLevel = m_sdlLightening.GetPos() / 100.0f;
+ option.smoothnessLevel = m_sldSmoothness.GetPos() / 100.0f;
+ option.lighteningContrastLevel = (agora::rtc::BeautyOptions::LIGHTENING_CONTRAST_LEVEL)m_cmbBeautyLevel.GetCurSel();
+ m_rtcEngine->setBeautyEffectOptions(m_chkBeauty.GetCheck() != 0, option);
+}
+
+void CAgoraBeautyDlg::SetColorful()
+{
+ if (!m_rtcEngine) return;
+ ColorEnhanceOptions options;
+ options.skinProtectLevel = m_sldSkin.GetPos() / 100.0f;
+ options.strengthLevel = m_sldStrength.GetPos() / 100.0f;
+ m_rtcEngine->setColorEnhanceOptions(m_chkEnhance.GetCheck()!=0,options);
+}
// join channel or level channel.
void CAgoraBeautyDlg::OnBnClickedButtonJoinchannel()
@@ -213,25 +258,24 @@ void CAgoraBeautyDlg::SetBeauty(bool enabled,
void CAgoraBeautyDlg::OnBnClickedCheckbeautyCtrlEnable()
{
bool enabled = m_chkBeauty.GetCheck() == BST_CHECKED ? TRUE : FALSE;
+ m_sldRedness.EnableWindow(enabled);
+ m_sldSmoothness.EnableWindow(enabled);
+ m_sdlLightening.EnableWindow(enabled);
+
//Beauty options to set
CString tmp;
auto lighteningContrastLevel = (agora::rtc::BeautyOptions::LIGHTENING_CONTRAST_LEVEL)m_cmbBeautyLevel.GetCurSel();
float lighteningLevel;
float rednessLevel;
float smoothnessLevel;
- m_edtLightLevel.GetWindowText(tmp);
- auto func = [](float a)->float {
- return a <0.0f ? 0.0f : a>1.0f ? 1.0f : a;
- };
- lighteningLevel = func(static_cast(_ttof(tmp)/10));
- m_edtReadness.GetWindowText(tmp);
- rednessLevel = func(static_cast(_ttof(tmp)/10));
- m_edtSmoothness.GetWindowText(tmp);
- smoothnessLevel = func(static_cast(_ttof(tmp)/10));
+ lighteningLevel = m_sdlLightening.GetPos() / 100.0f;
+ rednessLevel = m_sldRedness.GetPos() / 100.0f;
+ smoothnessLevel = m_sldSmoothness.GetPos() / 100.0f;
CString strInfo;
CString strlighteningContrastLevel;
m_cmbBeautyLevel.GetWindowText(strlighteningContrastLevel);
SetBeauty(enabled, lighteningContrastLevel, lighteningLevel, rednessLevel, smoothnessLevel);
+ SetColorful();
if (enabled)
{
strInfo.Format(_T("lighteningContrastLevel:%s,\nlightening:%.1f,\nredness:%.1f,\nsmoothness:%.1f"),
@@ -485,3 +529,55 @@ void CAgoraBeautyDlg::OnSelchangeListInfoBroadcasting()
m_lstInfo.GetText(sel, strDetail);
m_staDetail.SetWindowText(strDetail);
}
+
+
+void CAgoraBeautyDlg::OnNMCustomdrawSliderRedness(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ SetBeauty();
+}
+
+
+void CAgoraBeautyDlg::OnNMCustomdrawSliderLightening(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ SetBeauty();
+}
+
+
+void CAgoraBeautyDlg::OnNMCustomdrawSliderSmoothness(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ SetBeauty();
+}
+
+
+void CAgoraBeautyDlg::OnNMCustomdrawSliderStrength(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ SetColorful();
+}
+
+
+void CAgoraBeautyDlg::OnNMCustomdrawSliderSkinProtect(NMHDR *pNMHDR, LRESULT *pResult)
+{
+ SetColorful();
+}
+
+
+void CAgoraBeautyDlg::OnBnClickedCheckEnhance()
+{
+ m_sldStrength.EnableWindow(m_chkEnhance.GetCheck() != 0);
+ m_sldSkin.EnableWindow(m_chkEnhance.GetCheck() != 0);
+
+ SetColorful();
+}
+
+
+void CAgoraBeautyDlg::OnBnClickedCheckVideoDenoise()
+{
+ VideoDenoiserOptions options;
+ m_rtcEngine->setVideoDenoiserOptions(m_chkVideoDenoise.GetCheck() != 0,options);
+}
+
+
+void CAgoraBeautyDlg::OnSelchangeComboBeauteLighteningContrastLevel()
+{
+ SetBeauty();
+}
diff --git a/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.h b/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.h
index 43a9490c7..307a54bac 100644
--- a/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.h
+++ b/windows/APIExample/APIExample/Advanced/Beauty/CAgoraBeautyDlg.h
@@ -115,6 +115,8 @@ class CAgoraBeautyDlg : public CDialogEx
CBeautyEventHandler m_eventHandler;
protected:
+ void SetBeauty();
+ void SetColorful();
virtual void DoDataExchange(CDataExchange* pDX);
LRESULT OnEIDJoinChannelSuccess(WPARAM wParam, LPARAM lParam);
LRESULT OnEIDLeaveChannel(WPARAM wParam, LPARAM lParam);
@@ -129,11 +131,9 @@ class CAgoraBeautyDlg : public CDialogEx
CButton m_chkBeauty;
CButton m_btnJoinChannel;
CComboBox m_cmbBeautyLevel;
- CEdit m_edtLightLevel;
+
CStatic m_staRedness;
CStatic m_staSoomthness;
- CEdit m_edtReadness;
- CEdit m_edtSmoothness;
CStatic m_staVideoArea;
CListBox m_lstInfo;
CStatic m_staLightContrast;
@@ -146,6 +146,23 @@ class CAgoraBeautyDlg : public CDialogEx
virtual BOOL PreTranslateMessage(MSG* pMsg);
CStatic m_staDetail;
afx_msg void OnSelchangeListInfoBroadcasting();
+
+ CSliderCtrl m_sldStrength;
+ CStatic m_staSkin;
+ CSliderCtrl m_sldSkin;
+ CButton m_chkVideoDenoise;
+ CButton m_chkEnhance;
+ CSliderCtrl m_sdlLightening;
+ CSliderCtrl m_sldRedness;
+ CSliderCtrl m_sldSmoothness;
+ afx_msg void OnNMCustomdrawSliderRedness(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnNMCustomdrawSliderLightening(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnNMCustomdrawSliderSmoothness(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnNMCustomdrawSliderStrength(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnNMCustomdrawSliderSkinProtect(NMHDR *pNMHDR, LRESULT *pResult);
+ afx_msg void OnBnClickedCheckEnhance();
+ afx_msg void OnBnClickedCheckVideoDenoise();
+ afx_msg void OnSelchangeComboBeauteLighteningContrastLevel();
};
diff --git a/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.cpp b/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.cpp
index 79a66106b..b1c665523 100644
--- a/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.cpp
+++ b/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.cpp
@@ -427,9 +427,9 @@ LRESULT CAgoraMediaPlayer::OnmediaPlayerStateChanged(WPARAM wParam, LPARAM lPara
{
CString strState;
CString strError;
- switch ((agora::media::MEDIA_PLAYER_STATE)wParam)
+ switch ((agora::media::base::MEDIA_PLAYER_STATE)wParam)
{
- case agora::media::PLAYER_STATE_OPEN_COMPLETED:
+ case agora::media::base::PLAYER_STATE_OPEN_COMPLETED:
strState = _T("PLAYER_STATE_OPEN_COMPLETED");
m_mediaPlayerState = mediaPLAYER_OPEN;
m_btnPlay.EnableWindow(TRUE);
@@ -438,25 +438,25 @@ LRESULT CAgoraMediaPlayer::OnmediaPlayerStateChanged(WPARAM wParam, LPARAM lPara
m_sldVideo.SetRangeMax((int)duration);
break;
- case agora::media::PLAYER_STATE_OPENING:
+ case agora::media::base::PLAYER_STATE_OPENING:
strState = _T("PLAYER_STATE_OPENING");
break;
- case agora::media::PLAYER_STATE_IDLE:
+ case agora::media::base::PLAYER_STATE_IDLE:
strState = _T("PLAYER_STATE_IDLE");
break;
- case agora::media::PLAYER_STATE_PLAYING:
+ case agora::media::base::PLAYER_STATE_PLAYING:
strState = _T("PLAYER_STATE_PLAYING");
break;
- case agora::media::PLAYER_STATE_PLAYBACK_COMPLETED:
+ case agora::media::base::PLAYER_STATE_PLAYBACK_COMPLETED:
strState = _T("PLAYER_STATE_PLAYBACK_COMPLETED");
break;
- case agora::media::PLAYER_STATE_PAUSED:
+ case agora::media::base::PLAYER_STATE_PAUSED:
strState = _T("PLAYER_STATE_PAUSED");
break;
- case agora::media::PLAYER_STATE_STOPPED:
+ /*case agora::media::base::PLAYER_STATE_STOPPED:
strState = _T("PLAYER_STATE_PAUSED");
- break;
- case agora::media::PLAYER_STATE_FAILED:
+ break;*/
+ case agora::media::base::PLAYER_STATE_FAILED:
strState = _T("PLAYER_STATE_FAILED");
//call media player stop function
m_mediaPlayer->stop();
@@ -466,42 +466,40 @@ LRESULT CAgoraMediaPlayer::OnmediaPlayerStateChanged(WPARAM wParam, LPARAM lPara
break;
}
- switch ((agora::media::MEDIA_PLAYER_ERROR)lParam)
+ switch ((agora::media::base::MEDIA_PLAYER_ERROR)lParam)
{
- case agora::media::PLAYER_ERROR_URL_NOT_FOUND:
+ case agora::media::base::PLAYER_ERROR_URL_NOT_FOUND:
strError = _T("PLAYER_ERROR_URL_NOT_FOUND");
break;
- case agora::media::PLAYER_ERROR_NONE:
+ case agora::media::base::PLAYER_ERROR_NONE:
strError = _T("PLAYER_ERROR_NONE");
break;
- case agora::media::PLAYER_ERROR_CODEC_NOT_SUPPORTED:
+ case agora::media::base::PLAYER_ERROR_CODEC_NOT_SUPPORTED:
strError = _T("PLAYER_ERROR_NONE");
break;
- case agora::media::PLAYER_ERROR_INVALID_ARGUMENTS:
+ case agora::media::base::PLAYER_ERROR_INVALID_ARGUMENTS:
strError = _T("PLAYER_ERROR_INVALID_ARGUMENTS");
break;
- case agora::media::PLAY_ERROR_SRC_BUFFER_UNDERFLOW:
- strError = _T("PLAY_ERROR_SRC_BUFFER_UNDERFLOW");
- break;
- case agora::media::PLAYER_ERROR_INTERNAL:
+
+ case agora::media::base::PLAYER_ERROR_INTERNAL:
strError = _T("PLAYER_ERROR_INTERNAL");
break;
- case agora::media::PLAYER_ERROR_INVALID_STATE:
+ case agora::media::base::PLAYER_ERROR_INVALID_STATE:
strError = _T("PLAYER_ERROR_INVALID_STATE");
break;
- case agora::media::PLAYER_ERROR_NO_RESOURCE:
+ case agora::media::base::PLAYER_ERROR_NO_RESOURCE:
strError = _T("PLAYER_ERROR_NO_RESOURCE");
break;
- case agora::media::PLAYER_ERROR_OBJ_NOT_INITIALIZED:
+ case agora::media::base::PLAYER_ERROR_OBJ_NOT_INITIALIZED:
strError = _T("PLAYER_ERROR_OBJ_NOT_INITIALIZED");
break;
- case agora::media::PLAYER_ERROR_INVALID_CONNECTION_STATE:
+ case agora::media::base::PLAYER_ERROR_INVALID_CONNECTION_STATE:
strError = _T("PLAYER_ERROR_INVALID_CONNECTION_STATE");
break;
- case agora::media::PLAYER_ERROR_UNKNOWN_STREAM_TYPE:
+ case agora::media::base::PLAYER_ERROR_UNKNOWN_STREAM_TYPE:
strError = _T("PLAYER_ERROR_UNKNOWN_STREAM_TYPE");
break;
- case agora::media::PLAYER_ERROR_VIDEO_RENDER_FAILED:
+ case agora::media::base::PLAYER_ERROR_VIDEO_RENDER_FAILED:
strError = _T("PLAYER_ERROR_VIDEO_RENDER_FAILED");
break;
}
diff --git a/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.h b/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.h
index d29a02899..70b7930c2 100644
--- a/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.h
+++ b/windows/APIExample/APIExample/Advanced/MediaPlayer/CAgoraMediaPlayer.h
@@ -16,8 +16,8 @@ class AgoraMediaPlayerEvent : public AgoraRtcChannelPublishHelperObserver
* @param state New player state
* @param ec Player error message
*/
- virtual void onPlayerStateChanged(agora::media::MEDIA_PLAYER_STATE state,
- agora::media::MEDIA_PLAYER_ERROR ec)
+ virtual void onPlayerStateChanged(agora::media::base::MEDIA_PLAYER_STATE state,
+ agora::media::base::MEDIA_PLAYER_ERROR ec)
{
::PostMessage(m_hMsgHanlder, WM_MSGID(mediaPLAYER_STATE_CHANGED), (WPARAM)state, (LPARAM) ec);
@@ -37,7 +37,7 @@ class AgoraMediaPlayerEvent : public AgoraRtcChannelPublishHelperObserver
*
* @param event
*/
- virtual void onPlayerEvent(agora::media::MEDIA_PLAYER_EVENT event)
+ virtual void onPlayerEvent(agora::media::base::MEDIA_PLAYER_EVENT event)
{
};
@@ -49,12 +49,23 @@ class AgoraMediaPlayerEvent : public AgoraRtcChannelPublishHelperObserver
* @param data data
* @param length data length
*/
- virtual void onMetadata(agora::media::MEDIA_PLAYER_METADATA_TYPE type, const uint8_t* data,
+ virtual void onMetadata(agora::media::base::MEDIA_PLAYER_METADATA_TYPE type, const uint8_t* data,
uint32_t length)
{
}
+ virtual void onPreloadEvent(const char* src, media::base::PLAYER_PRELOAD_EVENT event)override {
+
+ }
+
+ virtual void onPlayBufferUpdated(int64_t playCachedBuffer) override {
+
+ }
+
+ virtual void onCompleted() override {
+
+ }
private:
HWND m_hMsgHanlder;
diff --git a/windows/APIExample/APIExample/Advanced/MultiVideoSource/ProcessScreenShare/ProcessScreenShare.vcxproj b/windows/APIExample/APIExample/Advanced/MultiVideoSource/ProcessScreenShare/ProcessScreenShare.vcxproj
index 4cb80f7d5..4e3fb1d93 100644
--- a/windows/APIExample/APIExample/Advanced/MultiVideoSource/ProcessScreenShare/ProcessScreenShare.vcxproj
+++ b/windows/APIExample/APIExample/Advanced/MultiVideoSource/ProcessScreenShare/ProcessScreenShare.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
{2B345C3C-4BEA-4DA3-B754-43F9AD219D4A}
@@ -24,6 +32,13 @@
Unicode
Dynamic
+
+ Application
+ true
+ v141
+ Unicode
+ Dynamic
+
Application
false
@@ -32,26 +47,50 @@
Unicode
Dynamic
+
+ Application
+ false
+ v141
+ true
+ Unicode
+ Dynamic
+
+
+
+
+
+
+
+ true
+ $(VC_IncludePath);$(WindowsSDK_IncludePath);
+ $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);
+
+
true
$(VC_IncludePath);$(WindowsSDK_IncludePath);../../../sdk/include;../sdk/include;../openLive/
- $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);../../../sdk/lib;../sdk/lib;
+ $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdk_71A_LibraryPath_x64);
false
$(VC_IncludePath);$(WindowsSDK_IncludePath);$(WindowsSdk_71A_IncludePath);../../../sdk/include;../sdk/include;../openLive/
$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(WindowsSdk_71A_LibraryPath_x86);../../../sdk/lib;../sdk/lib;
+
+ false
+ $(VC_IncludePath);$(WindowsSDK_IncludePath);$(WindowsSdk_71A_IncludePath);../../../sdk/include;../sdk/include;../openLive/
+ $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(WindowsSdk_71A_LibraryPath_x64);
+
Use
@@ -77,6 +116,30 @@
$(IntDir);%(AdditionalIncludeDirectories)
+
+
+ Use
+ Level3
+ Disabled
+ WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);
+
+
+ Windows
+ true
+ $(SolutionDir)libs\x86_64;$(SolutionDir)ThirdParty\libyuv\$(Configuration);
+
+
+ false
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ 0x0409
+ _DEBUG;%(PreprocessorDefinitions)
+ $(IntDir);%(AdditionalIncludeDirectories)
+
+
Level3
@@ -106,6 +169,34 @@
$(IntDir);%(AdditionalIncludeDirectories)
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)libs\include;$(solutionDir)ThirdParty\libYUV;$(ProjectDir);
+
+
+ Windows
+ true
+ true
+ true
+ $(SolutionDir)libs\x86_64;$(SolutionDir)ThirdParty\libyuv\$(Configuration);$(SolutionDir)
+
+
+ false
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ 0x0409
+ NDEBUG;%(PreprocessorDefinitions)
+ $(IntDir);%(AdditionalIncludeDirectories)
+
+
@@ -123,7 +214,9 @@
Create
+ Create
Create
+ Create
diff --git a/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp b/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp
index e9dfdf1c6..c66406bf2 100644
--- a/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp
+++ b/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.cpp
@@ -230,6 +230,14 @@ LRESULT CAgoraScreenCapture::OnEIDRemoteVideoStateChanged(WPARAM wParam, LPARAM
return 0;
}
+LRESULT CAgoraScreenCapture::OnEIDScreenCaptureInfoUpdated(WPARAM wParam, LPARAM lParam)
+{
+ CString strInfo;
+ strInfo.Format(_T("OnScreenCaptureInfoUpdated state:\n%s: error:\n%u"), wParam, lParam);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return TRUE;
+}
+
LRESULT CAgoraScreenCapture::OnEIDLocalVideoStateChanged(WPARAM wParam, LPARAM lParam)
{
LOCAL_VIDEO_STREAM_STATE localVideoState =(LOCAL_VIDEO_STREAM_STATE) wParam;
@@ -305,6 +313,7 @@ BEGIN_MESSAGE_MAP(CAgoraScreenCapture, CDialogEx)
ON_MESSAGE(WM_MSGID(EID_USER_OFFLINE), &CAgoraScreenCapture::OnEIDUserOffline)
ON_MESSAGE(WM_MSGID(EID_REMOTE_VIDEO_STATE_CHANED), &CAgoraScreenCapture::OnEIDRemoteVideoStateChanged)
ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATE_CHANGED), &CAgoraScreenCapture::OnEIDLocalVideoStateChanged)
+ ON_MESSAGE(WM_MSGID(EID_SCREEN_CAPTURE_INFO_UPDATED), &CAgoraScreenCapture::OnEIDScreenCaptureInfoUpdated)
ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_BUTTON_UPDATEPARAM, &CAgoraScreenCapture::OnBnClickedButtonUpdateparam)
@@ -637,6 +646,19 @@ void CScreenCaptureEventHandler::onRemoteVideoStateChanged(uid_t uid, REMOTE_VID
}
}
+/** Occurs when screencapture fail to filter window
+ *
+ *
+ * @param ScreenCaptureInfo
+ */
+void CScreenCaptureEventHandler::onScreenCaptureInfoUpdated(agora::rtc::ScreenCaptureInfo& info)
+{
+ if (m_hMsgHanlder)
+ {
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_SCREEN_CAPTURE_INFO_UPDATED), (WPARAM)info.cardType, (LPARAM)info.errCode);
+ }
+}
+
static
BOOL IsWindowCloaked(HWND hwnd)
{
diff --git a/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.h b/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.h
index 4d52508c3..ebe7da796 100644
--- a/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.h
+++ b/windows/APIExample/APIExample/Advanced/ScreenShare/AgoraScreenCapture.h
@@ -83,6 +83,12 @@ class CScreenCaptureEventHandler : public IRtcEngineEventHandler
SDK triggers this callback.
*/
virtual void onRemoteVideoStateChanged(uid_t uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON reason, int elapsed) override;
+ /** Occurs when screencapture fail to filter window
+ *
+ *
+ * @param ScreenCaptureInfo
+ */
+ virtual void onScreenCaptureInfoUpdated(agora::rtc::ScreenCaptureInfo & info) override;
private:
HWND m_hMsgHanlder;
};
@@ -152,6 +158,7 @@ class CAgoraScreenCapture : public CDialogEx
afx_msg LRESULT OnEIDUserOffline(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnEIDRemoteVideoStateChanged(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnEIDLocalVideoStateChanged(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT OnEIDScreenCaptureInfoUpdated(WPARAM wParam, LPARAM lParam);
protected:
virtual void DoDataExchange(CDataExchange* pDX);
diff --git a/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp b/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp
index bbcef9ced..7069cfbf8 100644
--- a/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp
+++ b/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.cpp
@@ -129,6 +129,7 @@ void CLiveBroadcastingDlg::DoDataExchange(CDataExchange* pDX)
DDX_Control(pDX, IDC_BUTTON_IMAGE, m_btnImagePath);
DDX_Control(pDX, IDC_CHECK_ENABLE_BACKGROUND, m_chkEnableBackground);
DDX_Control(pDX, IDC_EDIT_IMAGE_PATH, m_edtImagePath);
+ DDX_Control(pDX, IDC_CHECK_REPORT, m_chkReport);
}
@@ -150,6 +151,18 @@ BEGIN_MESSAGE_MAP(CLiveBroadcastingDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_IMAGE, &CLiveBroadcastingDlg::OnBnClickedButtonImage)
ON_BN_CLICKED(IDC_CHECK_ENABLE_BACKGROUND, &CLiveBroadcastingDlg::OnBnClickedCheckEnableBackground)
ON_CBN_SELCHANGE(IDC_COMBO_BACKGROUND_TYPE, &CLiveBroadcastingDlg::OnSelchangeComboBackgroundType)
+
+
+ ON_MESSAGE(WM_MSGID(EID_NETWORK_QUALITY), &CLiveBroadcastingDlg::OnEIDNetworkQuality)
+ ON_MESSAGE(WM_MSGID(EID_RTC_STATS), &CLiveBroadcastingDlg::onEIDRtcStats)
+ ON_MESSAGE(WM_MSGID(EID_LOCAL_AUDIO_STATS), &CLiveBroadcastingDlg::onEIDLocalAudioStats)
+ ON_MESSAGE(WM_MSGID(EID_LOCAL_AUDIO_STATE_CHANED), &CLiveBroadcastingDlg::onEIDLocalAudioStateChanged)
+ ON_MESSAGE(WM_MSGID(EID_REMOTE_AUDIO_STATS), &CLiveBroadcastingDlg::onEIDRemoteAudioStats)
+ ON_MESSAGE(WM_MSGID(EID_REMOTE_AUDIO_STATE_CHANGED), &CLiveBroadcastingDlg::onEIDRemoteAudioStateChanged)
+ ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATS), &CLiveBroadcastingDlg::onEIDLocalVideoStats)
+ ON_MESSAGE(WM_MSGID(EID_LOCAL_VIDEO_STATE_CHANGED), &CLiveBroadcastingDlg::onEIDLocalVideoStateChanged)
+ ON_MESSAGE(WM_MSGID(EID_REMOTE_VIDEO_STATS), &CLiveBroadcastingDlg::onEIDRemoteVideoStats)
+ ON_BN_CLICKED(IDC_CHECK_REPORT, &CLiveBroadcastingDlg::OnBnClickedCheckReport)
END_MESSAGE_MAP()
@@ -833,3 +846,298 @@ void CLiveBroadcastingDlg::OnSelchangeComboBackgroundType()
m_btnImagePath.ShowWindow(SW_SHOW);
}
}
+
+LRESULT CLiveBroadcastingDlg::OnEIDNetworkQuality(WPARAM wParam, LPARAM lParam) {
+ PNetworkQuality quality = (PNetworkQuality)wParam;
+ CString strInfo = _T("===onNetworkQuality===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("uid:%u"), quality->uid);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txQuality:%d"), quality->txQuality);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxQuality:%u"), quality->rxQuality);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ if (quality) {
+ delete quality;
+ quality = nullptr;
+ }
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDRtcStats(WPARAM wParam, LPARAM lParam) {
+ RtcStats* stats = (RtcStats*)wParam;
+ CString strInfo = _T("===onRtcStats===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("duration:%u"), stats->duration);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txBytes:%u"), stats->txBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxBytes:%u"), stats->rxBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("txAudioBytes:%u"), stats->txAudioBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txVideoBytes:%u"), stats->txVideoBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("rxAudioBytes:%u"), stats->rxAudioBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxVideoBytes:%u"), stats->rxVideoBytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("txKBitRate:%u"), stats->txKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxKBitRate:%u"), stats->rxKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("rxAudioKBitRate:%u"), stats->rxAudioKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txAudioKBitRate:%u"), stats->txAudioKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("rxVideoKBitRate:%u"), stats->rxVideoKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txVideoKBitRate:%u"), stats->txVideoKBitRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("lastmileDelay:%u"), stats->lastmileDelay);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("userCount:%u"), stats->userCount);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("cpuAppUsage:%u"), stats->cpuAppUsage);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("cpuTotalUsage:%u"), stats->cpuTotalUsage);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+
+ strInfo.Format(_T("gatewayRtt:%u"), stats->gatewayRtt);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("memoryAppUsageRatio:%u"), stats->memoryAppUsageRatio);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("memoryTotalUsageRatio:%u"), stats->memoryTotalUsageRatio);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("memoryAppUsageInKbytes:%u"), stats->memoryAppUsageInKbytes);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+
+ strInfo.Format(_T("txPacketLossRate:%u"), stats->txPacketLossRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxPacketLossRate:%u"), stats->rxPacketLossRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+
+ if (stats) {
+ delete stats;
+ stats = nullptr;
+ }
+ return 0;
+}
+
+LRESULT CLiveBroadcastingDlg::onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam) {
+ LocalAudioStats* stats = (LocalAudioStats*)wParam;
+ CString strInfo = _T("===onLocalAudioStats===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("numChannels:%u"), stats->numChannels);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("sentSampleRate:%u"), stats->sentSampleRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("sentBitrate:%u"), stats->sentBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("txPacketLossRate:%u"), stats->txPacketLossRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+
+ if (stats) {
+ delete stats;
+ stats = nullptr;
+ }
+ return 0;
+}
+
+LRESULT CLiveBroadcastingDlg::onEIDLocalAudioStateChanged(WPARAM wParam, LPARAM lParam) {
+ LOCAL_AUDIO_STREAM_STATE state = (LOCAL_AUDIO_STREAM_STATE)wParam;
+ LOCAL_AUDIO_STREAM_ERROR error = (LOCAL_AUDIO_STREAM_ERROR)lParam;
+ CString strInfo = _T("===onLocalAudioStateChanged===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("state:%d"), state);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("error:%d"), error);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam) {
+ RemoteAudioStats* stats = (RemoteAudioStats*)wParam;
+ CString strInfo = _T("===onRemoteAudioStats===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("uid:%u"), stats->uid);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("quality:%d"), stats->quality);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("networkTransportDelay:%d"), stats->networkTransportDelay);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("jitterBufferDelay:%d"), stats->jitterBufferDelay);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("audioLossRate:%d"), stats->audioLossRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("numChannels:%d"), stats->numChannels);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("receivedSampleRate:%d"), stats->receivedSampleRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("receivedBitrate:%d"), stats->receivedBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("totalFrozenTime:%d"), stats->totalFrozenTime);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("frozenRate:%d"), stats->frozenRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("mosValue:%d"), stats->mosValue);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("totalActiveTime:%d"), stats->totalActiveTime);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("publishDuration:%d"), stats->publishDuration);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ if (stats) {
+ delete stats;
+ stats = nullptr;
+ }
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDRemoteAudioStateChanged(WPARAM wParam, LPARAM lParam) {
+ CString strInfo = _T("===onRemoteAudioStateChanged===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ PRemoteAudioState state = (PRemoteAudioState)wParam;
+
+ strInfo.Format(_T("elapsed:%d"), state->elapsed);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("uid:%u"), state->uid);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("state:%d"), state->state);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("reason:%d"), state->reason);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam) {
+ LocalVideoStats* stats = (LocalVideoStats*)wParam;
+ CString strInfo = _T("===onLocalVideoStats===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("sentBitrate:%d"), stats->sentBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("sentFrameRate:%d"), stats->sentFrameRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("encoderOutputFrameRate:%d"), stats->encoderOutputFrameRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("rendererOutputFrameRate:%d"), stats->rendererOutputFrameRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("targetBitrate:%d"), stats->targetBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("qualityAdaptIndication:%d"), stats->qualityAdaptIndication);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("encodedBitrate:%d"), stats->encodedBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("encodedFrameWidth:%d"), stats->encodedFrameWidth);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("encodedFrameHeight:%d"), stats->encodedFrameHeight);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("encodedFrameCount:%d"), stats->encodedFrameCount);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("codecType:%d"), stats->codecType);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ if (stats) {
+ delete stats;
+ stats = nullptr;
+ }
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDLocalVideoStateChanged(WPARAM wParam, LPARAM lParam) {
+
+ LOCAL_VIDEO_STREAM_STATE state = (LOCAL_VIDEO_STREAM_STATE)wParam;
+ LOCAL_VIDEO_STREAM_ERROR error = (LOCAL_VIDEO_STREAM_ERROR)lParam;
+ CString strInfo = _T("===onLocalVideoStateChanged===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("state:%d"), state);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("error:%d"), error);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam) {
+ RemoteVideoStats* stats = (RemoteVideoStats*)wParam;
+ CString strInfo = _T("===onRemoteVideoStats===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("uid:%u"), stats->uid);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("delay:%d"), stats->delay);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("width:%d"), stats->width);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("height:%d"), stats->height);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("receivedBitrate:%d"), stats->receivedBitrate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("decoderOutputFrameRate:%d"), stats->decoderOutputFrameRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("rendererOutputFrameRate:%d"), stats->rendererOutputFrameRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("packetLossRate:%d"), stats->packetLossRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("rxStreamType:%d"), stats->rxStreamType);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("totalFrozenTime:%d"), stats->totalFrozenTime);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("frozenRate:%d"), stats->frozenRate);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ strInfo.Format(_T("totalActiveTime:%d"), stats->totalActiveTime);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("publishDuration:%d"), stats->publishDuration);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+
+ if (stats) {
+ delete stats;
+ stats = nullptr;
+ }
+ return 0;
+}
+LRESULT CLiveBroadcastingDlg::onEIDRemoteVideoStateChanged(WPARAM wParam, LPARAM lParam) {
+ CString strInfo = _T("===onRemoteVideoStateChanged===");
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ PRemoteVideoState state = (PRemoteVideoState)wParam;
+
+ strInfo.Format(_T("elapsed:%d"), state->elapsed);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("uid:%u"), state->uid);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("state:%d"), state->state);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ strInfo.Format(_T("reason:%d"), state->reason);
+ m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
+ return 0;
+}
+
+void CLiveBroadcastingDlg::OnBnClickedCheckReport()
+{
+ m_eventHandler.SetReport(m_chkReport.GetCheck() != 0);
+}
diff --git a/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.h b/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.h
index c8a676704..00596dc4a 100644
--- a/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.h
+++ b/windows/APIExample/APIExample/Basic/LiveBroadcasting/CLiveBroadcastingDlg.h
@@ -69,8 +69,102 @@ class CLiveBroadcastingRtcEngineEventHandler
virtual void onLeaveChannel(const RtcStats& stats) override;
virtual void onAudioDeviceStateChanged(const char* deviceId, int deviceType, int deviceState) override;
+
+ virtual void onNetworkQuality(uid_t uid, int txQuality, int rxQuality) override {
+ if (m_hMsgHanlder&& report) {
+ PNetworkQuality quality = new NetworkQuality;
+ quality->uid = uid;
+ quality->txQuality = txQuality;
+ quality->txQuality = rxQuality;
+
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_NETWORK_QUALITY), (WPARAM)quality, 0);
+
+ }
+ }
+ virtual void onRtcStats(const RtcStats& stats) override {
+ if (m_hMsgHanlder&& report) {
+ RtcStats* s = new RtcStats;
+ *s = stats;
+
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_RTC_STATS), (WPARAM)s, 0);
+
+ }
+ }
+
+
+ virtual void onLocalAudioStats(const LocalAudioStats& stats) override {
+ if (m_hMsgHanlder&& report) {
+ LocalAudioStats* s = new LocalAudioStats;
+ *s = stats;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_AUDIO_STATS), (WPARAM)s, 0);
+
+ }
+ }
+
+ virtual void onLocalAudioStateChanged(LOCAL_AUDIO_STREAM_STATE state, LOCAL_AUDIO_STREAM_ERROR error) {
+ if (m_hMsgHanlder&& report) {
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_AUDIO_STATE_CHANED), (WPARAM)state, (LPARAM)error);
+ }
+ }
+
+ virtual void onRemoteAudioStats(const RemoteAudioStats& stats) {
+ if (m_hMsgHanlder&& report) {
+ RemoteAudioStats* s = new RemoteAudioStats;
+ *s = stats;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_AUDIO_STATS), (WPARAM)s, 0);
+
+ }
+ }
+
+ virtual void onRemoteAudioStateChanged(uid_t uid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason, int elapsed) {
+ if (m_hMsgHanlder&& report) {
+ PRemoteAudioState s = new RemoteAudioState;
+ s->elapsed = elapsed;
+ s->uid = uid;
+ s->state = state;
+ s->reason = reason;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_AUDIO_STATE_CHANGED), (WPARAM)s, 0);
+
+ }
+ }
+ virtual void onLocalVideoStats(const LocalVideoStats& stats) {
+ if (m_hMsgHanlder&& report) {
+ LocalVideoStats* s = new LocalVideoStats;
+ *s = stats;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_VIDEO_STATS), (WPARAM)s, 0);
+
+ }
+ }
+
+ virtual void onLocalVideoStateChanged(LOCAL_VIDEO_STREAM_STATE state, LOCAL_VIDEO_STREAM_ERROR error) {
+ if (m_hMsgHanlder&& report) {
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_LOCAL_VIDEO_STATE_CHANGED), (WPARAM)state, (LPARAM)error);
+ }
+ }
+ virtual void onRemoteVideoStats(const RemoteVideoStats& stats) {
+ if (m_hMsgHanlder&& report) {
+ RemoteVideoStats* s = new RemoteVideoStats;
+ *s = stats;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_VIDEO_STATS), (WPARAM)s, 0);
+
+ }
+ }
+
+ virtual void onRemoteVideoStateChanged(uid_t uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON reason, int elapsed) {
+ if (m_hMsgHanlder&& report) {
+ PRemoteVideoState s = new RemoteVideoState;
+ s->elapsed = elapsed;
+ s->uid = uid;
+ s->state = state;
+ s->reason = reason;
+ ::PostMessage(m_hMsgHanlder, WM_MSGID(EID_REMOTE_VIDEO_STATE_CHANED), (WPARAM)s, 0);
+
+ }
+ }
+ void SetReport(bool b) { report = b; }
private:
HWND m_hMsgHanlder;
+ bool report = false;
};
class CLiveBroadcastingDlg : public CDialogEx
@@ -112,6 +206,16 @@ class CLiveBroadcastingDlg : public CDialogEx
afx_msg LRESULT OnEIDUserJoined(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnEIDUserOffline(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnEIDAudioDeviceStateChanged(const char* deviceId, int deviceType, int deviceState);
+ afx_msg LRESULT OnEIDNetworkQuality(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDRtcStats(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDLocalAudioStats(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDLocalAudioStateChanged(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDRemoteAudioStats(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDRemoteAudioStateChanged(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDLocalVideoStats(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDLocalVideoStateChanged(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDRemoteVideoStats(WPARAM wParam, LPARAM lParam);
+ afx_msg LRESULT onEIDRemoteVideoStateChanged(WPARAM wParam, LPARAM lParam);
private:
//set control text from config.
void InitCtrlText();
@@ -172,4 +276,6 @@ class CLiveBroadcastingDlg : public CDialogEx
CButton m_chkEnableBackground;
afx_msg void OnSelchangeComboBackgroundType();
CEdit m_edtImagePath;
+ afx_msg void OnBnClickedCheckReport();
+ CButton m_chkReport;
};
diff --git a/windows/APIExample/APIExample/RtcChannelHelperPlugin/AgoraRtcChannelPublishHelper.h b/windows/APIExample/APIExample/RtcChannelHelperPlugin/AgoraRtcChannelPublishHelper.h
index cf08935e3..5cad80b99 100644
--- a/windows/APIExample/APIExample/RtcChannelHelperPlugin/AgoraRtcChannelPublishHelper.h
+++ b/windows/APIExample/APIExample/RtcChannelHelperPlugin/AgoraRtcChannelPublishHelper.h
@@ -16,8 +16,8 @@ class AgoraRtcChannelPublishHelperObserver : public agora::rtc::IMediaPlayerObse
* @param state New player state
* @param ec Player error message
*/
- virtual void onPlayerStateChanged(agora::media::MEDIA_PLAYER_STATE state,
- agora::media::MEDIA_PLAYER_ERROR ec)
+ virtual void onPlayerStateChanged(agora::media::base::MEDIA_PLAYER_STATE state,
+ agora::media::base::MEDIA_PLAYER_ERROR ec)
{
}
@@ -36,7 +36,7 @@ class AgoraRtcChannelPublishHelperObserver : public agora::rtc::IMediaPlayerObse
*
* @param event
*/
- virtual void onPlayerEvent(agora::media::MEDIA_PLAYER_EVENT event)
+ virtual void onPlayerEvent(agora::media::base::MEDIA_PLAYER_EVENT event)
{
};
@@ -48,7 +48,7 @@ class AgoraRtcChannelPublishHelperObserver : public agora::rtc::IMediaPlayerObse
* @param data data
* @param length data length
*/
- virtual void onMetadata(agora::media::MEDIA_PLAYER_METADATA_TYPE type, const uint8_t* data,
+ virtual void onMetadata(agora::media::base::MEDIA_PLAYER_METADATA_TYPE type, const uint8_t* data,
uint32_t length)
{
diff --git a/windows/APIExample/APIExample/dsound/DSoundRender.cpp b/windows/APIExample/APIExample/dsound/DSoundRender.cpp
index 8a0b1a2a3..3786ca241 100644
--- a/windows/APIExample/APIExample/dsound/DSoundRender.cpp
+++ b/windows/APIExample/APIExample/dsound/DSoundRender.cpp
@@ -79,7 +79,7 @@ void DSoundRender::Render(BYTE * buffer, int buffer_len)
#ifdef _DEBUG
TCHAR buffer[1024];
#ifdef _UNICODE
- swprintf(buffer, _T("offset:%d ,data_len:%d\n"), offset, buffer_len);
+ swprintf_s(buffer, 1024, _T("offset:%d ,data_len:%d\n"), offset, buffer_len);
#else
sprintf(buffer, _T("offset:%d ,data_len:%d\n"), offset, buffer_len);
#endif // _UNICODE
diff --git a/windows/APIExample/APIExample/resource.h b/windows/APIExample/APIExample/resource.h
index 09cc9c968..d5851de87 100644
--- a/windows/APIExample/APIExample/resource.h
+++ b/windows/APIExample/APIExample/resource.h
@@ -1,6 +1,6 @@
//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by APIExample.rc
+// Microsoft Visual C++ 生成的包含文件。
+// 供 APIExample.rc 使用
//
#define IDM_ABOUTBOX 0x0010
#define IDD_ABOUTBOX 100
@@ -12,8 +12,8 @@
#define IDD_DIALOG_SCREEN_SHARE 134
#define IDD_DIALOG_CUSTOM_CAPTURE_VIDEO 135
#define IDD_DIALOG_CUSTOM_CAPTURE_AUDIO 136
-#define IDD_DIALOG_BEAUTY 137
#define IDB_BITMAP_NETWORK_STATE 137
+#define IDD_DIALOG_BEAUTY 137
#define IDD_DIALOG_AUDIO_PROFILE 138
#define IDR_TEST_WAVE 138
#define IDD_DIALOG_BEAUTY_AUDIO 139
@@ -57,7 +57,6 @@
#define IDC_BUTTON1 1021
#define IDC_BUTTON_JOINCHANNEL 1021
#define IDC_STATIC_SENDSEI 1022
-#define IDC_EDIT_LIGHTENING 1022
#define IDC_EDIT_AUDIO_MIX_PATH 1022
#define IDC_STATIC_FPS 1022
#define IDC_BUTTON_SET_AUDIO_PROC 1022
@@ -69,7 +68,6 @@
#define IDC_COMBO_PERSONS2 1022
#define IDC_COMBO_AUDIENCE_LATENCY 1022
#define IDC_EDIT_SEI 1023
-#define IDC_EDIT_BEAUTY_REDNESS 1023
#define IDC_EDIT_AUDIO_REPEAT_TIMES 1023
#define IDC_EDIT_FPS 1023
#define IDC_EDIT_VIDEO_SOURCE 1023
@@ -77,7 +75,6 @@
#define IDC_STATIC_AUDIENCE_LATENCY 1023
#define IDC_BUTTON_ADDSTREAM 1024
#define IDC_BUTTON_SEND 1024
-#define IDC_EDIT_BEAUTY_SMOOTHNESS 1024
#define IDC_STATIC_BITRATE 1024
#define IDC_BUTTON_OPEN 1024
#define IDC_EDIT_VIDEO_FPS 1024
@@ -109,9 +106,9 @@
#define IDC_COMBO_SCREEN_CAPTURE 1042
#define IDC_BUTTON_START_CAPUTRE 1043
#define IDC_STATIC_CAPTUREDEVICE 1044
-#define IDC_STATIC_BEAUTY_LIGHTENING 1044
#define IDC_BUTTON_SHARE_DESKTOP 1044
#define IDC_STATIC_SCREEN_SHARE 1044
+#define IDC_STATIC_BEAUTY_LIGHTENING 1044
#define IDC_COMBO_CAPTURE_VIDEO_DEVICE 1045
#define IDC_COMBO_SCREEN_SCREEN 1045
#define IDC_BUTTON_RENDER_AUDIO 1045
@@ -123,21 +120,21 @@
#define IDC_STATIC_SDKCAMERA 1047
#define IDC_COMBO_CAPTURE_AUDIO_TYPE 1048
#define IDC_COMBO_SDKCAMERA 1048
-#define IDC_STATIC_BEAUTY_LIGHTENING_CONTRAST_LEVEL 1049
#define IDC_COMBO_SDK_RESOLUTION 1049
+#define IDC_STATIC_BEAUTY_LIGHTENING_CONTRAST_LEVEL 1049
#define IDC_COMBO_BEAUTE_LIGHTENING_CONTRAST_LEVEL 1050
#define IDC_STATIC_BEAUTY_REDNESS 1051
-#define IDC_STATIC_BEAUTY_SMOOTHNESS 1052
#define IDC_STATIC_CAPTURE_TYPE 1052
+#define IDC_STATIC_BEAUTY_SMOOTHNESS 1052
#define IDC_COMBO_SDKCAMERA2 1053
#define IDC_CMB_MEDIO_CAPTURETYPE 1053
#define IDC_CHECK1 1054
-#define IDC_CHECK_BEAUTY_ENABLE 1054
#define IDC_CHK_ONLY_LOCAL 1054
#define IDC_CHECK_CURSOR 1054
#define IDC_CHK_TRANS_CODING 1054
#define IDC_CHECK_LOOPBACK 1054
#define IDC_CHECK_PUBLISH_AUDIO 1054
+#define IDC_CHECK_BEAUTY_ENABLE 1054
#define IDC_STATIC_ADUIO_PROFILE 1055
#define IDC_CHK_REPLACE_MICROPHONE 1055
#define IDC_CHECK_PUBLISH_VIDEO 1055
@@ -194,19 +191,31 @@
#define IDC_BUTTON_SET_MEDIA_ENCRYPT 1088
#define IDC_STATIC_ENCRYPT_KEY 1089
#define IDC_CHECK_WINDOW_FOCUS 1090
+#define IDC_STATIC_BEaUTY 1090
#define IDC_COMBO_FPS 1091
+#define IDC_CHECK_ENHANCE 1091
#define IDC_STATIC_AUDIO_EFFECT_PATH 1092
+#define IDC_SLIDER_STRENGTH 1092
#define IDC_EDIT_AUDIO_EFFECT_PATH 1093
+#define IDC_STATIC_STRENTH 1093
#define IDC_SPIN1 1094
#define IDC_SPIN_AGIN 1094
+#define IDC_STATIC_SKIN_PROTECT 1094
#define IDC_STATIC_AUDIO_PITCH 1095
+#define IDC_SLIDER_SKIN_PROTECT 1095
#define IDC_SPIN2 1096
#define IDC_SPIN_PITCH 1096
+#define IDC_CHECK_VIDEO_DENOISE 1096
#define IDC_STATIC_AUDIO_PAN 1097
+#define IDC_SLIDER_REDNESS 1097
#define IDC_COMBO_PAN 1098
+#define IDC_SLIDER_LIGHTENING 1098
#define IDC_CHK_PUBLISH 1099
+#define IDC_STATIC_STRENTH2 1099
#define IDC_BUTTON_ADD_EFFECT 1100
+#define IDC_CHECK_VIDEO_DENOISE2 1100
#define IDC_STATIC_AUDIO_EFFECT 1101
+#define IDC_SLIDER_SMOOTHNESS 1101
#define IDC_COMBO2 1102
#define IDC_BUTTON_REMOVE 1103
#define IDC_BUTTON_PRELOAD 1104
@@ -301,6 +310,8 @@
#define IDC_EDIT1 1179
#define IDC_EDIT_IMAGE_PATH 1180
#define IDC_BUTTON_ECHO_TEST2 1181
+#define IDC_CHECK_ 1182
+#define IDC_CHECK_REPORT 1182
// Next default values for new objects
//
@@ -308,7 +319,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 139
#define _APS_NEXT_COMMAND_VALUE 32771
-#define _APS_NEXT_CONTROL_VALUE 1182
+#define _APS_NEXT_CONTROL_VALUE 1183
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/windows/APIExample/APIExample/stdafx.h b/windows/APIExample/APIExample/stdafx.h
index e20bab258..c7e7371aa 100644
--- a/windows/APIExample/APIExample/stdafx.h
+++ b/windows/APIExample/APIExample/stdafx.h
@@ -88,6 +88,7 @@ using namespace agora::media;
#define EID_AUDIO_DEVICE_STATE_CHANGED 0x00000019
#define EID_RTMP_STREAM_EVENT 0x00000020
+#define EID_SCREEN_CAPTURE_INFO_UPDATED 0x00000021
typedef struct _StreamPublished {
char* url;
int error;
@@ -110,6 +111,7 @@ typedef struct _tagVideoStateStateChanged {
REMOTE_VIDEO_STATE_REASON reason;
}VideoStateStateChanged, *PVideoStateStateChanged;
+
std::string cs2utf8(CString str);
CString utf82cs(std::string utf8);
CString getCurrentTime();
@@ -142,6 +144,32 @@ typedef struct _AGE_SCREENSHARE_START
HWND hWnd;
}AGE_SCREENSHARE_START, *PAGE_SCREENSHARE_START, *LPAGE_SCREENSHARE_START;
+typedef struct _tagNetworkQuality {
+ uid_t uid;
+ int txQuality;
+ int rxQuality;
+}NetworkQuality, *PNetworkQuality;
+
+typedef struct _tagRemoteAudioState {
+ uid_t uid;
+ REMOTE_AUDIO_STATE state;
+ REMOTE_AUDIO_STATE_REASON reason;
+ int elapsed;
+}RemoteAudioState, *PRemoteAudioState;
+
+typedef struct _tagRemoteVideoState {
+ uid_t uid;
+ REMOTE_VIDEO_STATE state;
+ REMOTE_VIDEO_STATE_REASON reason;
+ int elapsed;
+}RemoteVideoState, *PRemoteVideoState;
+
+#define EID_NETWORK_QUALITY 0x00000022
+
+#define EID_LOCAL_AUDIO_STATS 0x00000024
+#define EID_LOCAL_AUDIO_STATE_CHANED 0x00000025
+#define EID_REMOTE_AUDIO_STATE_CHANGED 0x00000027
+
#define EID_SCREENSHARE_START 0x00000022
#define EID_SCREENSHARE_STOP 0x00000023
#define EID_SCREENSHARE_CLOSE 0x00000024
diff --git a/windows/APIExample/install.ps1 b/windows/APIExample/install.ps1
index 848ca43bf..fb225abe9 100644
--- a/windows/APIExample/install.ps1
+++ b/windows/APIExample/install.ps1
@@ -1,10 +1,14 @@
$ThirdPartysrc = 'https://agora-adc-artifacts.oss-cn-beijing.aliyuncs.com/libs/ThirdParty.zip'
$ThirdPartydes = 'ThirdParty.zip'
-$agora_sdk = 'https://download.agora.io/sdk/release/Agora_Native_SDK_for_Windows_v3_5_0_3_FULL.zip'
+$agora_sdk = 'https://download.agora.io/sdk/release/Agora_Native_SDK_for_Windows_v3_6_1_1_FULL.zip'
+$agora_sdk = ''
$agora_des = 'Agora_Native_SDK_for_Windows.zip'
-$MediaPlayerSDK = 'https://download.agora.io/sdk/release/Agora_Media_Player_for_Windows_x86_32597_20200923_2306.zip'
+$MediaPlayerSDK = 'https://download.agora.io/sdk/release/Agora_Media_Player_for_Windows_x86_rel.v1.3.0_63393_ffmpeg_player_lite_20210727_1117.zip'
+$MediaPlayerSDK64 = 'https://download.agora.io/sdk/release/Agora_Media_Player_for_Windows_x64_rel.v1.3.0_63392_ffmpeg_player_lite_20210727_1117.zip'
$MediaPlayerDes = 'MediaPlayerPartSave.zip'
+$MediaPlayerDes64 = 'MediaPlayerPartSave.zip'
+$arch = $args[0]
if (-not (Test-Path ThirdParty)){
echo "download $ThirdPartydes"
@@ -27,15 +31,26 @@ if (-not (Test-Path libs)){
Remove-Item Agora_Native_SDK_for_Windows_FULL -Recurse
}
-
-if (-not (Test-Path MediaPlayerPart)){
- echo "download $MediaPlayerSDK"
- mkdir MediaPlayerPart
- (New-Object System.Net.WebClient).DownloadFile($MediaPlayerSDK,$MediaPlayerDes)
- Unblock-File $MediaPlayerDes
- Expand-Archive -Path $MediaPlayerDes -DestinationPath . -Force
- Move-Item Agora_Media_Player_for_Windows_x86_tongjiangyong_32597_20200923_2306\sdk\* MediaPlayerPart
- Remove-Item $MediaPlayerDes -Recurse
- Remove-Item Agora_Media_Player_for_Windows_x86_tongjiangyong_32597_20200923_2306 -Recurse
-}
-
+if($arch -eq 'x64'){
+ if (-not (Test-Path MediaPlayerPart64)){
+ echo "download $MediaPlayerSDK64"
+ mkdir MediaPlayerPart64
+ (New-Object System.Net.WebClient).DownloadFile($MediaPlayerSDK64,$MediaPlayerDes)
+ Unblock-File $MediaPlayerDes
+ Expand-Archive -Path $MediaPlayerDes -DestinationPath . -Force
+ Move-Item Agora_Media_Player_for_Windows_x64_rel.v1.3.0_63392_ffmpeg_player_lite_20210727_1117\sdk\* MediaPlayerPart64
+ Remove-Item $MediaPlayerDes -Recurse
+ Remove-Item Agora_Media_Player_for_Windows_x64_rel.v1.3.0_63392_ffmpeg_player_lite_20210727_1117 -Recurse
+ }
+}else{
+ if (-not (Test-Path MediaPlayerPart)){
+ echo "download $MediaPlayerSDK"
+ mkdir MediaPlayerPart
+ (New-Object System.Net.WebClient).DownloadFile($MediaPlayerSDK,$MediaPlayerDes)
+ Unblock-File $MediaPlayerDes
+ Expand-Archive -Path $MediaPlayerDes -DestinationPath . -Force
+ Move-Item Agora_Media_Player_for_Windows_x86_rel.v1.3.0_63393_ffmpeg_player_lite_20210727_1117\sdk\* MediaPlayerPart
+ Remove-Item $MediaPlayerDes -Recurse
+ Remove-Item Agora_Media_Player_for_Windows_x86_rel.v1.3.0_63393_ffmpeg_player_lite_20210727_1117 -Recurse
+ }
+}
\ No newline at end of file
diff --git a/windows/APIExample/installThirdParty.bat b/windows/APIExample/installThirdParty.bat
index 003ad0881..568cb2f97 100644
--- a/windows/APIExample/installThirdParty.bat
+++ b/windows/APIExample/installThirdParty.bat
@@ -7,4 +7,4 @@ if not exist .\libs (
)
powershell.exe -command ^
- "& {set-executionpolicy Remotesigned -Scope Process; ./'install.ps1'}"
+ "& {set-executionpolicy Remotesigned -Scope Process; ./'install.ps1' '%1'}"
diff --git a/windows/APIExample/installThirdParty_x64.bat b/windows/APIExample/installThirdParty_x64.bat
new file mode 100644
index 000000000..d76beb098
--- /dev/null
+++ b/windows/APIExample/installThirdParty_x64.bat
@@ -0,0 +1,10 @@
+cd /d %~dp0
+
+if not exist .\libs (
+ if exist ..\..\..\libs (
+ echo d | xcopy ..\..\..\libs .\libs /Y /E /Q
+ )
+)
+
+powershell.exe -command ^
+ "& {set-executionpolicy Remotesigned -Scope Process; ./'install.ps1' 'x64'}"
diff --git a/windows/APIExample/installThirdParty_x86.bat b/windows/APIExample/installThirdParty_x86.bat
new file mode 100644
index 000000000..40901bca5
--- /dev/null
+++ b/windows/APIExample/installThirdParty_x86.bat
@@ -0,0 +1,10 @@
+cd /d %~dp0
+
+if not exist .\libs (
+ if exist ..\..\..\libs (
+ echo d | xcopy ..\..\..\libs .\libs /Y /E /Q
+ )
+)
+
+powershell.exe -command ^
+ "& {set-executionpolicy Remotesigned -Scope Process; ./'install.ps1' 'x86'}"
diff --git a/windows/README.md b/windows/README.md
index b2e1021ce..d5aee1a12 100644
--- a/windows/README.md
+++ b/windows/README.md
@@ -50,9 +50,9 @@ The project uses a single program to combine a variety of functionalities. Each
1. Navigate to the **windows** folder and run following command to install project dependencies:
```shell
- $ installThirdParty.bat
+ $ installThirdParty_x86.bat or installThirdParty_x64.bat. You can also go to next step. It will download depdencies when build solution.
```
-
+
**Note:**
If you encounter ps1 script errors, you may need to update your powershell.
diff --git a/windows/README.zh.md b/windows/README.zh.md
index 41e8dd2bc..09edd9392 100644
--- a/windows/README.zh.md
+++ b/windows/README.zh.md
@@ -53,7 +53,7 @@ _[English](README.md) | 涓枃_
1. 鍦 **windows** 鐩綍涓嬭繍琛 `installThirdParty.bat` 鏂囦欢瀹夎渚濊禆椤:
```shell
- $ installThirdParty.bat
+ $ installThirdParty_x86.bat 鎴栬卛nstallThirdParty_x64.bat銆備篃鍙互鐩存帴鍒颁笅涓姝ワ紝褰揵uild solution鐨勬椂鍊欎細鐩存帴涓嬭浇渚濊禆搴撱
```
**娉ㄦ剰:**