diff --git a/Demo.Common/Converters/AspectRatioConverter.cs b/Demo.Common/Converters/AspectRatioConverter.cs
new file mode 100644
index 0000000..8c79474
--- /dev/null
+++ b/Demo.Common/Converters/AspectRatioConverter.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Demo.Common.Converters
+{
+ public class AspectRatioConverter : IMultiValueConverter
+ {
+ private readonly double ratio = 1.777;
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (values.Length == 2 && values[0] is double height && values[1] is double maxWidth)
+ {
+ Console.WriteLine($@"height {height} maxWidth {maxWidth}");
+ var controlWidth = height * ratio;
+ return controlWidth > maxWidth ? maxWidth : controlWidth;
+ }
+ //else if (values.Length == 4 && values[0] is double stackHeight
+ // && values[1] is double stackWidth && values[2] is int userPageSize
+ // && values[3] is Thickness margin)
+ //{
+ // var controlWidth = stackHeight * ratio;
+ //}
+ return 0;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
+
diff --git a/Demo.Common/Converters/BooleanInverseConverter.cs b/Demo.Common/Converters/BooleanInverseConverter.cs
new file mode 100644
index 0000000..fda79da
--- /dev/null
+++ b/Demo.Common/Converters/BooleanInverseConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Demo.Common.Converters
+{
+ public class BooleanInverseConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value is bool boolValue ? !boolValue : false;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value is bool boolValue ? !boolValue : false;
+ }
+ }
+}
diff --git a/Demo.Common/Demo.Common.csproj b/Demo.Common/Demo.Common.csproj
index 89541cf..2e71b64 100644
--- a/Demo.Common/Demo.Common.csproj
+++ b/Demo.Common/Demo.Common.csproj
@@ -5,6 +5,22 @@
enable
true
enable
+ AnyCPU;x64
+ false
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
diff --git a/Demo.Common/Dtos/BaseApiResult.cs b/Demo.Common/Dtos/BaseApiResult.cs
new file mode 100644
index 0000000..b72b0f4
--- /dev/null
+++ b/Demo.Common/Dtos/BaseApiResult.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Dtos
+{
+ public class BaseApiResult
+ {
+ public int code { get; set; }
+ public string message { get; set; }
+ public T Data { get; set; }
+ }
+}
diff --git a/Demo.Common/Dtos/LoginApiResponse.cs b/Demo.Common/Dtos/LoginApiResponse.cs
new file mode 100644
index 0000000..a6d1523
--- /dev/null
+++ b/Demo.Common/Dtos/LoginApiResponse.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Dtos
+{
+ public class LoginApiResponse
+ {
+ public string token { get; set; }
+ public string refresh_token { get; set; }
+
+ public string userName { get; set; }
+ public int expire { get; set; }
+ public string uid { get; set; }
+ }
+}
diff --git a/Demo.Common/Events/AudioVolumeIndicationEvent.cs b/Demo.Common/Events/AudioVolumeIndicationEvent.cs
new file mode 100644
index 0000000..de719ed
--- /dev/null
+++ b/Demo.Common/Events/AudioVolumeIndicationEvent.cs
@@ -0,0 +1,14 @@
+using Agora.Rtc;
+using Prism.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Events
+{
+ public class AudioVolumeIndicationEvent : PubSubEvent
+ {
+ }
+}
diff --git a/Demo.Common/Events/UserJoinEvent.cs b/Demo.Common/Events/UserJoinEvent.cs
new file mode 100644
index 0000000..83910bf
--- /dev/null
+++ b/Demo.Common/Events/UserJoinEvent.cs
@@ -0,0 +1,14 @@
+using Demo.Common.Models;
+using Prism.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Events
+{
+ public class UserJoinEvent : PubSubEvent
+ {
+ }
+}
diff --git a/Demo.Common/Events/UserLeaveEvent.cs b/Demo.Common/Events/UserLeaveEvent.cs
new file mode 100644
index 0000000..c4f3400
--- /dev/null
+++ b/Demo.Common/Events/UserLeaveEvent.cs
@@ -0,0 +1,14 @@
+using Demo.Common.Models;
+using Prism.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Events
+{
+ public class UserLeaveEvent : PubSubEvent
+ {
+ }
+}
diff --git a/Demo.Common/Extensions/RestClientExtension.cs b/Demo.Common/Extensions/RestClientExtension.cs
new file mode 100644
index 0000000..a4e5fa6
--- /dev/null
+++ b/Demo.Common/Extensions/RestClientExtension.cs
@@ -0,0 +1,33 @@
+using Demo.Common.Dtos;
+using Newtonsoft.Json.Linq;
+using RestSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Windows;
+using DataFormat = RestSharp.DataFormat;
+
+namespace Demo.Common.Extensions
+{
+ public static class RestClientExtension
+ {
+ public static async Task PostAsync(this RestClient client, TBody body) where TResult : class where TBody : class
+ {
+ RestRequest request = new RestRequest();
+ request.Method = Method.Post;
+ request.RequestFormat = DataFormat.Json;
+ request.AddOrUpdateHeader("Authorization", $"Bearer {Application.Current.Properties["token"]}");
+ request.AddJsonBody(body);
+ var result = await client.PostAsync>(request);
+ if (result.code != 200)
+ {
+ return result.Data;
+ }
+ return null;
+ }
+ }
+}
diff --git a/Demo.Common/Helpers/AgoraHelper.cs b/Demo.Common/Helpers/AgoraHelper.cs
new file mode 100644
index 0000000..6f48fc2
--- /dev/null
+++ b/Demo.Common/Helpers/AgoraHelper.cs
@@ -0,0 +1,123 @@
+using Agora.Rtc;
+using Masuit.Tools.Systems;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Helpers
+{
+ public class AgoraHelper : IRtcEngineEventHandler
+ {
+ private static uint _localUId;
+ public static IRtcEngine _RtcEngineInstance;
+ public static int Init(string appId, uint localUid = 0)
+ {
+ if (null == _RtcEngineInstance)
+ {
+ _RtcEngineInstance = RtcEngine.CreateAgoraRtcEngine();
+ }
+ RtcEngineContext rtc_engine_ctx = new RtcEngineContext();
+ rtc_engine_ctx.appId = appId;
+ var ret = _RtcEngineInstance.Initialize(rtc_engine_ctx);
+
+ ret = _RtcEngineInstance.InitEventHandler(new RtcEngineEventHandler());
+
+ _localUId = localUid;
+ return ret;
+ }
+
+ public static int UnInit()
+ {
+ if (null != _RtcEngineInstance)
+ {
+ // Dispose engine
+ _RtcEngineInstance.Dispose();
+ _RtcEngineInstance = null;
+ }
+
+ return 0;
+ }
+
+ ///
+ /// 渲染用户视频
+ ///
+ ///
+ ///
+ ///
+ public static int SetupUserVideo(uint uid, long controlHandle)
+ {
+ if (_localUId == uid)
+ {
+ // 本地用户
+ return _RtcEngineInstance.SetupLocalVideo(new VideoCanvas
+ {
+ view = controlHandle,
+ renderMode = RENDER_MODE_TYPE.RENDER_MODE_HIDDEN,
+ mirrorMode = VIDEO_MIRROR_MODE_TYPE.VIDEO_MIRROR_MODE_DISABLED,
+ uid = uid,
+ setupMode = VIDEO_VIEW_SETUP_MODE.VIDEO_VIEW_SETUP_ADD
+ });
+ }
+ else
+ {
+ return _RtcEngineInstance.SetupRemoteVideo(new VideoCanvas
+ {
+ view = controlHandle,
+ renderMode = RENDER_MODE_TYPE.RENDER_MODE_HIDDEN,
+ mirrorMode = VIDEO_MIRROR_MODE_TYPE.VIDEO_MIRROR_MODE_DISABLED,
+ uid = uid,
+ setupMode = VIDEO_VIEW_SETUP_MODE.VIDEO_VIEW_SETUP_ADD
+ });
+ }
+ }
+
+ ///
+ /// 清除已渲染的用户视频
+ ///
+ ///
+ ///
+ ///
+ public static int ClearUserVideo(uint uid, long controlHandle)
+ {
+ if (_localUId == uid)
+ {
+ // 本地用户
+ // 删除用户渲染
+ return _RtcEngineInstance.SetupLocalVideo(new VideoCanvas
+ {
+ view = controlHandle,
+ uid = uid,
+ setupMode = VIDEO_VIEW_SETUP_MODE.VIDEO_VIEW_SETUP_REMOVE
+ });
+ }
+ else
+ {
+ return _RtcEngineInstance.SetupRemoteVideo(new VideoCanvas
+ {
+ view = controlHandle,
+ uid = uid,
+ setupMode = VIDEO_VIEW_SETUP_MODE.VIDEO_VIEW_SETUP_REMOVE
+ });
+ }
+ }
+
+ ///
+ /// 渲染用户视频
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int SetupUserVideo(uint uid, long controlHandle, uint delUid = 0)
+ {
+ if (delUid > 0)
+ {
+ ClearUserVideo(delUid, controlHandle);
+ }
+ return SetupUserVideo(uid, controlHandle);
+ }
+ }
+}
diff --git a/Demo.Common/Helpers/RtcEngineEventHandler.cs b/Demo.Common/Helpers/RtcEngineEventHandler.cs
new file mode 100644
index 0000000..f75435d
--- /dev/null
+++ b/Demo.Common/Helpers/RtcEngineEventHandler.cs
@@ -0,0 +1,58 @@
+using Agora.Rtc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Prism.Ioc;
+using Prism.Events;
+using Demo.Common.Events;
+using Masuit.Tools;
+
+namespace Demo.Common.Helpers
+{
+ public class RtcEngineEventHandler : IRtcEngineEventHandler
+ {
+ private readonly IEventAggregator aggregator;
+ public RtcEngineEventHandler()
+ {
+ aggregator = ContainerLocator.Container.Resolve();
+ }
+
+ public override void OnUserJoined(RtcConnection connection, uint remoteUid, int elapsed)
+ {
+ //base.OnUserJoined(connection, remoteUid, elapsed);
+ Console.WriteLine($@"新用户加入: channelId:{connection.channelId} localuid: {connection.localUid} remoteuid:{remoteUid} elapsed: {elapsed}");
+
+
+ //var aggregator = ContainerLocator.Container.Resolve();
+ aggregator.GetEvent().Publish(new Models.User
+ {
+ Id = remoteUid,
+ UserName = remoteUid.ToString(),
+ IsManager = true,
+ IsLocal = false
+ });
+ }
+
+
+ public override void OnUserOffline(RtcConnection connection, uint remoteUid, USER_OFFLINE_REASON_TYPE reason)
+ {
+ //var aggregator = ContainerLocator.Container.Resolve();
+ aggregator.GetEvent().Publish(new Models.User
+ {
+ Id = remoteUid,
+ UserName = remoteUid.ToString(),
+ IsManager = true,
+ IsLocal = false
+ });
+ }
+
+ public override void OnAudioVolumeIndication(RtcConnection connection, AudioVolumeInfo[] speakers, uint speakerNumber, int totalVolume)
+ {
+
+ //aggregator.GetEvent().Publish();
+ }
+
+ }
+}
diff --git a/Demo.Common/Models/User.cs b/Demo.Common/Models/User.cs
new file mode 100644
index 0000000..620218c
--- /dev/null
+++ b/Demo.Common/Models/User.cs
@@ -0,0 +1,48 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common.Models
+{
+ public class User : BindableBase
+ {
+ private long id;
+ public long Id
+ {
+ get { return id; }
+ set { SetProperty(ref id, value); }
+ }
+
+ private string userName;
+ public string UserName
+ {
+ get { return userName; }
+ set { SetProperty(ref userName, value); }
+ }
+ private bool isManager;
+ public bool IsManager
+ {
+ get { return isManager; }
+ set { SetProperty(ref isManager, value); }
+ }
+
+
+ private bool isLocal;
+ public bool IsLocal
+ {
+ get { return isLocal; }
+ set { SetProperty(ref isLocal, value); }
+ }
+
+ //private bool isMain;
+ //public bool IsMain
+ //{
+ // get { return isMain; }
+ // set { SetProperty(ref isMain, value); }
+ //}
+ }
+}
diff --git a/Demo.Common/Models/UserInfo.cs b/Demo.Common/Models/UserInfo.cs
deleted file mode 100644
index 1706a69..0000000
--- a/Demo.Common/Models/UserInfo.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Demo.Common.Models
-{
- public class UserInfo
- {
- public long Id { get; set; }
- public string UserName { get; set; }
- public bool IsManager { get; set; }
- }
-}
diff --git a/Demo.Common/TestCredentials.cs b/Demo.Common/TestCredentials.cs
new file mode 100644
index 0000000..372a3c5
--- /dev/null
+++ b/Demo.Common/TestCredentials.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Common
+{
+ public static class TestCredentials
+ {
+ public static string Token { get; set; }
+ }
+}
diff --git a/Demo.Services.Interfaces/Demo.Services.Interfaces.csproj b/Demo.Services.Interfaces/Demo.Services.Interfaces.csproj
new file mode 100644
index 0000000..5ad0915
--- /dev/null
+++ b/Demo.Services.Interfaces/Demo.Services.Interfaces.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net6.0-windows net6.0
+ enable
+ enable
+ AnyCPU;x64
+
+
+
diff --git a/Demo.Services.Interfaces/IAgoraConfigService.cs b/Demo.Services.Interfaces/IAgoraConfigService.cs
new file mode 100644
index 0000000..0597504
--- /dev/null
+++ b/Demo.Services.Interfaces/IAgoraConfigService.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Services.Interfaces
+{
+ public interface IAgoraConfigService : IBaseService
+ {
+ Task GetAgoraConfigAsync();
+ Task GetRtcTokenAsync();
+ }
+}
diff --git a/Demo.Services.Interfaces/IAgoraEngineService.cs b/Demo.Services.Interfaces/IAgoraEngineService.cs
new file mode 100644
index 0000000..a2789b0
--- /dev/null
+++ b/Demo.Services.Interfaces/IAgoraEngineService.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Services.Interfaces
+{
+ public interface IAgoraEngineService
+ {
+ }
+}
diff --git a/Demo.Services.Interfaces/IAuthService.cs b/Demo.Services.Interfaces/IAuthService.cs
new file mode 100644
index 0000000..ea54010
--- /dev/null
+++ b/Demo.Services.Interfaces/IAuthService.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Services.Interfaces
+{
+ public interface IAuthService : IBaseService
+ {
+ Task LoginAsync();
+ }
+}
diff --git a/Demo.Services.Interfaces/IBaseService.cs b/Demo.Services.Interfaces/IBaseService.cs
new file mode 100644
index 0000000..0740f2f
--- /dev/null
+++ b/Demo.Services.Interfaces/IBaseService.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Demo.Services.Interfaces
+{
+ public interface IBaseService
+ {
+
+ }
+}
diff --git a/Demo.Services/AgoraConfigService.cs b/Demo.Services/AgoraConfigService.cs
new file mode 100644
index 0000000..df27610
--- /dev/null
+++ b/Demo.Services/AgoraConfigService.cs
@@ -0,0 +1,38 @@
+using Demo.Common.Dtos;
+using Demo.Services.Interfaces;
+using RestSharp;
+using System.Windows;
+
+namespace Demo.Services
+{
+ public class AgoraConfigService : BaseService, IAgoraConfigService
+ {
+ public async Task GetAgoraConfigAsync()
+ {
+ RestRequest request = new RestRequest("home/agora-conf");
+ var result = await BaseRestClient.ExecuteAsync>(request);
+ if (!result.IsSuccessful || result.Data == null)
+ {
+ MessageBox.Show(result.ErrorMessage);
+ return string.Empty;
+ }
+ return result.Data.Data;
+ }
+
+ public async Task GetRtcTokenAsync()
+ {
+ var request = new RestRequest("room/tk/rtc?roomNum=999").AddHeader("Authorization", "Bearer " + Application.Current.Properties["token"]);
+ var result = await BaseRestClient.ExecuteAsync>(request);
+
+ if (result == null || result.Data == null)
+ {
+ MessageBox.Show("token 获取失败");
+ return string.Empty;
+ }
+
+ //return result.Data.Data;
+
+ return result.Data.Data;
+ }
+ }
+}
diff --git a/Demo.Services/AgoraEngineService.cs b/Demo.Services/AgoraEngineService.cs
new file mode 100644
index 0000000..ab82af3
--- /dev/null
+++ b/Demo.Services/AgoraEngineService.cs
@@ -0,0 +1,20 @@
+using Agora.Rtc;
+using Demo.Services.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Demo.Services
+{
+ public class AgoraEngineService : IAgoraEngineService
+ {
+ private IRtcEngine _rtcEngine;
+
+ public AgoraEngineService()
+ {
+
+ }
+ }
+}
diff --git a/Demo.Services/AuthService.cs b/Demo.Services/AuthService.cs
new file mode 100644
index 0000000..db60e86
--- /dev/null
+++ b/Demo.Services/AuthService.cs
@@ -0,0 +1,29 @@
+using Demo.Common;
+using Demo.Common.Dtos;
+using Demo.Services.Interfaces;
+using RestSharp;
+using System.Windows;
+
+namespace Demo.Services
+{
+ public class AuthService : BaseService, IAuthService
+ {
+ public async Task LoginAsync()
+ {
+ var restRequest = new RestRequest("auth/login");
+ restRequest.AddBody(new
+ {
+ account = "2",
+ pwd = "c81e728d9d4c2f636f067f89cc14862c"
+ });
+ var response = await BaseRestClient.ExecutePostAsync>(restRequest);
+ if (!response.IsSuccessful || response.Data == null || response.Data.code != 200)
+ {
+ MessageBox.Show("登录失败");
+ return string.Empty;
+ }
+ return response.Data.Data.token;
+ }
+
+ }
+}
diff --git a/Demo.Services/BaseService.cs b/Demo.Services/BaseService.cs
new file mode 100644
index 0000000..6a40cd0
--- /dev/null
+++ b/Demo.Services/BaseService.cs
@@ -0,0 +1,17 @@
+using Demo.Common;
+using Demo.Services.Interfaces;
+using RestSharp;
+using System.Windows;
+
+namespace Demo.Services
+{
+ public class BaseService : IBaseService
+ {
+ protected RestClient BaseRestClient;
+ public BaseService(RestClient client = null)
+ {
+ BaseRestClient = client ?? new RestClient(new Uri($@"http://192.168.2.9:5192"));
+ }
+
+ }
+}
diff --git a/Demo.Services/Demo.Services.csproj b/Demo.Services/Demo.Services.csproj
new file mode 100644
index 0000000..645b28b
--- /dev/null
+++ b/Demo.Services/Demo.Services.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net6.0-windows
+ enable
+ enable
+ AnyCPU;x64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Meeting.V2.Demo.sln b/Meeting.V2.Demo.sln
index 3bada02..499abe7 100644
--- a/Meeting.V2.Demo.sln
+++ b/Meeting.V2.Demo.sln
@@ -5,42 +5,60 @@ VisualStudioVersion = 17.12.35506.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{13DA16E8-EB84-4F95-B120-F4CC4B0162E4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meeting.V2.Demo.Services", "Meeting.V2.Demo\Services\Meeting.V2.Demo.Services\Meeting.V2.Demo.Services.csproj", "{A4A5CAFF-287C-4833-98B6-D074132ED8BF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meeting.V2.Demo.Services.Interfaces", "Meeting.V2.Demo\Services\Meeting.V2.Demo.Services.Interfaces\Meeting.V2.Demo.Services.Interfaces.csproj", "{A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meeting.V2.Demo", "Meeting.V2.Demo\Meeting.V2.Demo\Meeting.V2.Demo.csproj", "{ED1004D9-097A-4AB6-BA74-BD5CB40D9984}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Common", "Demo.Common\Demo.Common.csproj", "{B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Services", "Demo.Services\Demo.Services.csproj", "{F1C3D513-854E-447B-B0C8-306963706E85}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.Services.Interfaces", "Demo.Services.Interfaces\Demo.Services.Interfaces.csproj", "{AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {A4A5CAFF-287C-4833-98B6-D074132ED8BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A4A5CAFF-287C-4833-98B6-D074132ED8BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A4A5CAFF-287C-4833-98B6-D074132ED8BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A4A5CAFF-287C-4833-98B6-D074132ED8BF}.Release|Any CPU.Build.0 = Release|Any CPU
- {A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB}.Release|Any CPU.Build.0 = Release|Any CPU
{ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Debug|x64.ActiveCfg = Debug|x64
+ {ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Debug|x64.Build.0 = Debug|x64
{ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Release|x64.ActiveCfg = Release|x64
+ {ED1004D9-097A-4AB6-BA74-BD5CB40D9984}.Release|x64.Build.0 = Release|x64
{B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Debug|x64.ActiveCfg = Debug|x64
+ {B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Debug|x64.Build.0 = Debug|x64
{B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Release|x64.ActiveCfg = Release|x64
+ {B8ACCBD2-1C4D-4CF5-BBBD-C0A62DB64C31}.Release|x64.Build.0 = Release|x64
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Debug|x64.ActiveCfg = Debug|x64
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Debug|x64.Build.0 = Debug|x64
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Release|x64.ActiveCfg = Release|x64
+ {F1C3D513-854E-447B-B0C8-306963706E85}.Release|x64.Build.0 = Release|x64
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Debug|x64.ActiveCfg = Debug|x64
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Debug|x64.Build.0 = Debug|x64
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Release|x64.ActiveCfg = Release|x64
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {A4A5CAFF-287C-4833-98B6-D074132ED8BF} = {13DA16E8-EB84-4F95-B120-F4CC4B0162E4}
- {A4FC67BC-E1AE-48A3-A312-3BBB3FB1BAEB} = {13DA16E8-EB84-4F95-B120-F4CC4B0162E4}
+ {F1C3D513-854E-447B-B0C8-306963706E85} = {13DA16E8-EB84-4F95-B120-F4CC4B0162E4}
+ {AAB9554E-AF4A-4B94-BFEC-B239DC9DD2A6} = {13DA16E8-EB84-4F95-B120-F4CC4B0162E4}
EndGlobalSection
EndGlobal
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml b/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml
index 366ccd7..6865043 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml
@@ -2,6 +2,7 @@
x:Class="Meeting.V2.Demo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:cnt="clr-namespace:Demo.Common.Converters;assembly=Demo.Common"
xmlns:local="clr-namespace:Meeting.V2.Demo"
xmlns:prism="http://prismlibrary.com/">
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml.cs b/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml.cs
index 33a2bc2..bfd78ee 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml.cs
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/App.xaml.cs
@@ -1,9 +1,14 @@
-using Meeting.V2.Demo.Services;
+using Demo.Common.Helpers;
+using Demo.Services;
+using Demo.Services.Interfaces;
+using Meeting.V2.Demo.Services;
using Meeting.V2.Demo.Services.Interfaces;
using Meeting.V2.Demo.ViewModels;
using Meeting.V2.Demo.Views;
+using Prism.Events;
using Prism.Ioc;
using Prism.Modularity;
+using System;
using System.Windows;
namespace Meeting.V2.Demo
@@ -21,9 +26,12 @@ namespace Meeting.V2.Demo
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton();
+ containerRegistry.RegisterSingleton();
+ containerRegistry.RegisterSingleton();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
+ containerRegistry.RegisterSingleton();
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
@@ -32,15 +40,24 @@ namespace Meeting.V2.Demo
//moduleCatalog.AddModule();
}
- protected override void OnInitialized()
+ protected override async void OnInitialized()
{
base.OnInitialized();
var config = Container.Resolve();
if (config != null)
{
- config.Init();
+ await config.Init();
}
}
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ AgoraHelper.UnInit();
+ Console.WriteLine("推出了!");
+ base.OnExit(e);
+
+ }
+
}
}
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/Configure/ConfigureService.cs b/Meeting.V2.Demo/Meeting.V2.Demo/Configure/ConfigureService.cs
index a8a7ace..6b66df8 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/Configure/ConfigureService.cs
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/Configure/ConfigureService.cs
@@ -1,23 +1,39 @@
-using Demo.Common;
+using AngleSharp.Io;
+using Demo.Common;
+using Demo.Common.Helpers;
+using Demo.Services.Interfaces;
using Meeting.V2.Demo.Views;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
namespace Meeting.V2.Demo.Services.Interfaces
{
public class ConfigureService : IConfigureService
{
- private readonly IRegionManager _regionManager;
+ private readonly IRegionManager _regionManager;
+ private readonly IAuthService _authService;
- public ConfigureService(IRegionManager regionManager)
+ public ConfigureService(IRegionManager regionManager, IAuthService authService)
{
- this._regionManager = regionManager;
+ this._regionManager = regionManager;
+ this._authService = authService;
}
- public void Init()
+ public async Task Init()
{
_regionManager.RegisterViewWithRegion(RegionNames.VideoRegion);
+ var token = await _authService.LoginAsync();
+ if (string.IsNullOrWhiteSpace(token) )
+ {
+ MessageBox.Show("登录失败");
+ return;
+
+ }
+ System.Windows.Application.Current.Properties["token"] = token;
+ //var appid = await _agoraConfigService.GetAgoraConfigAsync();
}
}
}
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/Configure/IConfigureService.cs b/Meeting.V2.Demo/Meeting.V2.Demo/Configure/IConfigureService.cs
index c73691c..a3cfdf4 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/Configure/IConfigureService.cs
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/Configure/IConfigureService.cs
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
namespace Meeting.V2.Demo.Services.Interfaces
{
public interface IConfigureService
{
- void Init();
+ Task Init();
}
}
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/Meeting.V2.Demo.csproj b/Meeting.V2.Demo/Meeting.V2.Demo/Meeting.V2.Demo.csproj
index c0b61a3..e09d979 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/Meeting.V2.Demo.csproj
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/Meeting.V2.Demo.csproj
@@ -4,12 +4,15 @@
net6.0-windows
true
True
+ AnyCPU;x64
+ false
+
@@ -17,8 +20,8 @@
-
-
+
+
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/MainWindowViewModel.cs b/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/MainWindowViewModel.cs
index 8159fdc..f0bc04c 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/MainWindowViewModel.cs
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/MainWindowViewModel.cs
@@ -1,19 +1,118 @@
-using Prism.Mvvm;
+using Agora.Rtc;
+using Demo.Common.Events;
+using Demo.Common.Helpers;
+using Demo.Common.Models;
+using Demo.Services.Interfaces;
+using HandyControl.Controls;
+using HandyControl.Data;
+using Masuit.Tools;
+using Prism.Commands;
+using Prism.Events;
+using Prism.Mvvm;
+using System;
+using System.Windows;
namespace Meeting.V2.Demo.ViewModels
{
public class MainWindowViewModel : BindableBase
{
+ public MainWindowViewModel(IEventAggregator aggregator, IAgoraConfigService agoraConfigService)
+ {
+ this._aggregator = aggregator;
+ this._agoraConfigService = agoraConfigService;
+ }
+
private string _title = "Prism Application";
+ private readonly IEventAggregator _aggregator;
+ private readonly IAgoraConfigService _agoraConfigService;
+
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
- public MainWindowViewModel()
+ private long uid = (DateTime.Now.Ticks % 100000).ToString("D5").ToInt64();
+ public long UId
{
-
+ get { return uid; }
+ set { SetProperty(ref uid, value); }
}
+
+ private bool isJoin;
+ public bool IsJoin
+ {
+ get { return isJoin; }
+ set { SetProperty(ref isJoin, value); }
+ }
+
+
+
+ public DelegateCommand JoinChannelCommand => new DelegateCommand(JoinChannel);
+ async void JoinChannel()
+ {
+ AgoraHelper.Init("4a4f7be64fa1404ebda74784fe9ac381", (uint)UId);
+
+ var rtcToken = await _agoraConfigService.GetRtcTokenAsync();
+ if (!string.IsNullOrWhiteSpace(rtcToken))
+ Application.Current.Properties["rtctoken"] = rtcToken;
+
+ var result = AgoraHelper._RtcEngineInstance.EnableVideo();
+ Console.WriteLine($@"{nameof(JoinChannel)}-EnableVideo : {result}");
+
+ result = AgoraHelper._RtcEngineInstance.StartPreview(VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA_PRIMARY);
+ Console.WriteLine($@"{nameof(JoinChannel)}-StartPreview : {result}");
+
+ ChannelMediaOptions options = new ChannelMediaOptions();
+ options.channelProfile.SetValue(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_LIVE_BROADCASTING);
+ options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
+ // 发布麦克风采集的音频流
+ options.publishMicrophoneTrack.SetValue(true);
+ // 发布摄像头采集的视频流
+ options.publishCameraTrack.SetValue(true);
+ // 自动订阅所有音频流
+ options.autoSubscribeAudio.SetValue(true);
+ // 自动订阅所有视频流
+ options.autoSubscribeVideo.SetValue(true);
+
+ AgoraHelper._RtcEngineInstance.JoinChannel(System.Windows.Application.Current.Properties["rtctoken"].ToString(), "999", (uint)UId, options);
+
+ ///启用用户音量提示。
+ AgoraHelper._RtcEngineInstance.EnableAudioVolumeIndication(200, 5, false);
+
+ _aggregator.GetEvent().Publish(new User
+ {
+ Id = UId,
+ UserName = UId.ToString(),
+ IsManager = true,
+ IsLocal = true
+ });
+
+ IsJoin = !IsJoin;
+ Growl.Success("加入频道成功");
+ }
+
+ public DelegateCommand LeavelChannelCommand => new DelegateCommand(LeavelChannel);
+ void LeavelChannel()
+ {
+ AgoraHelper._RtcEngineInstance.LeaveChannel();
+ AgoraHelper._RtcEngineInstance.StopPreview();
+ AgoraHelper._RtcEngineInstance.DisableVideo();
+
+
+ _aggregator.GetEvent().Publish(new User
+ {
+ Id = UId,
+ UserName = UId.ToString(),
+ IsManager = true,
+ IsLocal = true
+ });
+
+ IsJoin = !IsJoin;
+
+ Growl.Success("离开频道成功");
+ }
+
+
}
}
diff --git a/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/VideoAreaViewModel.cs b/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/VideoAreaViewModel.cs
index 2b2e01b..6356239 100644
--- a/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/VideoAreaViewModel.cs
+++ b/Meeting.V2.Demo/Meeting.V2.Demo/ViewModels/VideoAreaViewModel.cs
@@ -1,77 +1,140 @@
-using Demo.Common.Models;
+using Demo.Common.Events;
using Meeting.V2.Demo.Core.Mvvm;
using Prism.Commands;
+using Prism.Events;
using Prism.Regions;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Threading;
+using User = Demo.Common.Models.User;
namespace Meeting.V2.Demo.ViewModels
{
public class VideoAreaViewModel : RegionViewModelBase
{
- public VideoAreaViewModel(IRegionManager regionManager) : base(regionManager)
+ public VideoAreaViewModel(IRegionManager regionManager,
+ IEventAggregator aggregator) : base(regionManager)
{
- UserInfos.Add(new UserInfo() { Id = 1, UserName = "张三", IsManager = true });
- UserInfos.Add(new UserInfo() { Id = 2, UserName = "李四", IsManager = false });
+ this.aggregator = aggregator;
- UinfoProp = new UserInfo
+ aggregator.GetEvent().Subscribe((a) => Application.Current.Dispatcher.BeginInvoke(() =>
{
- Id = 111,
- UserName = "王五",
- IsManager = false
- };
+
+ UserInfos.Add(a);
+ }));
+ aggregator.GetEvent().Subscribe((a) =>
+ {
+ Application.Current.Dispatcher.BeginInvoke(() =>
+ {
+ if (a.IsLocal)
+ {
+ UserInfos.Clear();
+ FocusUser = null;
+ return;
+ }
+ for (int i = 0; i < UserInfos.Count; i++)
+ {
+ if (UserInfos[i].Id == a.Id)
+ {
+ UserInfos.RemoveAt(i);
+ return;
+ }
+ }
+ });
+
+ });
+ //UserInfos.Add(new UserInfo() { Id = 1, UserName = "张三", IsManager = true });
+ //UserInfos.Add(new UserInfo() { Id = 2, UserName = "李四", IsManager = false });
+ //UserInfos.Add(new UserInfo() { Id = 3, UserName = "李四", IsManager = false });
+ //UserInfos.Add(new UserInfo() { Id = 4, UserName = "李四", IsManager = false });
+ //UserInfos.Add(new UserInfo() { Id = 4, UserName = "李四", IsManager = false });
+ //UserInfos.Add(new UserInfo() { Id = 4, UserName = "李四", IsManager = false });
}
- private ObservableCollection userInfos = new();
+ private ObservableCollection userInfos = new();
///
/// 用户列表
///
- public ObservableCollection UserInfos
+ public ObservableCollection UserInfos
{
get { return userInfos; }
set { SetProperty(ref userInfos, value); }
}
- private string fieldName = "卧槽";
- public string PropertyNameAA
+ private int userPageSize = 6;
+ ///
+ /// 每页用户数
+ ///
+ public int UserPageSize
{
- get { return fieldName; }
- set { SetProperty(ref fieldName, value); }
- }
-
- private UserInfo Uinfo;
- public UserInfo UinfoProp
- {
- get { return Uinfo; }
- set { SetProperty(ref Uinfo, value); }
+ get { return userPageSize; }
+ set { SetProperty(ref userPageSize, value); }
}
- public override void OnNavigatedTo(NavigationContext navigationContext)
- {
- //base.OnNavigatedTo(navigationContext);
+ private User focusUser;
+ private readonly IEventAggregator aggregator;
- Init();
- }
-
- private void Init()
+ ///
+ /// 焦点用户
+ ///
+ public User FocusUser
{
- UserInfos.Add(new UserInfo() { Id = 3, UserName = "王五", IsManager = true });
- UserInfos.Add(new UserInfo() { Id = 4, UserName = "李2", IsManager = false });
+ get { return focusUser; }
+ set { SetProperty(ref focusUser, value); }
}
- public DelegateCommand TestCommand => new DelegateCommand(ExecuteCommandName);
-
- void ExecuteCommandName()
+ ///
+ /// 选择焦点用户
+ ///
+ public DelegateCommand SelectedUserCommand => new DelegateCommand((u) =>
{
- MessageBox.Show($@"{UserInfos.Count} Id:{string.Join(',', UserInfos.Select(x => x.Id))}");
- }
+ if (FocusUser != u || FocusUser.Id != u.Id)
+ {
+ FocusUser = u;
+ }
+ });
+
+ /////
+ ///// 选择焦点用户
+ /////
+ //public DelegateCommand SelectedUserCommand => new DelegateCommand(() =>
+ //{
+ // Console.WriteLine("2222222222222222222222222222");
+ //});
+
+
+
+ ///
+ /// 用户列表尺寸大小改变事件
+ ///
+ public DelegateCommand