1.拷贝相关dll到bin目录
2.项目添加agorartc的引用
3.自定义EventHandler
internal class CustomEventHandler : IAgoraRtcEngineEventHandler
{
public override void OnWarning(int warn, string msg)
{
Console.WriteLine("OnWarning {0} {1}", warn, msg);
}
public override void one rror(int error, string msg)
{
Console.WriteLine("=====>OnError {0} {1}", error, msg);
}
public override void OnJoinChannelSuccess(string channel, uint uid, int elapsed)
{
Console.WriteLine("----->OnJoinChannelSuccess, channel={0}, uid={1}", channel, uid);
//var video_canvas = new VideoCanvas((ulong)CSharpForm.local_win_id, 0, "123");
//int ret = CSharpForm.rtc_engine.SetupLocalVideo(video_canvas);
//ret = CSharpForm.rtc_engine.StartPreview();
//Console.ReadLine();
//ret = rtc_engine.StopPreview();
}
public override void OnRejoinChannelSuccess(string channel, uint uid, int elapsed)
{
Console.WriteLine("OnRejoinChannelSuccess");
}
public override void OnConnectionLost()
{
Console.WriteLine("OnConnectionLost");
}
public override void OnLeaveChannel(RtcStats stats)
{
Console.WriteLine("----->OnLeaveChannel, duration={0}", stats.duration);
}
public override void OnRequestToken()
{
Console.WriteLine("OnRequestToken");
}
public override void OnAudioSubscribeStateChanged(string channel, uint uid, STREAM_SUBSCRIBE_STATE oldState,
STREAM_SUBSCRIBE_STATE newState, int elapseSinceLastState)
{
Console.WriteLine("OnAudioSubscribeStateChanged");
}
public override void OnFacePositionChanged(int imageWidth, int imageHeight, agora.rtc.Rectangle vecRectangle,
int[] vecDistance, int numFaces)
{
Console.WriteLine("OnFacePositionChanged");
}
public override void OnUserJoined(uint uid, int elapsed)
{
Console.WriteLine("----->OnUserJoined, uid={0}", uid);
// todo
}
public override void OnUserOffline(uint uid, USER_OFFLINE_REASON_TYPE reason)
{
Console.WriteLine("----->OnUserOffline");
}
public override void OnAudioVolumeIndication(AudioVolumeInfo[] speakers, uint speakerNumber, int totalVolume)
{
Console.WriteLine("OnAudioVolumeIndication");
}
public override void OnUserMuteAudio(uint uid, bool muted)
{
Console.WriteLine("OnUserMuteAudio");
}
public override void OnRtcStats(RtcStats stats)
{
Console.WriteLine("OnRtcStats");
}
public override void OnAudioRouteChanged(AUDIO_ROUTE_TYPE routing)
{
Console.WriteLine("OnAudioRouteChanged");
}
public override void OnFirstRemoteVideoDecoded(uint uid, int width, int height, int elapsed)
{
Console.WriteLine("OnFirstRemoteVideoDecoded");
}
public override void OnVideoSizeChanged(uint uid, int width, int height, int rotation)
{
Console.WriteLine("OnVideoSizeChanged");
}
public override void OnClientRoleChanged(CLIENT_ROLE_TYPE oldRole, CLIENT_ROLE_TYPE newRole)
{
Console.WriteLine("OnClientRoleChanged");
}
public override void OnUserMuteVideo(uint uid, bool muted)
{
Console.WriteLine("OnUserMuteVideo");
}
public override void OnApiCallExecuted(int err, string api, string result)
{
Console.WriteLine("OnApiCallExecuted, err:{0}, result: {1}", err, result);
}
public override void OnFirstLocalAudioFramePublished(int elapsed)
{
Console.WriteLine("OnFirstLocalAudioFramePublished");
}
public override void OnLastmileQuality(int quality)
{
Console.WriteLine("OnLastmileQuality");
}
public override void OnStreamInjectedStatus(string url, uint uid, int status)
{
Console.WriteLine("OnStreamInjectedStatus");
}
public override void OnStreamMessageError(uint uid, int streamId, int code, int missed, int cached)
{
Console.WriteLine("OnStreamMessageError");
}
public override void OnStreamMessage(uint uid, int streamId, byte[] data, uint length)
{
Console.WriteLine("OnStreamMessage");
}
public override void OnTranscodingUpdated()
{
Console.WriteLine("OnTranscodingUpdated");
}
public override void OnAudioDeviceVolumeChanged(MEDIA_DEVICE_TYPE deviceType, int volume, bool muted)
{
Console.WriteLine("OnAudioDeviceVolumeChanged");
}
public override void OnActiveSpeaker(uint uid)
{
Console.WriteLine("OnActiveSpeaker");
}
public override void OnMediaEngineStartCallSuccess()
{
Console.WriteLine("OnMediaEngineStartCallSuccess");
}
public override void OnUserSuperResolutionEnabled(uint uid, bool enabled, SUPER_RESOLUTION_STATE_REASON reason)
{
Console.WriteLine("OnUserSuperResolutionEnabled");
}
public override void OnMediaEngineLoadSuccess()
{
Console.WriteLine("OnMediaEngineLoadSuccess");
}
public override void OnTokenPrivilegeWillExpire(string token)
{
Console.WriteLine("OnTokenPrivilegeWillExpire");
}
public override void OnNetworkQuality(uint uid, int txQuality, int rxQuality)
{
Console.WriteLine("OnNetworkQuality");
}
public override void OnLocalVideoStats(LocalVideoStats stats)
{
Console.WriteLine("OnLocalVideoStats");
}
public override void OnRemoteVideoStats(RemoteVideoStats stats)
{
Console.WriteLine("OnRemoteVideoStats");
}
public override void OnRemoteAudioStats(RemoteAudioStats stats)
{
Console.WriteLine("OnRemoteAudioStats");
}
public override void OnLocalAudioStats(LocalAudioStats stats)
{
Console.WriteLine("OnLocalAudioStats");
}
public override void OnFirstLocalVideoFrame(int width, int height, int elapsed)
{
Console.WriteLine("OnFirstLocalVideoFrame");
}
public override void OnFirstLocalVideoFramePublished(int elapsed)
{
Console.WriteLine("OnFirstLocalVideoFramePublished");
}
public override void OnFirstRemoteVideoFrame(uint uid, int width, int height, int elapsed)
{
Console.WriteLine("OnFirstRemoteVideoFrame");
}
public override void OnUserEnableVideo(uint uid, bool enabled)
{
Console.WriteLine("OnUserEnableVideo");
}
public override void OnAudioDeviceStateChanged(string deviceId, int deviceType, int deviceState)
{
Console.WriteLine("OnAudioDeviceStateChanged");
}
public override void OnCameraFocusAreaChanged(int x, int y, int width, int height)
{
Console.WriteLine("OnCameraFocusAreaChanged");
}
public override void OnCameraExposureAreaChanged(int x, int y, int width, int height)
{
Console.WriteLine("OnCameraExposureAreaChanged");
}
public override void OnRemoteAudioMixingBegin()
{
Console.WriteLine("OnRemoteAudioMixingBegin");
}
public override void OnRemoteAudioMixingEnd()
{
Console.WriteLine("OnRemoteAudioMixingEnd");
}
public override void OnAudioEffectFinished(int soundId)
{
Console.WriteLine("OnAudioEffectFinished");
}
public override void OnVideoDeviceStateChanged(string deviceId, int deviceType, int deviceState)
{
Console.WriteLine("OnVideoDeviceStateChanged");
}
public override void OnRemoteVideoStateChanged(uint uid, REMOTE_VIDEO_STATE state,
REMOTE_VIDEO_STATE_REASON reason, int elapsed)
{
Console.WriteLine("OnRemoteVideoStateChanged");
}
public override void OnUserEnableLocalVideo(uint uid, bool enabled)
{
Console.WriteLine("OnUserEnableLocalVideo");
}
public override void OnLocalPublishFallbackToAudioOnly(bool isFallbackOrRecover)
{
Console.WriteLine("OnLocalPublishFallbackToAudioOnly");
}
public override void OnRemoteSubscribeFallbackToAudioOnly(uint uid, bool isFallbackOrRecover)
{
Console.WriteLine("OnRemoteSubscribeFallbackToAudioOnly");
}
public override void OnConnectionStateChanged(CONNECTION_STATE_TYPE state, CONNECTION_CHANGED_REASON_TYPE reason)
{
Console.WriteLine("OnConnectionStateChanged");
}
public override void OnRtmpStreamingStateChanged(string url, RTMP_STREAM_PUBLISH_STATE state,
RTMP_STREAM_PUBLISH_ERROR errCode)
{
Console.WriteLine("OnRtmpStreamingStateChanged");
}
public override void OnLocalUserRegistered(uint uid, string userAccount)
{
Console.WriteLine("OnLocalUserRegistered");
}
public override void OnUserInfoUpdated(uint uid, UserInfo info)
{
Console.WriteLine("OnUserInfoUpdated");
}
public override void OnLocalAudioStateChanged(LOCAL_AUDIO_STREAM_STATE state, LOCAL_AUDIO_STREAM_ERROR error)
{
Console.WriteLine("OnLocalAudioStateChanged");
}
public override void OnRemoteAudioStateChanged(uint uid, REMOTE_AUDIO_STATE state,
REMOTE_AUDIO_STATE_REASON reason, int elapsed)
{
Console.WriteLine("OnRemoteAudioStateChanged");
}
public override void OnAudioPublishStateChanged(string channel, STREAM_PUBLISH_STATE oldState,
STREAM_PUBLISH_STATE newState, int elapseSinceLastState)
{
Console.WriteLine("OnAudioPublishStateChanged");
}
public override void OnVideoPublishStateChanged(string channel, STREAM_PUBLISH_STATE oldState,
STREAM_PUBLISH_STATE newState, int elapseSinceLastState)
{
Console.WriteLine("OnVideoPublishStateChanged");
}
public override void OnAudioMixingStateChanged(AUDIO_MIXING_STATE_TYPE audioMixingStateType,
AUDIO_MIXING_REASON_TYPE reason)
{
Console.WriteLine("OnAudioMixingStateChanged");
}
public override void OnLocalVideoStateChanged(LOCAL_VIDEO_STREAM_STATE localVideoState,
LOCAL_VIDEO_STREAM_ERROR error)
{
Console.WriteLine("OnLocalVideoStateChanged");
}
public override void OnNetworkTypeChanged(NETWORK_TYPE networkType)
{
Console.WriteLine("OnNetworkTypeChanged");
}
public override void OnLastmileProbeResult(LastmileProbeResult result)
{
Console.WriteLine("OnLastmileProbeResult");
}
public override void OnChannelMediaRelayStateChanged(CHANNEL_MEDIA_RELAY_STATE state,
CHANNEL_MEDIA_RELAY_ERROR code)
{
Console.WriteLine("OnChannelMediaRelayStateChanged");
}
public override void OnChannelMediaRelayEvent(CHANNEL_MEDIA_RELAY_EVENT code)
{
Console.WriteLine("OnChannelMediaRelayEvent");
}
}
4.自定义FrameObserver
public class VideoFrameObserver : IAgoraRtcVideoFrameObserver
{
public Action OnLocalVideoBitmapInitialized;
public override VIDEO_FRAME_TYPE GetVideoFormatPreference()
{
return VIDEO_FRAME_TYPE.FRAME_TYPE_RGBA;
}
public void ClearBitmap()
{
_drawBitmap = null;
}
public WriteableBitmap _drawBitmap;
public WriteableBitmap GetWriteableBitmap(VideoFrame videoFrame, out bool newBitmap)
{
if (_drawBitmap == null
|| _drawBitmap.Width != videoFrame.width
|| _drawBitmap.Height != videoFrame.height)
{
newBitmap = true;
_drawBitmap = new WriteableBitmap(videoFrame.width, videoFrame.height, 96, 96, PixelFormats.Bgra32, null);
ConvertFromRgb32ToPbgra32(videoFrame);
_drawBitmap.WritePixels(new Int32Rect(0, 0, videoFrame.width, videoFrame.height),
videoFrame.yBuffer, videoFrame.yStride, 0);
}
else
{
newBitmap = false;
ConvertFromRgb32ToPbgra32(videoFrame);
_drawBitmap.WritePixels(new Int32Rect(0, 0, videoFrame.width, videoFrame.height),
videoFrame.yBuffer, videoFrame.yStride, 0);
}
if (newBitmap)
OnLocalVideoBitmapInitialized?.Invoke();
return _drawBitmap;
}
private void ConvertFromRgb32ToPbgra32(VideoFrame videoFrame)
{
for (int y = 0; y < videoFrame.height; y++)
{
for (int x = 0; x < videoFrame.width; x++)
{
// Calculate array offset for this pixel
int offset = y * videoFrame.yStride + x * 4;
// Extract individual color channels from pixel value
int pb = videoFrame.yBuffer[offset];
int pg = videoFrame.yBuffer[offset + 1];
int pr = videoFrame.yBuffer[offset + 2];
int alpha = videoFrame.yBuffer[offset + 3];
// Remove premultiplication
int r = 0, g = 0, b = 0;
if (alpha > 0)
{
r = pr * 255 / alpha;
g = pg * 255 / alpha;
b = pb * 255 / alpha;
}
// Write color channels in desired order
videoFrame.yBuffer[offset] = (byte)r;
videoFrame.yBuffer[offset + 1] = (byte)g;
videoFrame.yBuffer[offset + 2] = (byte)b;
videoFrame.yBuffer[offset + 3] = (byte)alpha;
}
}
}
public override bool OnPreEncodeVideoFrame(VideoFrame videoFrame)
{
return base.OnPreEncodeVideoFrame(videoFrame);
}
public override bool OnRenderVideoFrameEx(string channelId, uint uid, VideoFrame videoFrame)
{
if (uid != 0)
{
}
else
{
Application.Current?.Dispatcher.Invoke(() =>
{
GetWriteableBitmap(videoFrame, out bool newBitmap);
});
}
return true;
}
public override bool OnRenderVideoFrame(uint uid, VideoFrame videoFrame)
{
return base.OnRenderVideoFrame(uid, videoFrame);
}
public override bool OnCaptureVideoFrame(VideoFrame videoFrame)
{
//Application.Current.Dispatcher.Invoke(() =>
//{
// GetWriteableBitmap(videoFrame, out bool newBitmap);
//});
return base.OnCaptureVideoFrame(videoFrame);
}
}
5.输入声网appid,测试效果
private string appId = "声网appid"; //这里需要改成声网的appid
private void Button_Click(object sender, RoutedEventArgs e)
{
var engine = AgoraRtcEngine.CreateAgoraRtcEngine();
RtcEngineContext rtc_engine_context = new RtcEngineContext(appId);
engine.Initialize(rtc_engine_context);
engine.InitEventHandler(new CustomEventHandler());
var frameObeserver = new VideoFrameObserver();
engine.RegisterVideoFrameObserver(frameObeserver);
frameObeserver.OnLocalVideoBitmapInitialized = () => {
imgMain.Source = frameObeserver._drawBitmap;
};
engine.EnableVideo();
engine.JoinChannel("", "123", "");
}
6.实际效果展示
源码:
链接:https://pan.baidu.com/s/1Rmm2gRfDDGZ_ht5kCQxBYg
提取码:swg9