diff --git a/JianGongYun/App.xaml b/JianGongYun/App.xaml
index 1a00d43..0b1630d 100644
--- a/JianGongYun/App.xaml
+++ b/JianGongYun/App.xaml
@@ -12,6 +12,7 @@
+
diff --git a/JianGongYun/JianGongYun.csproj b/JianGongYun/JianGongYun.csproj
index f9244b0..3d696aa 100644
--- a/JianGongYun/JianGongYun.csproj
+++ b/JianGongYun/JianGongYun.csproj
@@ -15,6 +15,8 @@
+
+
diff --git a/JianGongYun/Style/TRTCResource.xaml b/JianGongYun/Style/TRTCResource.xaml
new file mode 100644
index 0000000..d4856e1
--- /dev/null
+++ b/JianGongYun/Style/TRTCResource.xaml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml b/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml
new file mode 100644
index 0000000..e5cab13
--- /dev/null
+++ b/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml
@@ -0,0 +1,10 @@
+
+
diff --git a/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml.cs b/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml.cs
new file mode 100644
index 0000000..8f5f274
--- /dev/null
+++ b/JianGongYun/TRTC/Components/SytemGatherVolumeControl.xaml.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace JianGongYun.TRTC.Components
+{
+ ///
+ /// SytemGatherVolumeControl.xaml 的交互逻辑
+ ///
+ public partial class SytemGatherVolumeControl : UserControl
+ {
+ public SytemGatherVolumeControl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/LiveClassroom.cs b/JianGongYun/TRTC/LiveClassroom.cs
new file mode 100644
index 0000000..42a415a
--- /dev/null
+++ b/JianGongYun/TRTC/LiveClassroom.cs
@@ -0,0 +1,127 @@
+using JianGongYun.TRTC.Models;
+using JianGongYun.TRTC.Utils;
+using JianGongYun.TRTC.Windows;
+using ManageLiteAV;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+
+namespace JianGongYun.TRTC
+{
+ ///
+ /// 直播调用对象全放这里
+ ///
+ public static class LiveClassroom
+ {
+ const uint SDKAppID = 1400463444;
+ const string SDKAppKEY = "6ee2586282eb8ab5bff3f917b44500c4ffd9bbd3d820258b1fa8cdd470cfd1ee";
+ ///
+ /// TRTC实例
+ ///
+ public static ITRTCCloud lTRTCCloud;
+ ///
+ /// 设备管理器
+ ///
+ public static ITXDeviceManager lTXDeviceManager;
+ ///
+ /// live窗口的调用窗口
+ ///
+ public static Window CallerWindow { get; private set; }
+ ///
+ /// 直播窗口
+ ///
+ public static Window CurrentLiveWindow;
+ public static ClassroomEntity CurrentClassroomEntity { get; private set; }
+ //public static int UserCount = 999;
+ ///
+ /// 进入直播教室
+ ///
+ /// 调用窗口
+ /// 教室数据
+ public static void EnterTheClassroom(Window callerWindow, ClassroomEntity classroomEntity)
+ {
+ if (CurrentLiveWindow != null)
+ {
+ _ = AduSkin.Controls.Metro.AduMessageBox.Show("已经进入教室", "提醒");
+ CurrentLiveWindow.Topmost = true;
+ return;
+ }
+ CallerWindow = callerWindow;
+ CurrentClassroomEntity = classroomEntity;
+ CurrentLiveWindow = new LiveWindow();
+ CurrentLiveWindow.Closed += CurrentLiveWindow_Closed;
+
+
+ lTRTCCloud = ITRTCCloud.getTRTCShareInstance();//创建TRTC实例
+ var roomPars = new TRTCParams
+ {
+ sdkAppId = SDKAppID,
+ userId = CurrentClassroomEntity.TeacherId,
+ userSig = GenTestUserSig(CurrentClassroomEntity.TeacherId),
+ roomId = 0,//使用strRoomId
+ strRoomId = CurrentClassroomEntity.TeacherId,
+ role = TRTCRoleType.TRTCRoleAnchor
+ };
+ lTRTCCloud.enterRoom(ref roomPars, TRTCAppScene.TRTCAppSceneLIVE);//创建房间
+
+ //设备
+ var settingViewMode = ViewModels.SettingWindowViewModel.GetInstance();
+ lTXDeviceManager = lTRTCCloud.getDeviceManager();
+ var currentMic = settingViewMode.CurrentMic;//麦克风
+ if (!string.IsNullOrEmpty(currentMic))
+ {
+ var res = lTXDeviceManager.setCurrentDevice(TRTCDeviceType.TXMediaDeviceTypeMic, currentMic);
+ Console.WriteLine($"设置麦克风:{res}");
+ }
+ //设备完结
+
+
+ callerWindow.Hide();//隐藏调用窗口
+ CurrentLiveWindow.Show();
+ }
+
+ private static void CurrentLiveWindow_Closed(object sender, EventArgs e)
+ {
+ CurrentLiveWindow = null;
+ CurrentClassroomEntity = null;
+ CallerWindow.Show();//还原调用者窗口
+
+ lTXDeviceManager.Dispose();
+ lTXDeviceManager = null;
+ lTRTCCloud.exitRoom();
+ ITRTCCloud.destroyTRTCShareInstance();//销毁TRTC实例
+ lTRTCCloud.Dispose();
+ lTRTCCloud = null;
+ }
+
+
+
+ ///
+ /// 计算 UserSig 签名
+ ///
+ /// 函数内部使用 HMAC-SHA256 非对称加密算法,对 SDKAPPID、userId 和 EXPIRETIME 进行加密
+ ///
+ /// 该方案仅适合本地跑通demo和功能调试,产品真正上线发布,要使用服务器获取方案避免私钥被破解。
+ ///
+ ///
+ /// 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
+ ///
+ /// 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
+ /// 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
+ /// 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
+ ///
+ /// 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
+ /// 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
+ ///
+ /// 文档:https://cloud.tencent.com/document/product/647/17275#GetFromServer
+ ///
+ public static string GenTestUserSig(string userId)
+ {
+ if (SDKAppID == 0 || string.IsNullOrEmpty(SDKAppKEY)) return null;
+ TLSSigAPIv2 api = new TLSSigAPIv2((int)SDKAppID, SDKAppKEY);
+ // 统一转换为UTF8,SDK内部是用UTF8编码。
+ return api.GenSig(Util.UTF16To8(userId));
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/Models/ClassroomEntity.cs b/JianGongYun/TRTC/Models/ClassroomEntity.cs
new file mode 100644
index 0000000..7b2b44d
--- /dev/null
+++ b/JianGongYun/TRTC/Models/ClassroomEntity.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JianGongYun.TRTC.Models
+{
+ ///
+ /// 教室实体数据
+ ///
+ public class ClassroomEntity
+ {
+ ///
+ /// 教师id(长度不超过32字符,教师id同时视为直播教室id)
+ ///
+ public string TeacherId { get; set; }
+ ///
+ /// 教师名称
+ ///
+ public string TeacherName { get; set; }
+ ///
+ /// 课程名称
+ ///
+ public string ClassHead { get; set; }
+ ///
+ /// 章节名称
+ ///
+ public string ClassSubHead { get; set; }
+
+ }
+}
diff --git a/JianGongYun/TRTC/Models/ComboBoxEntity.cs b/JianGongYun/TRTC/Models/ComboBoxEntity.cs
new file mode 100644
index 0000000..485eb75
--- /dev/null
+++ b/JianGongYun/TRTC/Models/ComboBoxEntity.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JianGongYun.TRTC.Models
+{
+ public class ComboBoxEntity
+ {
+ public string Id { get; set; }
+ public string Text { get; set; }
+ }
+}
diff --git a/JianGongYun/TRTC/Utils/IniStorage.cs b/JianGongYun/TRTC/Utils/IniStorage.cs
new file mode 100644
index 0000000..99c3020
--- /dev/null
+++ b/JianGongYun/TRTC/Utils/IniStorage.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace JianGongYun.TRTC.Utils
+{
+ public class IniStorage
+ { // 声明INI文件的写操作函数
+ [DllImport("kernel32")]
+ private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
+
+ // 声明INI文件的读操作函数
+ [DllImport("kernel32")]
+ private static extern int GetPrivateProfileString(string section, string key, string def, System.Text.StringBuilder retVal, int size, string filePath);
+
+ private string sPath = null;
+
+ public IniStorage(string path)
+ {
+ this.sPath = path;
+ }
+
+ public void SetValue(string section, string key, string value)
+ {
+ // section=配置节,key=键名,value=键值,path=路径
+ WritePrivateProfileString(section, key, value, sPath);
+ }
+
+ public string GetValue(string section, string key)
+ {
+ // 每次从ini中读取多少字节
+ System.Text.StringBuilder temp = new System.Text.StringBuilder(255);
+ // section=配置节,key=键名,temp=上面,path=路径
+ GetPrivateProfileString(section, key, "", temp, 255, sPath);
+ return temp.ToString();
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/Utils/TLSSigAPIv2.cs b/JianGongYun/TRTC/Utils/TLSSigAPIv2.cs
new file mode 100644
index 0000000..cd70105
--- /dev/null
+++ b/JianGongYun/TRTC/Utils/TLSSigAPIv2.cs
@@ -0,0 +1,123 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using zlib;
+
+namespace JianGongYun.TRTC.Utils
+{
+ public class TLSSigAPIv2
+ {
+ private readonly int sdkappid;
+ private readonly string key;
+
+ public TLSSigAPIv2(int sdkappid, string key)
+ {
+ this.sdkappid = sdkappid;
+ this.key = key;
+ }
+
+ private static byte[] CompressBytes(byte[] sourceByte)
+ {
+ MemoryStream inputStream = new MemoryStream(sourceByte);
+ Stream outStream = CompressStream(inputStream);
+ byte[] outPutByteArray = new byte[outStream.Length];
+ outStream.Position = 0;
+ outStream.Read(outPutByteArray, 0, outPutByteArray.Length);
+ return outPutByteArray;
+ }
+
+ private static Stream CompressStream(Stream sourceStream)
+ {
+ MemoryStream streamOut = new MemoryStream();
+ ZOutputStream streamZOut = new ZOutputStream(streamOut, zlibConst.Z_DEFAULT_COMPRESSION);
+ CopyStream(sourceStream, streamZOut);
+ streamZOut.finish();
+ return streamOut;
+ }
+
+ public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
+ {
+ byte[] buffer = new byte[2000];
+ int len;
+ while ((len = input.Read(buffer, 0, 2000)) > 0)
+ {
+ output.Write(buffer, 0, len);
+ }
+ output.Flush();
+ }
+
+ private string HMACSHA256(string identifier, long currTime, int expire, string base64UserBuf, bool userBufEnabled)
+ {
+ string rawContentToBeSigned = "TLS.identifier:" + identifier + "\n"
+ + "TLS.sdkappid:" + sdkappid + "\n"
+ + "TLS.time:" + currTime + "\n"
+ + "TLS.expire:" + expire + "\n";
+ if (true == userBufEnabled)
+ {
+ rawContentToBeSigned += "TLS.userbuf:" + base64UserBuf + "\n";
+ }
+ using (HMACSHA256 hmac = new HMACSHA256())
+ {
+ UTF8Encoding encoding = new UTF8Encoding();
+ Byte[] textBytes = encoding.GetBytes(rawContentToBeSigned);
+ Byte[] keyBytes = encoding.GetBytes(key);
+ Byte[] hashBytes;
+ using (HMACSHA256 hash = new HMACSHA256(keyBytes))
+ hashBytes = hash.ComputeHash(textBytes);
+ return Convert.ToBase64String(hashBytes);
+ }
+ }
+
+ private string GenSig(string identifier, int expire, byte[] userbuf, bool userBufEnabled)
+ {
+ DateTime epoch = new DateTime(1970, 1, 1); // unix 时间戳
+ Int64 currTime = (Int64)(DateTime.UtcNow - epoch).TotalMilliseconds / 1000;
+
+ string base64UserBuf;
+ string jsonData;
+ if (true == userBufEnabled)
+ {
+ base64UserBuf = Convert.ToBase64String(userbuf);
+ string base64sig = HMACSHA256(identifier, currTime, expire, base64UserBuf, userBufEnabled);
+ var jsonObj = new JObject();
+ jsonObj["TLS.ver"] = "2.0";
+ jsonObj["TLS.identifier"] = identifier;
+ jsonObj["TLS.sdkappid"] = sdkappid;
+ jsonObj["TLS.expire"] = expire;
+ jsonObj["TLS.time"] = currTime;
+ jsonObj["TLS.sig"] = base64sig;
+ jsonObj["TLS.userbuf"] = base64UserBuf;
+ jsonData = JsonConvert.SerializeObject(jsonObj);
+ }
+ else
+ {
+ string base64sig = HMACSHA256(identifier, currTime, expire, "", false);
+ var jsonObj = new JObject();
+ jsonObj["TLS.ver"] = "2.0";
+ jsonObj["TLS.identifier"] = identifier;
+ jsonObj["TLS.sdkappid"] = sdkappid;
+ jsonObj["TLS.expire"] = expire;
+ jsonObj["TLS.time"] = currTime;
+ jsonObj["TLS.sig"] = base64sig;
+ jsonData = JsonConvert.SerializeObject(jsonObj);
+ }
+ byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
+ return Convert.ToBase64String(CompressBytes(buffer))
+ .Replace('+', '*').Replace('/', '-').Replace('=', '_');
+ }
+
+ public string GenSig(string identifier, int expire = 180 * 86400)
+ {
+ return GenSig(identifier, expire, null, false);
+ }
+
+ public string GenSigWithUserBuf(string identifier, int expire, byte[] userbuf)
+ {
+ return GenSig(identifier, expire, userbuf, true);
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/Utils/Util.cs b/JianGongYun/TRTC/Utils/Util.cs
new file mode 100644
index 0000000..267ea9a
--- /dev/null
+++ b/JianGongYun/TRTC/Utils/Util.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace JianGongYun.TRTC.Utils
+{
+ public class Util
+ {
+ public static string UTF16To8(string str)
+ {
+ byte[] utf16Bytes = Encoding.Unicode.GetBytes(str);
+ byte[] utf8Bytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, utf16Bytes);
+ return Encoding.UTF8.GetString(utf8Bytes);
+ }
+
+ public static bool IsSys64bit()
+ {
+ return IntPtr.Size == 8;
+ }
+
+ public static string GetRandomString(int iLength)
+ {
+ string buffer = "0123456789";
+ StringBuilder sb = new StringBuilder();
+ Random r = new Random(iLength);
+ int range = buffer.Length;
+ for (int i = 0; i < iLength; i++)
+ {
+ sb.Append(buffer.Substring(r.Next(range), 1));
+ }
+ return sb.ToString();
+ }
+
+ public static string MD5(string str)
+ {
+ MD5 md5 = System.Security.Cryptography.MD5.Create();
+ byte[] byteOld = Encoding.UTF8.GetBytes(str);
+ byte[] byteNew = md5.ComputeHash(byteOld);
+ StringBuilder sb = new StringBuilder();
+ foreach (byte b in byteNew)
+ {
+ // 将字节转换成16进制表示的字符串
+ sb.Append(b.ToString("x2"));
+ }
+ return sb.ToString();
+ }
+
+ public static bool IsTestEnv()
+ {
+ string path = Environment.CurrentDirectory + "\\ShowTestEnv.txt";
+ return File.Exists(path);
+ }
+
+ public static string ConvertMSToTime(int lCurMS, int lDurationMS)
+ {
+ string strTime = "00:00/00:00";
+
+ int nTotalDurationSecond = lDurationMS / 1000;
+ int nDurationMinute = nTotalDurationSecond / 60;
+ int nDurationSecond = nTotalDurationSecond % 60;
+
+ int nTotalCurSecond = lCurMS / 1000;
+ int nCurMinute = nTotalCurSecond / 60;
+ int nCurSecond = nTotalCurSecond % 60;
+
+ string format = "{0:00}:{1:00}/{2:00}:{3:00}";
+
+ strTime = string.Format(format, nCurMinute, nCurSecond, nDurationMinute, nDurationSecond);
+
+ return strTime;
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/ViewModels/LiveWindowViewModel.cs b/JianGongYun/TRTC/ViewModels/LiveWindowViewModel.cs
new file mode 100644
index 0000000..57efc01
--- /dev/null
+++ b/JianGongYun/TRTC/ViewModels/LiveWindowViewModel.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Text;
+
+namespace JianGongYun.TRTC.ViewModels
+{
+ public class LiveWindowViewModel : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ ///
+ /// 教室信息
+ ///
+ public Models.ClassroomEntity ClassroomEntity { get { return LiveClassroom.CurrentClassroomEntity; } }
+
+ ///
+ /// 学生总数
+ ///
+ private int _StudentCount = 0;
+ public int StudentCount
+ {
+ set
+ {
+ _StudentCount = value;
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("StudentCount"));//对StudentCount进行监听
+ }
+ }
+ get
+ {
+ return _StudentCount;
+ }
+ }
+
+ ///
+ /// 是否在直播中
+ ///
+ private bool _IsLive = false;
+ public bool IsLive
+ {
+ set
+ {
+ _IsLive = value;
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("IsLive"));
+ }
+ }
+ get
+ {
+ return _IsLive;
+ }
+ }
+
+ }
+}
diff --git a/JianGongYun/TRTC/ViewModels/SettingWindowViewModel.cs b/JianGongYun/TRTC/ViewModels/SettingWindowViewModel.cs
new file mode 100644
index 0000000..ecc163b
--- /dev/null
+++ b/JianGongYun/TRTC/ViewModels/SettingWindowViewModel.cs
@@ -0,0 +1,304 @@
+using JianGongYun.TRTC.Models;
+using JianGongYun.TRTC.Utils;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Text;
+using System.Linq;
+using System.Windows.Controls;
+using JianGongYun.TRTC.Components;
+using System.Windows;
+
+namespace JianGongYun.TRTC.ViewModels
+{
+ public class SettingWindowViewModel : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// 单例
+ ///
+ private static SettingWindowViewModel _Instance;
+
+ public static SettingWindowViewModel GetInstance()
+ {
+ if (_Instance == null)
+ {
+ _Instance = new SettingWindowViewModel();
+ }
+ return _Instance;
+ }
+
+ ///
+ /// 直播主窗口viewmodel
+ ///
+ private LiveWindowViewModel LiveWindowViewModel
+ {
+ get
+ {
+ return LiveClassroom.CurrentLiveWindow.DataContext == null ? null : LiveClassroom.CurrentLiveWindow.DataContext as LiveWindowViewModel;
+ }
+ }
+
+ #region 麦克风
+ ///
+ /// 集合,实时获取
+ ///
+ public List MicList
+ {
+ get
+ {
+ var mics = LiveClassroom.lTXDeviceManager.getDevicesList(ManageLiteAV.TRTCDeviceType.TXMediaDeviceTypeMic);
+ List micList = new List();
+ var count = mics.getCount();
+ for (uint i = 0; i < count; i++)
+ {
+ var temp = new ComboBoxEntity { Id = mics.getDevicePID(i), Text = mics.getDeviceName(i) };
+ micList.Add(temp);
+ }
+ return micList;
+ }
+ }
+
+ ///
+ /// 当前
+ ///
+ private string _CurrentMic;
+ public string CurrentMic
+ {
+ get
+ {
+ var tempList = this.MicList;
+ if (tempList.Count == 0)
+ {
+ return null;
+ }
+ if (string.IsNullOrEmpty(_CurrentMic) || !tempList.Any(a => a.Id == _CurrentMic))//第一次取或者设备发生变动找不到上次的选择
+ {
+ var localMic = storage.GetValue(INI_ROOT_KEY, INI_KEY_CHOOSE_MIC);//本地缓存
+ if (string.IsNullOrEmpty(localMic))//本地没有就取第一个
+ {
+ _CurrentMic = tempList.First().Id;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_CHOOSE_MIC, _CurrentMic);//生成初始数据
+ }
+ else
+ {
+ _CurrentMic = localMic;
+ var temp = tempList.Where(a => a.Id == localMic).FirstOrDefault();
+ if (temp == null)//找不到上次缓存的设备就取第一个
+ {
+ _CurrentMic = tempList.First().Id;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_CHOOSE_MIC, _CurrentMic);//生成初始数据
+ }
+ }
+ }
+ return _CurrentMic;
+ }
+ set
+ {
+ _CurrentMic = value;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_CHOOSE_MIC, value);//生成保存本地
+ LiveClassroom.lTXDeviceManager.setCurrentDevice(ManageLiteAV.TRTCDeviceType.TXMediaDeviceTypeMic, _CurrentMic);//设置麦克
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("CurrentMic"));//对CurrentMic进行监听
+ }
+ }
+ }
+
+
+ ///
+ /// 麦克风采集音量
+ ///
+ private uint _MicVolume = 100;
+ public uint MicVolume
+ {
+ get
+ {
+ var micVolume = storage.GetValue(INI_ROOT_KEY, INI_KEY_AUDIO_MIC_VOLUME);//本地缓存
+ if (string.IsNullOrEmpty(micVolume))//本地没有就取第一个
+ {
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_MIC_VOLUME, _MicVolume.ToString());//生成初始数据
+ }
+ else
+ {
+ _MicVolume = uint.Parse(micVolume);
+ }
+ return _MicVolume;
+ }
+ set
+ {
+ _MicVolume = value;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_MIC_VOLUME, value.ToString());//生成保存本地
+ var res = LiveClassroom.lTXDeviceManager.setCurrentDeviceVolume(ManageLiteAV.TRTCDeviceType.TXMediaDeviceTypeMic, _MicVolume);//设置麦克音量
+ Console.WriteLine("设置麦克风采集音量" + res);
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("MicVolume"));
+ }
+ }
+ }
+
+
+ #endregion
+
+ #region 音频来源
+
+ ///
+ /// 音频来源
+ ///
+ private string _AudioSource = "1";
+ public string AudioSource
+ {
+ get
+ {
+ var audioSource = storage.GetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SOURCE);//本地缓存
+ if (string.IsNullOrEmpty(audioSource))//本地没有就取第一个
+ {
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SOURCE, _AudioSource);//生成初始数据
+ }
+ else
+ {
+ _AudioSource = audioSource;
+ }
+ return _AudioSource;
+ }
+ set
+ {
+ _AudioSource = value;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SOURCE, value);//生成保存本地
+ if (_AudioSource == "1")//只采集麦克风,关闭系统音采集
+ {
+ ShowSytemGatherSlider = Visibility.Hidden;
+ LiveClassroom.lTRTCCloud.stopSystemAudioLoopback();
+ }
+ else if (_AudioSource == "2")//麦和系统音,开启采集系统音
+ {
+ ShowSytemGatherSlider = Visibility.Visible;
+ LiveClassroom.lTRTCCloud.startSystemAudioLoopback(null);
+ }
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("AudioSource"));
+ }
+ }
+ }
+
+ ///
+ /// 是否显示系统采集滑动条
+ ///
+ private Visibility _ShowSytemGatherSlider = Visibility.Hidden;
+ public Visibility ShowSytemGatherSlider
+ {
+ get
+ {
+ if (AudioSource=="2")
+ {
+ _ShowSytemGatherSlider = Visibility.Visible;
+ }
+ else
+ {
+ _ShowSytemGatherSlider = Visibility.Hidden;
+ }
+ return _ShowSytemGatherSlider;
+ }
+ set
+ {
+ _ShowSytemGatherSlider = value;
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("ShowSytemGatherSlider"));
+ }
+ }
+ }
+
+ ///
+ /// 系统采集音量
+ ///
+ private uint _SytemGatherVolume = 100;
+ public uint SytemGatherVolume
+ {
+ get
+ {
+ var sytemGatherVolume = storage.GetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SYSTEM_GATHER_VOLUME);//本地缓存
+ if (string.IsNullOrEmpty(sytemGatherVolume))//本地没有就取第一个
+ {
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SYSTEM_GATHER_VOLUME, _SytemGatherVolume.ToString());//生成初始数据
+ }
+ else
+ {
+ _SytemGatherVolume = uint.Parse(sytemGatherVolume);
+ }
+ return _SytemGatherVolume;
+ }
+ set
+ {
+ _SytemGatherVolume = value;
+ storage.SetValue(INI_ROOT_KEY, INI_KEY_AUDIO_SYSTEM_GATHER_VOLUME, value.ToString());//生成保存本地
+ LiveClassroom.lTRTCCloud.setSystemAudioLoopbackVolume(_SytemGatherVolume);//设置系统采集音量
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs("SytemGatherVolume"));
+ }
+ }
+ }
+
+
+ #endregion
+
+
+ ///
+ /// ini文件操作
+ ///
+ private IniStorage storage;
+ private SettingWindowViewModel()
+ {
+ storage = new IniStorage(sPath);
+ }
+
+ #region 配置持久化
+
+ //配置文件路径
+ private string sPath = ".\\TRTCConfig.ini";
+ //根节点
+ public const string INI_ROOT_KEY = "TRTCLOCALCONFIG";
+ // 设备
+ public const string INI_KEY_CHOOSE_CAMERA = "INI_KEY_CHOOSE_CAMERA";//当前摄像头
+ public const string INI_KEY_CHOOSE_MIC = "INI_KEY_CHOOSE_MIC";//当前麦克风
+ // 音频
+ public const string INI_KEY_AUDIO_MIC_VOLUME = "INI_KEY_AUDIO_MIC_VOLUME";//麦克风音量
+ public const string INI_KEY_AUDIO_SPEAKER_VOLUME = "INI_KEY_AUDIO_SOURCE";//播放音量
+ public const string INI_KEY_AUDIO_SOURCE = "INI_KEY_AUDIO_SOURCE";//音频来源
+ public const string INI_KEY_AUDIO_SYSTEM_GATHER_VOLUME = "INI_KEY_AUDIO_SYSTEM_GATHER_VOLUME";//麦克风音量
+ // 视频
+ public const string INI_KEY_VIDEO_FPS = "INI_KEY_VIDEO_FPS";//视频FPS
+ public const string INI_KEY_VIDEO_BITRATE = "INI_KEY_VIDEO_BITRATE";
+ public const string INI_KEY_VIDEO_RESOLUTION = "INI_KEY_VIDEO_RESOLUTION";
+ public const string INI_KEY_VIDEO_RES_MODE = "INI_KEY_VIDEO_RES_MODE";
+ public const string INI_KEY_VIDEO_QUALITY = "INI_KEY_VIDEO_QUALITY";
+ public const string INI_KEY_VIDEO_QUALITY_CONTROL = "INI_KEY_VIDEO_QUALITY_CONTROL";
+ public const string INI_KEY_VIDEO_APP_SCENE = "INI_KEY_VIDEO_APP_SCENE";
+ public const string INI_KEY_VIDEO_FILL_MODE = "INI_KEY_VIDEO_FILL_MODE";
+ public const string INI_KEY_VIDEO_ROTATION = "INI_KEY_VIDEO_ROTATION";
+ // 美颜
+ public const string INI_KEY_BEAUTY_OPEN = "INI_KEY_BEAUTY_OPEN";
+ public const string INI_KEY_BEAUTY_STYLE = "INI_KEY_BEAUTY_STYLE";
+ public const string INI_KEY_BEAUTY_VALUE = "INI_KEY_BEAUTY_VALUE";
+ public const string INI_KEY_WHITE_VALUE = "INI_KEY_WHITE_VALUE";
+ public const string INI_KEY_RUDDINESS_VALUE = "INI_KEY_RUDDINESS_VALUE";
+ // 大小流
+ public const string INI_KEY_SET_PUSH_SMALLVIDEO = "INI_KEY_SET_PUSH_SMALLVIDEO";
+ public const string INI_KEY_SET_PLAY_SMALLVIDEO = "INI_KEY_SET_PLAY_SMALLVIDEO";
+ // 测试
+ public const string INI_KEY_SET_NETENV_STYLE = "INI_KEY_SET_NETENV_STYLE";
+ public const string INI_KEY_ROOMCALL_STYLE = "INI_KEY_ROOMCALL_STYLE";
+ // 镜像
+ public const string INI_KEY_LOCAL_VIDEO_MIRROR = "INI_KEY_LOCAL_VIDEO_MIRROR";
+ public const string INI_KEY_REMOTE_VIDEO_MIRROR = "INI_KEY_REMOTE_VIDEO_MIRROR";
+ // 音量提示
+ public const string INI_KEY_SHOW_AUDIO_VOLUME = "INI_KEY_SHOW_AUDIO_VOLUME";
+ // 混流
+ public const string INI_KEY_CLOUD_MIX_TRANSCODING = "INI_KEY_CLOUD_MIX_TRANSCODING";
+ #endregion
+ }
+}
diff --git a/JianGongYun/TRTC/Windows/LiveWindow.xaml b/JianGongYun/TRTC/Windows/LiveWindow.xaml
new file mode 100644
index 0000000..e5a6c52
--- /dev/null
+++ b/JianGongYun/TRTC/Windows/LiveWindow.xaml
@@ -0,0 +1,55 @@
+
+
+
+ M512 884.363636c-50.059636 0-98.722909-9.890909-144.64-29.393454a372.922182 372.922182 0 0 1-118.365091-79.965091 372.922182 372.922182 0 0 1-79.965091-118.365091A367.872 367.872 0 0 1 139.636364 512c0-50.036364 9.890909-98.722909 29.393454-144.64a372.945455 372.945455 0 0 1 79.965091-118.365091 372.922182 372.922182 0 0 1 118.365091-79.965091A367.872 367.872 0 0 1 512 139.636364c50.059636 0 98.722909 9.890909 144.64 29.393454a372.945455 372.945455 0 0 1 118.365091 79.965091 372.922182 372.922182 0 0 1 79.965091 118.365091A367.872 367.872 0 0 1 884.363636 512c0 50.059636-9.890909 98.722909-29.393454 144.64a372.945455 372.945455 0 0 1-79.965091 118.365091 372.922182 372.922182 0 0 1-118.365091 79.965091A367.848727 367.848727 0 0 1 512 884.363636z m0-698.181818c-43.776 0-86.341818 8.634182-126.464 25.693091a326.516364 326.516364 0 0 0-103.633455 70.050909 326.516364 326.516364 0 0 0-70.027636 103.610182A321.629091 321.629091 0 0 0 186.181818 512c0 43.776 8.634182 86.341818 25.693091 126.464a326.516364 326.516364 0 0 0 70.050909 103.633455 326.516364 326.516364 0 0 0 103.610182 70.027636A321.652364 321.652364 0 0 0 512 837.818182c43.776 0 86.341818-8.657455 126.464-25.693091a326.516364 326.516364 0 0 0 103.633455-70.050909 326.516364 326.516364 0 0 0 70.027636-103.610182A321.652364 321.652364 0 0 0 837.818182 512c0-43.776-8.657455-86.341818-25.693091-126.464a326.516364 326.516364 0 0 0-70.050909-103.633455 326.516364 326.516364 0 0 0-103.610182-70.027636A321.652364 321.652364 0 0 0 512 186.181818z m-170.077091 512.162909a18.013091 18.013091 0 0 1-17.408-22.667636l70.865455-265.774546a18.013091 18.013091 0 0 1 12.753454-12.753454l265.774546-70.865455a18.013091 18.013091 0 0 1 22.039272 22.039273l-70.865454 265.774546a18.013091 18.013091 0 0 1-12.776727 12.753454L346.554182 697.716364a18.013091 18.013091 0 0 1-4.654546 0.628363z m85.573818-269.079272l-60.16 225.62909 225.605818-60.16 60.16-225.62909-225.605818 60.16z m111.755637 126.138181a17.966545 17.966545 0 0 1-12.730182-5.282909l-46.801455-46.778182a18.013091 18.013091 0 1 1 25.483637-25.506909l46.778181 46.801455a18.013091 18.013091 0 0 1-12.730181 30.766545z
+
+
+
diff --git a/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs b/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs
new file mode 100644
index 0000000..f59a34b
--- /dev/null
+++ b/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs
@@ -0,0 +1,49 @@
+using AduSkin.Controls.Metro;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using System.Linq;
+
+namespace JianGongYun.TRTC.Windows
+{
+ ///
+ /// LiveWindow.xaml 的交互逻辑
+ ///
+ public partial class LiveWindow : MetroWindow
+ {
+ ViewModels.LiveWindowViewModel LiveWindowViewModel;
+ public LiveWindow()
+ {
+ InitializeComponent();
+ LiveWindowViewModel =new ViewModels.LiveWindowViewModel();
+ this.DataContext = LiveWindowViewModel;
+ BorderBrush = new SolidColorBrush(color: Color.FromRgb(42, 43, 48));//窗口标题背景颜色
+
+ }
+ private void aaaa(object sender, RoutedEventArgs e)
+ {
+ LiveWindowViewModel.StudentCount++;
+ }
+
+ //设置按钮
+ private void Setting_Btn_Click(object sender, RoutedEventArgs e)
+ {
+ var settingWindow = SettingWindow.GetInstance();
+ settingWindow.Show();
+ if (settingWindow.WindowState != WindowState.Normal)
+ {
+ settingWindow.WindowState = WindowState.Normal;
+ }
+ settingWindow.Topmost = true;
+ }
+ }
+}
diff --git a/JianGongYun/TRTC/Windows/SettingWindow.xaml b/JianGongYun/TRTC/Windows/SettingWindow.xaml
new file mode 100644
index 0000000..6d982e3
--- /dev/null
+++ b/JianGongYun/TRTC/Windows/SettingWindow.xaml
@@ -0,0 +1,62 @@
+
+
+
+
+ 音频设置
+
+
+ 录屏设置
+
+
+ 直播设置
+
+
+
+
+
+
+
+
+ 麦克风
+
+
+
+
+ 麦采集音量
+
+
+
+ 音频来源
+
+
+
+
+
+
+ 系统采集音量
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JianGongYun/TRTC/Windows/SettingWindow.xaml.cs b/JianGongYun/TRTC/Windows/SettingWindow.xaml.cs
new file mode 100644
index 0000000..083d118
--- /dev/null
+++ b/JianGongYun/TRTC/Windows/SettingWindow.xaml.cs
@@ -0,0 +1,91 @@
+using AduSkin.Controls.Metro;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace JianGongYun.TRTC.Windows
+{
+ ///
+ /// SettingWindow.xaml 的交互逻辑
+ ///
+ public partial class SettingWindow : MetroWindow
+ {
+ ///
+ /// 单例
+ ///
+ private static SettingWindow _Instance;
+ public static SettingWindow GetInstance()
+ {
+ if (_Instance == null)
+ {
+ _Instance = new SettingWindow();
+ }
+ return _Instance;
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ _Instance = null;
+ if (micTesting)//关闭麦克风测试
+ {
+ LiveClassroom.lTXDeviceManager.stopMicDeviceTest();
+ }
+ base.OnClosed(e);
+ }
+ ViewModels.SettingWindowViewModel mode = ViewModels.SettingWindowViewModel.GetInstance();
+ private SettingWindow()
+ {
+ InitializeComponent();
+ BorderBrush = new SolidColorBrush(color: Color.FromRgb(42, 43, 48));//窗口标题背景颜色
+ this.DataContext = mode;
+ }
+
+ bool micTesting = false;
+ private void TestMic(object sender, RoutedEventArgs e)
+ {
+ if (micTesting)
+ {
+ LiveClassroom.lTXDeviceManager.stopMicDeviceTest();
+ this.Dispatcher.Invoke(new Action(() =>
+ {
+ this.MicTestBtn.Content = "检测麦克风";
+ this.MicTestBtn.Type = AduSkin.Controls.FlatButtonSkinEnum.info;
+ micTesting = false;
+ }));
+ }
+ else
+ {
+ if (LiveClassroom.lTXDeviceManager.startMicDeviceTest(1000) == 0)
+ {
+ this.Dispatcher.Invoke(new Action(() =>
+ {
+ this.MicTestBtn.Content = "停止检测";
+ this.MicTestBtn.Type = AduSkin.Controls.FlatButtonSkinEnum.error;
+ micTesting = true;
+ }));
+ }
+ else
+ {
+ AduMessageBox.Show("测试失败", "提醒");
+ }
+ }
+ }
+
+ protected override void OnActivated(EventArgs e)
+ {
+ base.OnActivated(e);
+ //滑动条颜色前台设置无效,手动调用才行
+ var sliderColor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#3e7fff"));
+ Slider1.DecreaseColor = sliderColor;
+ Slider2.DecreaseColor = sliderColor;
+ }
+ }
+}
diff --git a/JianGongYun/Views/TeachingInfo.xaml b/JianGongYun/Views/TeachingInfo.xaml
index 586c7fc..b638fb9 100644
--- a/JianGongYun/Views/TeachingInfo.xaml
+++ b/JianGongYun/Views/TeachingInfo.xaml
@@ -21,40 +21,45 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JianGongYun/Views/TeachingInfo.xaml.cs b/JianGongYun/Views/TeachingInfo.xaml.cs
index 32dad7d..52828ed 100644
--- a/JianGongYun/Views/TeachingInfo.xaml.cs
+++ b/JianGongYun/Views/TeachingInfo.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using JianGongYun.TRTC;
+using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
@@ -21,5 +22,17 @@ namespace JianGongYun.Views
{
InitializeComponent();
}
+
+ private void LiveTest_Click(object sender, RoutedEventArgs e)
+ {
+ LiveClassroom.EnterTheClassroom(Window.GetWindow(this),
+ new TRTC.Models.ClassroomEntity
+ {
+ ClassHead = "课程1",
+ ClassSubHead = "章节1",
+ TeacherId = "53245345",
+ TeacherName = "王大锤"
+ });
+ }
}
-}
+}
\ No newline at end of file