From 923b57e7b0fa3a653a19f19cb8b9f62d32d51f14 Mon Sep 17 00:00:00 2001 From: sbd021 Date: Fri, 8 Oct 2021 15:35:08 +0800 Subject: [PATCH] plugin pubish obs camera video to rtc seperately --- data/locale/Ru-RU-0927.ini | 108 ++++ data/locale/de-DE-0927.ini | 108 ++++ data/locale/en-ES-0927.ini | 108 ++++ data/locale/en-US.ini | 13 +- data/locale/zh-CN.ini | 11 +- data/locale/zh-TW.ini | 11 +- installer/agora-tool-obs-25.0.8-32.nsi | 86 --- installer/agora-tool-obs-25.0.8.nsi | 86 --- installer/agora-tool-obs-26.0.2-32.nsi | 86 --- installer/agora-tool-obs-3.3.0.nsi | 88 --- ...s-3.3.3.nsi => agora-tool-obs-3.6.200.nsi} | 2 +- src/Agora/agorartcengine.cpp | 510 ++++++++++++------ src/Agora/agorartcengine.hpp | 41 +- src/agora-plugin/video-plugin-filter.cpp | 149 +++++ src/agora-ui-main.cpp | 4 + src/forms/AgoraBasic.ui | 6 +- src/forms/AgoraSettings.ui | 227 +++++--- src/forms/window-agora-main.cpp | 141 +++-- src/forms/window-agora-main.hpp | 14 +- src/forms/window-agora-settings.cpp | 190 +++++-- src/forms/window-agora-settings.hpp | 5 + 21 files changed, 1328 insertions(+), 666 deletions(-) create mode 100644 data/locale/Ru-RU-0927.ini create mode 100644 data/locale/de-DE-0927.ini create mode 100644 data/locale/en-ES-0927.ini delete mode 100644 installer/agora-tool-obs-25.0.8-32.nsi delete mode 100644 installer/agora-tool-obs-25.0.8.nsi delete mode 100644 installer/agora-tool-obs-26.0.2-32.nsi delete mode 100644 installer/agora-tool-obs-3.3.0.nsi rename installer/{agora-tool-obs-3.3.3.nsi => agora-tool-obs-3.6.200.nsi} (98%) create mode 100644 src/agora-plugin/video-plugin-filter.cpp diff --git a/data/locale/Ru-RU-0927.ini b/data/locale/Ru-RU-0927.ini new file mode 100644 index 00000000..575226cd --- /dev/null +++ b/data/locale/Ru-RU-0927.ini @@ -0,0 +1,108 @@ +AgoraTool.Settings.DialogTitle="妒扶扼找把批技快扶找 均忍抉把抑 RTC" +Agora.Main.Start="妖忘折忘找抆 扼找把我技我扶忍 扶忘 均忍抉把忘" +Agora.Main.Starting="扼找把我技我扶忍 扶忘 均忍抉把忘 志 扭把抉扯快扼扼快" +Agora.Main.Stop="妤把快抗把忘找我找抆 扼找把我技我扶忍 扶忘 均忍抉把忘" +Agora.Main.Stopping="妤把快抗把忘找我找抆 扼找把我技我扶忍 扶忘 均忍抉把忘 志 扭把抉扯快扼扼快" +Agora.Main.Controls="批扭把忘志抖快扶我快" +Agora.Settings.General="妍忌投快快" +Agora.Settings.Audio="均批忱我抉" +Agora.Settings.Video="志我忱快抉" +Basic.Settigs.Agora.LoadConfig="妝忘忍把批戒我找抆 扳忘抄抖 抗抉扶扳我忍批把忘扯我我" +Basic.Settigs.Agora.LoadConfigButton="妝忘忍把批戒我找抆" +Basic.Settings.Agora.APPID="均忍抉把忘 APPID" +Basic.Settings.Agora.APPTOKEN="Agora Token(扶忘 志抑忌抉把)" +Basic.Settings.Agora.Token.Expired="妊把抉抗 忱快抄扼找志我攸" +Basic.Settings.Agora.ChannelName="妖忘戒志忘扶我快 抗忘扶忘抖忘" +Basic.Settings.Agora.UID="ID 扭抉抖抆戒抉志忘找快抖攸 (扶忘 志抑忌抉把)" +Basic.Settings.Agora.Video.Resolution="把忘戒把快扮快扶我快" +Basic.Settings.Agora.PersistSave="妊抉抒把忘扶我找快 志扼快 扶忘扼找把抉抄抗我, 抗把抉技快 APPID, 志抗抖攻折忘攸 扶忘扼找把抉抄抗我 忘批忱我抉, 志我忱快抉 我 Rtmp." +Basic.Settings.Agora.MutAllRemoteAudioVideo="妍找抗抖攻折快扶我快 志扼快抒 批忱忘抖快扶扶抑抒 忘批忱我抉 我 志我忱快抉" +Agora.Settings.Recording="妊抉抒把忘扶快扶我快 扭忘把忘技快找把抉志 批扼找把抉抄扼找志忘" +Agora.Record.Devices="技我抗把抉扳抉扶" +Agora.Record.Devices.Volume="坐把抉技抗抉扼找抆 技我抗把抉扳抉扶忘" +Agora.Settings.Playout.Devices="扶忘扼找把抉抄抗我 扼扭我抗快把忘" +Agora.Playout.Devices="扼扭我抗快把" +Agora.Payout.Devices.Volume="坐把抉技抗抉扼找抆 批扼找把抉抄扼找志忘 扼扭我抗快把忘" +Agora.Settings.Video.BaseResolution="圾抑抒抉忱扶抉快 把忘戒把快扮快扶我快" +Agora.Settings.Video.FPS="Output FPS" +Agora.Settings.Video.Birate="Output 忌我找把快抄找" +Agora.Settings.Video.Devices="圾我忱快抉批扼找把抉抄扼找志抉" +Agora.Settings.Video.FPS5="5fps" +Agora.Settings.Video.FPS7="7fps" +Agora.Settings.Video.FPS10="10fps" +Agora.Settings.Video.FPS15="15fps" +Agora.Settings.Video.FPS24="24fps" +Agora.Settings.Video.FPS30="30fps" +Agora.Settings.Video.FPS60="60fps" +Agora.Bitrate.Default="坎我找把快抄找 扭抉 批技抉抖折忘扶我攻" +Agora.Bitrate.Compatible="妊抉志技快扼找我技抑抄 坎我找把快抄找" +Agora.Bitrate.Standard="妊找忘扶忱忘把找扶抑抄 忌我找把快抄找" +Agora.General.Appid.Set="妒扶我扯我忘抖我戒我把抉志忘找抆" +Agora.Settings.Loopback="Loopback" +Basic.Agora.AutoLoadConfig="均志找抉技忘找我折快扼抗忘攸 戒忘忍把批戒抗忘 抗抉扶扳我忍批把忘扯我我 均忍抉把忘(Check Persist Save First)" +Agora.General.EmptyAppid="圾抑志快忱我找快 APPID" +Agora.General.Init.Failed="妍扮我忌抗忘 我扶我扯我忘抖我戒忘扯我我 均忍抉把忘 Engine. 妤把抉志快把抆找快 appid.." +Agora.General.EmptyChannel="妤抉忪忘抖批抄扼找忘, 志志快忱我找快 扶抉技快把 抗忘扶忘抖忘" +Agora.General.EmptyUID="妤抉忪忘抖批抄扼找忘, 志志快忱我找快 UID" +Agora.Settings.Rtmp="Agora Rtmp" +Agora.Settings.Rtmp.Url="Url" +Agora.Settings.Rtmp.FPS="FPS" +Agora.Settings.Rtmp.Bitrate="坎我找把快抄找" +Agora.Settings.Rtmp.Width="宋我把我扶忘" +Agora.Settings.Rtmp.Height="圾抑扼抉找忘" +Basic.Settings.Agora.AudioProfile.DefaultScenario="妊扯快扶忘把我抄 扭抉 批技抉抖折忘扶我攻" +Basic.Settings.Agora.AudioProfile.ChatRoomScenario="妊扯快扶忘把我抄 折忘找-把批技" +Basic.Settings.Agora.AudioProfile.EducationScenario="妊扯快扶忘把我抄 抉忌批折快扶我攸" +Basic.Settings.Agora.AudioProfile.GameStreamingScenario="妊扯快扶忘把我抄 我忍把忘-扼找把我技我扶忍" +Basic.Settings.Agora.AudioProfile.ShowRoomScenario="妊扯快扶忘把我抄 ShowRoom" +Basic.Settings.Agora.AudioProfile.ChatRoomGameScenario="妊扯快扶忘把我抄 我忍把抑 志 折忘找-把批技" +Basic.Settings.Agora.AudioProfile.IOTScenario="IOT 妊扯快扶忘把我抄" +Basic.Settings.Agora.AudioProfile.MettingScenario="妊扯快扶忘把我抄 志扼找把快折我" +Basic.Settings.Agora.AudioProfile.Scenario="均批忱我抉 扼扯快扶忘把我抄" +Basic.Settings.Agora.AudioProfile.SuggestScenario="妊扯快扶忘把我抄 扭抉 批技抉抖折忘扶我攻" +Basic.Settings.Agora.AudioProfile.High="圾抑扼抉抗抉忍抉 抗忘折快扼找志忘(妊扯快扶忘把我抄 扭抉 批技抉抖折忘扶我攻)" +Basic.Main.Agora.Empty.Information="妖忘扼找把抉抄抗我 均忍抉把忘 志 忱我忘抖抉忍抉志抉技 抉抗扶快 扶忘扼找把抉快抗, 志志快忱我找快 " +Basic.Main.Agora.Invalid.Token="妖快志快把扶抑抄 找抉抗快扶, 志志快忱我找快 忱快抄扼找志我找快抖抆扶抑抄 找抉抗快扶 志 忱我忘抖抉忍抉志抉技 抉抗扶快 扶忘扼找把抉抄抗我" +Basic.Main.Agora.Token.Expired="妊把抉抗 忱快抄扼找志我攸 找抉抗快扶忘 我扼找快抗, 扭抉志找抉把扶抉 扼忍快扶快把我把批抄找快 找抉抗快扶 我 志志快忱我找快 忱快抄扼找志我找快抖抆扶抑抄 找抉抗快扶 志 忱我忘抖抉忍抉志抉技 抉抗扶快 扶忘扼找把抉抄抗我" +Basic.Main.Agora.Invalid.Channel="妖快志快把扶抑抄 抗忘扶忘抖, 志志快忱我找快 忱快抄扼找志我找快抖抆扶抑抄 抗忘扶忘抖 志 忱我忘抖抉忍抉志抉技 抉抗扶快 扶忘扼找把抉抄抗我" +Basic.Main.Agora.Invalid.Appid="妖快忱快抄扼找志我找快抖抆扶抑抄 Appid, 志志快忱我找快 忱快抄扼找志我找快抖抆扶抑抄 Appid 志 忱我忘抖抉忍抉志抉技 抉抗扶快 扶忘扼找把抉抄抗我" +Agora.Settings.Video.Agora.Bitrate="攻戒忘找抆 忌我找把快抄找 Agora" +Agora.Settings.Video.OBS.Bitrate="攻戒忘找抆 OBS 忌我找把快抄找" +Agora.Settings.Video.Encoder="Output 忌我找把快抄找" +Agora.Settings.Video.FPS.Resolution="攻戒忘找抆 OBS FPS and 把忘戒把快扮快扶我快" +Basic.Settings.Agora.PersistSaveAppid="抒把忘扶我找抆 志快折扶抉 APPID" +Basic.Settings.Agora.PersistSaveAppidInfo="APPID 忌批忱快找 扼抉抒把忘扶快扶 志 basic.ini 抗抉扶扳我忍 扳忘抄抖忘 OBS, 扭抉找抉技批 折找抉 志抑 抉找技快找我找快 抉扭扯我攻 抒把忘扶我找抆 志快折扶抉 appid. 妙抑 扭把快忱抖忘忍忘快技 扶快 扼抉抒把忘扶攸找抆 appid 志 抖抉抗忘抖抆扶抉技 扳忘抄抖快 抗抉扶扳我忍批把忘扯我我.." +Agora.JoinChannelFailed.Token="妍扮我忌抗忘 扭把我扼抉快忱我扶快扶我攸 抗 抗忘扶忘抖批, 技抉忪快找 忌抑找抆 扶快忱抉扭批扼找我技抑抄 appid, 抗忘扶忘抖, 找抉抗快扶, 扭把抉扼把抉折快扶扶抑抄 找抉抗快扶 我 找. 坏." +Agora.Settings.Agora.APPTOKEN.URL="妝忘扭把抉扼 妒扶扳抉把技忘扯我攸 抉 扭抉抖抆戒抉志忘找快抖快 Url" +Agora.Main.Request.Token.Error="妝忘扭把抉扼 我扶扳抉把技忘扯我我 扭抉抖抆戒抉志忘找快抖攸 扶快 批忱忘抖抉扼抆" +Agora.Settings.GetInfo.Mode="妓快忪我技 扭抉抖批折快扶我攸 我扶扳抉把技忘扯我我 抉 抗忘扶忘抖快" +Agora.Settings.GetInfo.Mode.Information="妤抉抖批折我找快 我扶扳抉把技忘扯我攻 抉 appid, 找抉抗快扶快 扭把我抖抉忪快扶我攸, 我技快扶我 抗忘扶忘抖忘 我 uid. 圻扼抖我 志抑 志抑忌快把快找快 http , 志忘技 扶批忪扶抉 批抗忘戒忘找抆 URL." +Agora.Settings.GetInfo.Mode.Manaul="圾志抉忱 我扶扳抉把技忘扯我我 志把批折扶批攻" +Agora.Settings.GetInfo.Mode.Http.Get="妤抉抖批折我找抆 我扶扳抉把技忘扯我攻 扭抉 HTTP-戒忘扭把抉扼批" +Agora.Setting.TestNet.Start="妖忘折忘找抆 妥快扼找 妊快找抆" +Agora.Setting.TestNet.Stop="妊找抉扭 妥快扼找 妊快找抆" +Agora.Test.Network.Result.Unknown="妞忘折快扼找志抉 扼快找我 扶快我戒志快扼找扶抉." +Agora.Test.Network.Result.Excellent="妞忘折快扼找志抉 扼快找我 扼批扭快把!" +Agora.Test.Network.Result.Good="妞忘折快扼找志抉 扼快找我 扶快扭抖抉抒抉快, 扶抉 忌我找把快抄找 技抉忪快找 忌抑找抆 扶快技扶抉忍抉 扶我忪快 抉找抖我折扶抉忍抉." +Agora.Test.Network.Result.Poor="妤抉抖抆戒抉志忘找快抖我 技抉忍批找 扭抉折批志扼找志抉志忘找抆 抖快忍抗抉快 扶忘把批扮快扶我快 扼志攸戒我." +Agora.Test.Network.Result.Bad="妤抉抖抆戒抉志忘找快抖我 扶快 技抉忍批找 扭抖忘志扶抉 抉忌投忘找抆扼攸. (妓快抗抉技快扶忱批快找扼攸 扼扶我戒我找抆 忌我找把快抄找, FPS 我 把忘戒把快扮快扶我快)" +Agora.Test.Network.Result.VBad="妊快找抆 扶忘扼找抉抖抆抗抉 扭抖抉抒忘, 折找抉 扭抉抖抆戒抉志忘找快抖我 扭把忘抗找我折快扼抗我 扶快 技抉忍批找 抉忌投忘找抆扼攸." +Agora.Test.Network.Result.Down="妊快找抆 扶快 把忘忌抉找忘快找, 我 扭抉抖抆戒抉志忘找快抖我 志抉抉忌投快 扶快 技抉忍批找 抉忌投忘找抆扼攸."(妤把抉志快把抆找快 扼快找抆, 批忌快忱我找快扼抆, 折找抉 扼快找抆 志 扭抉把攸忱抗快)" +Agora.Test.Network.Result.UnSupported="妤抉抖抆戒抉志忘找快抖我 扶快 技抉忍批找 抉忌扶忘把批忪我找抆 抗忘折快扼找志抉 扼快找我. (Not in use).." +Agora.Test.Network.Result.Detecting="妍扭把快忱快抖快扶我快 抗忘折快扼找志忘 扼快找我." +Agora.Settings.NetworkTest="妥快扼找我把抉志忘扶我快 扼快找我" +Agora.Network.Testing="妥快扼找 扼快找抆 志 扭把抉扯快扼扼快..." +Agora.Network.Testing.Info="圾抑 找快扼找我把批快找快 扼快找抆. 妊扶忘折忘抖忘 扭把快抗把忘找我找快 找快扼找我把抉志忘扶我快 扼快找我." +Basic.Settings.Agora.Save.PCM="妊抉抒把忘扶我找抆 OBS PCM Data(in the path of obs logs)" +Agora.System.CPU.Infomation="妍忌扶忘把批忪快扶忘 志抑扼抉抗忘攸 戒忘忍把批戒抗忘 CPU. 尿找抉 技抉忪快找 志抑戒志忘找抆 扼忌抉抄 戒志批抗忘 我 扭抉志抖我攸找抆 扶忘 抗忘折快扼找志抉 扼找把我技我扶忍. 妤抉扭把抉忌批抄找快 戒忘抗把抑找抆 扶快把快抖快志忘扶找扶抑快 扭把我抖抉忪快扶我攸, 折找抉忌抑 扼扶我戒我找抆 扶忘忍把批戒抗批 扶忘 CPU." +Agora.CPU.Threshold="妤抉把抉忍 CPU" +Agora.Settings.DualStream="坏志抉抄扶抉抄 扼找把我技" +Camera.Encoder.Settings.Resolution="妓忘戒把快扮快扶我快 抗抉忱我把抉志投我抗忘 抗忘技快把抑" +Camera.Encoder.Settings.Bitrate="妞忘技快把忘 抗抉忱我把抉志投我抗 坎我找把快抄找" +Camera.Encoder.Settings.FPS="妞忘技快把忘 抗抉忱我把抉志投我抗 FPS" +Plugin.Settings.Camera.UID="妞忘技快把忘 UID" +Plugin.Settings.SendObsCamera="妍找扭把忘志我找抆 OBS Camera Video" +Plugin.OBS.Camera.UID.Empty="妞忘技快把忘 UID 扭批扼找忘" +Plugin.OBS.Camera.UID.Conflict="UID 抗忘技快把抑 忱抉抖忪快扶 抉找抖我折忘找抆扼攸 抉找 UID" +Plugin.Settings.Camera.Token="Camera 妝忘扶攸找忘" +Plugin.Settings.Error.EmptyUrl="URL 戒忘扭把抉扼忘 扭批扼找. 妝忘扭抉抖扶我找快 忱快抄扼找志我找快抖抆扶抑抄 http-URL" \ No newline at end of file diff --git a/data/locale/de-DE-0927.ini b/data/locale/de-DE-0927.ini new file mode 100644 index 00000000..58aa3b56 --- /dev/null +++ b/data/locale/de-DE-0927.ini @@ -0,0 +1,108 @@ +嚜澤goraTool.Settings.DialogTitle="Agora RTC-Tool" +Agora.Main.Start="Streaming zu Agora starten" +Agora.Main.Starting="Streaming zu Agora gleich gestartet" +Agora.Main.Stop="Streaming zu Agora stoppen" +Agora.Main.Stopping="Streaming zu Agora gleich gestoppt" +Agora.Main.Controls="Steuerung" +Agora.Settings.General="Allgemein" +Agora.Settings.Audio="Audio" +Agora.Settings.Video="Video" +Basic.Settigs.Agora.LoadConfig="Konfigurationsdatei laden" +Basic.Settigs.Agora.LoadConfigButton="Laden" +Basic.Settings.Agora.APPID="Agora-APPID" +Basic.Settings.Agora.APPTOKEN="AgoraToken(Optional)" +Basic.Settings.Agora.Token.Expired="Token abgelaufene Stunde" +Basic.Settings.Agora.ChannelName="Kanalname" +Basic.Settings.Agora.UID="Uid(Optional)" +Basic.Settings.Agora.Video.Resolution="Aufl繹sung" +Basic.Settings.Agora.PersistSave="Alle Einstellungen auer APPID speichern, einschlielich Audio-, Video- und Rtmp-Einstellungen" +Basic.Settings.Agora.MutAllRemoteAudioVideo="Alle Remote-Audio und -Video stumm schalten" +Agora.Settings.Recording="Mikrofon-Einstellungen" +Agora.Record.Devices="Mikrofon" +Agora.Record.Devices.Volume="Lautst瓣rke des Mikrofons" +Agora.Settings.Playout.Devices="Lautsprecher-Einstellungen" +Agora.Playout.Devices="Lautsprecher" +Agora.Payout.Devices.Volume="Lautst瓣rke des Lautsprechers" +Agora.Settings.Video.BaseResolution="Output-Aufl繹sung" +Agora.Settings.Video.FPS="Output-FPS" +Agora.Settings.Video.Birate="Output-Bitrate" +Agora.Settings.Video.Devices="Videoger瓣t" +Agora.Settings.Video.FPS5="5fps" +Agora.Settings.Video.FPS7="7fps" +Agora.Settings.Video.FPS10="10fps" +Agora.Settings.Video.FPS15="15fps" +Agora.Settings.Video.FPS24="24fps" +Agora.Settings.Video.FPS30="30fps" +Agora.Settings.Video.FPS60="60fps" +Agora.Bitrate.Default="Vorgegebene Bitrate" +Agora.Bitrate.Compatible="Kompatible Birate" +Agora.Bitrate.Standard="Standard-Birate" +Agora.General.Appid.Set="Initialisieren" +Agora.Settings.Loopback="Loopback" +Basic.Agora.AutoLoadConfig="Agora-Config automatisch laden (Effektiv nur wenn F羹r-immer-Speichern gew瓣hlt ist )" +Agora.General.EmptyAppid="Appid eingeben" +Agora.General.Init.Failed="Initialisierung von Agora gescheitert.APPID 羹berpr羹fen." +Agora.General.EmptyChannel="Kanalnamen eingeben" +Agora.General.EmptyUID="UID eingeben" +Agora.Settings.Rtmp="Agora-Rtmp" +Agora.Settings.Rtmp.Url="Url" +Agora.Settings.Rtmp.FPS="FPS" +Agora.Settings.Rtmp.Bitrate="Bitrate" +Agora.Settings.Rtmp.Width="Breite" +Agora.Settings.Rtmp.Height="H繹he" +Basic.Settings.Agora.AudioProfile.DefaultScenario="Vorgegebenes Szenario" +Basic.Settings.Agora.AudioProfile.ChatRoomScenario="ChatRoom-Szenario" +Basic.Settings.Agora.AudioProfile.EducationScenario="Ausbildung-Szenario" +Basic.Settings.Agora.AudioProfile.GameStreamingScenario="GameStreaming-Szenario" +Basic.Settings.Agora.AudioProfile.ShowRoomScenario="ShowRoom-Szenario" +Basic.Settings.Agora.AudioProfile.ChatRoomGameScenario="ChatRoom-Gaming-Szenario" +Basic.Settings.Agora.AudioProfile.IOTScenario="IOT-Szenario" +Basic.Settings.Agora.AudioProfile.MettingScenario="Sitzung-Szenario" +Basic.Settings.Agora.AudioProfile.Scenario="Audio-Szenario" +Basic.Settings.Agora.AudioProfile.SuggestScenario="Vorschlagendes Szenario" +Basic.Settings.Agora.AudioProfile.High="Hohe Qualit瓣t(Vorschlagendes Szenario)" +Basic.Main.Agora.Empty.Information="Agora-Einstellungen im Einstellungsdialog, bitte eingeben " +Basic.Main.Agora.Invalid.Token="Ung羹ltiges Token, bitte ein g羹ltiges Token im Einstellungsdialog eingeben" +Basic.Main.Agora.Token.Expired="Token abgelaufen, bitte Token neu generieren und g羹ltiges Token im Einstellungsdialog eingeben" +Basic.Main.Agora.Invalid.Channel="Ung羹ltiger Kanal, bitte einen g羹ltigen Kanal im Einstellungsdialog eingeben" +Basic.Main.Agora.Invalid.Appid="Ung羹ltige APPID, bitte eine g羹ltige APPID im Einstellungsdialog eingeben" +Agora.Settings.Video.Agora.Bitrate="Agora-Bitrate verwenden" +Agora.Settings.Video.OBS.Bitrate="OBS-Bitrate verwenden" +Agora.Settings.Video.Encoder="Output-Bitrate" +Agora.Settings.Video.FPS.Resolution="OBS-FPS und Aufl繹sung verwenden" +Basic.Settings.Agora.PersistSaveAppid="APPID f羹r immer speichern" +Basic.Settings.Agora.PersistSaveAppidInfo="APPID wird in basic.ini von OBS-Konfigurationsdatei gespeichert. Wir empfehlen, APPID nicht in der lokalen Konfigurationsdatei zu speichern ." +Agora.JoinChannelFailed.Token="Beitritt des Kanals ist fehlgeschlagen, kann eine ung羹ltige APPID, ein ung羹ltiger Kanal, ein ung羹ltiges Token, ein abgelaufenes Token usw. sein." +Agora.Settings.Agora.APPTOKEN.URL="Benutzerinfos anfordern" +Agora.Main.Request.Token.Error="Anforderung der Benutzerinfos ist fehlgeschlagen." +Agora.Settings.GetInfo.Mode="Kanalinfo-Abrufen-Modus" +Agora.Settings.GetInfo.Mode.Information="Infos 羹ber APPID, App-Token, Kanalname und UID abrufen. Wenn Sie http-get w瓣hlen, m羹ssen Sie eine URL angeben." +Agora.Settings.GetInfo.Mode.Manaul="Infos manuell eingeben" +Agora.Settings.GetInfo.Mode.Http.Get="Infos per http-get-Anfrage abrufen" +Agora.Setting.TestNet.Start="Netzwerktest starten" +Agora.Setting.TestNet.Stop="Netzwerktest stoppen" +Agora.Test.Network.Result.Unknown="Die Netzqualit瓣t ist unbekannt." +Agora.Test.Network.Result.Excellent="Die Netzqualit瓣t ist ausgezeichnet." +Agora.Test.Network.Result.Good="Die Netzwerkqualit瓣t ist recht gut, aber die Bitrate k繹nnte vielleicht nicht so gut sein." +Agora.Test.Network.Result.Poor="Benutzer k繹nnen die Kommunikation leicht beeintr瓣chtigt sp羹ren." +Agora.Test.Network.Result.Bad="Benutzer k繹nnen nicht reibungslos kommunizieren. (niedrige Bitrate, FPS und Aufl繹sung vorschlagen)" +Agora.Test.Network.Result.VBad="Das Netzwerk ist so schlecht, dass Benutzer kaum kommunizieren k繹nnen." +Agora.Test.Network.Result.Down="Das Netzwerk ist ausgefallen und die Benutzer k繹nnen 羹berhaupt nicht kommunizieren. (berpr羹fen Sie das Netzwerk, stellen Sie sicher, dass das Netzwerk in Ordnung ist)" +Agora.Test.Network.Result.UnSupported="Benutzer k繹nnen die Netzwerkqualit瓣t nicht erkennen. (Nicht in Gebrauch.)" +Agora.Test.Network.Result.Detecting="Netzwerkqualit瓣t in der Erkennung." +Agora.Settings.NetworkTest="Netzwerktest" +Agora.Network.Testing="Netzwerk in der Erkennung ......" +Agora.Network.Testing.Info="Ihr Netzwerk ist im Test. Stoppen Sie zuerst den Test." +Basic.Settings.Agora.Save.PCM="OBS PCM-Daten speichern (im Pfad der Obs-Logs)" +Agora.System.CPU.Infomation="Hohe CPU-Last erkannt, dies kann zu Audiofehlern f羹hren und das Streaming-Erlebnis beeinflussen. Versuchen Sie, irrelevante Anwendungen zu beenden, um die CPU-Auslastung zu reduzieren." +Agora.CPU.Threshold="CPU-Schwellenwert" +Agora.Settings.DualStream="Dual-Stream" +Camera.Encoder.Settings.Resolution="Kamera-Encoder-Aufl繹sung" +Camera.Encoder.Settings.Bitrate="Kamera-Encoder-Bitrate" +Camera.Encoder.Settings.FPS="Kamera-Encoder-FPS" +Plugin.Settings.Camera.UID="Kamera-UID" +Plugin.Settings.SendObsCamera="OBS-Kameravideo senden" +Plugin.OBS.Camera.UID.Empty="Kamera-UID ist leer" +Plugin.OBS.Camera.UID.Conflict="Kamera-UID soll sich von UID unterscheiden" +Plugin.Settings.Camera.Token="Kamera-Token" +Plugin.Settings.Error.EmptyUrl="Anfrage-URL ist leer. Geben Sie eine g羹ltige http-URL ein" \ No newline at end of file diff --git a/data/locale/en-ES-0927.ini b/data/locale/en-ES-0927.ini new file mode 100644 index 00000000..0c6b4cc5 --- /dev/null +++ b/data/locale/en-ES-0927.ini @@ -0,0 +1,108 @@ +AgoraTool.Settings.DialogTitle="Herramienta Agora RTC" +Agora.Main.Start="Iniciar transmisi車n a Agora" +Agora.Main.Starting="Comenzando a transmitir a Agora" +Agora.Main.Stop="Dejar de transmitir a Agora" +Agora.Main.Stopping="Dejando la transmisi車n a Agora" +Agora.Main.Controls="Control" +Agora.Settings.General="General" +Agora.Settings.Audio="Audio" +Agora.Settings.Video="Video" +Basic.Settigs.Agora.LoadConfig="Cargar archivo de configuraci車n" +Basic.Settigs.Agora.LoadConfigButton="Cargar" +Basic.Settings.Agora.APPID="Agora APPID" +Basic.Settings.Agora.APPTOKEN="Token de Agora (opcional)" +Basic.Settings.Agora.Token.Expired="Hora de vencimiento del Token" +Basic.Settings.Agora.ChannelName="Nombre del canal" +Basic.Settings.Agora.UID="Uid (opcional)" +Basic.Settings.Agora.Video.Resolution="Resoluci車n" +Basic.Settings.Agora.PersistSave="Guardar todas las configuraciones excepto APPID, incluidas las configuraciones de audio, video y Rtmp" +Basic.Settings.Agora.MutAllRemoteAudioVideo="Silenciar todo el audio y v赤deo remotos" +Agora.Settings.Recording="Configuraci車n del dispositivo de grabaci車n" +Agora.Record.Devices="Dispositivo de grabaci車n" +Agora.Record.Devices.Volume="Volumen del dispositivo de grabaci車n" +Agora.Settings.Playout.Devices="Configuraci車n del altavoz" +Agora.Playout.Devices="Altavoz" +Agora.Payout.Devices.Volume="Volumen del altavoz" +Agora.Settings.Video.BaseResolution="Resoluci車n de salida" +Agora.Settings.Video.FPS="Salida FPS" +Agora.Settings.Video.Birate="Salida Bitrate" +Agora.Settings.Video.Devices="Dispositivo de video" +Agora.Settings.Video.FPS5="5fps" +Agora.Settings.Video.FPS7="7fps" +Agora.Settings.Video.FPS10="10fps" +Agora.Settings.Video.FPS15="15fps" +Agora.Settings.Video.FPS24="24fps" +Agora.Settings.Video.FPS30="30fps" +Agora.Settings.Video.FPS60="60fps" +Agora.Bitrate.Default="Defecto Bitrate" +Agora.Bitrate.Compatible="Compatible Bitrate" +Agora.Bitrate.Standard="Est芍ndar Bitrate" +Agora.General.Appid.Set="Inicializar" +Agora.Settings.Loopback="Loopback" +Basic.Agora.AutoLoadConfig="Cargar autom芍ticamente la configuraci車n de Agora (Marque persistir guardar primero)" +Agora.General.EmptyAppid="Ingresar Appid Primero" +Agora.General.Init.Failed="Fall車 la inicializaci車n del motor de Agora. Verifique APPiD." +Agora.General.EmptyChannel="Ingresar nombre del canal" +Agora.General.EmptyUID="Ingresar UID" +Agora.Settings.Rtmp="Agora Rtmp" +Agora.Settings.Rtmp.Url="Url" +Agora.Settings.Rtmp.FPS="FPS" +Agora.Settings.Rtmp.Bitrate="Bitrate" +Agora.Settings.Rtmp.Width="Ancho" +Agora.Settings.Rtmp.Height="Altura" +Basic.Settings.Agora.AudioProfile.DefaultScenario="Escenario defecto" +Basic.Settings.Agora.AudioProfile.ChatRoomScenario="Escenario de sala de comentario" +Basic.Settings.Agora.AudioProfile.EducationScenario="Escenario educativo" +Basic.Settings.Agora.AudioProfile.GameStreamingScenario="Escenario de transmisi車n de juegos" +Basic.Settings.Agora.AudioProfile.ShowRoomScenario="Escenario de Lifestyle" +Basic.Settings.Agora.AudioProfile.ChatRoomGameScenario="Escenario de juegos de sala de chat" +Basic.Settings.Agora.AudioProfile.IOTScenario="Escenario de IOT" +Basic.Settings.Agora.AudioProfile.MettingScenario="Escenario de reuniones" +Basic.Settings.Agora.AudioProfile.Scenario="Escenario de audio" +Basic.Settings.Agora.AudioProfile.SuggestScenario="Escenario defecto de sugerir" +Basic.Settings.Agora.AudioProfile.High="Alta calidad(Escenario defecto de sugerir)" +Basic.Main.Agora.Empty.Information="Configuraci車n de Agora en el cuadro de di芍logo de configuraci車n, por favor ingrese " +Basic.Main.Agora.Invalid.Token="Token no v芍lido, ingrese un token v芍lido en el cuadro de di芍logo de configuraci車n" +Basic.Main.Agora.Token.Expired="Token caducado, vuelva a generar el token y ingrese un token v芍lido en el cuadro de di芍logo de configuraci車n" +Basic.Main.Agora.Invalid.Channel="Canal no v芍lido, ingrese un canal v芍lido en el cuadro de di芍logo de configuraci車n" +Basic.Main.Agora.Invalid.Appid="Appid no v芍lido, ingrese el appid v芍lido en el cuadro de di芍logo de configuraci車n" +Agora.Settings.Video.Agora.Bitrate="Usar Bitrate de Agora" +Agora.Settings.Video.OBS.Bitrate="Usar Bitrate de OBS" +Agora.Settings.Video.Encoder="Salida Bitrate" +Agora.Settings.Video.FPS.Resolution="Usar resoluci車n y FPS de OBS" +Basic.Settings.Agora.PersistSaveAppid="Persistir Guardar APPID" +Basic.Settings.Agora.PersistSaveAppidInfo="APPID se guardar芍 en basic.ini del archivo de configuraci車n OBS, porque marca la opci車n para persistir guardar appid. Sugerimos no guardar appid en el archivo de configuraci車n local." +Agora.JoinChannelFailed.Token="Unirse al canal fall車, puede ser un APPid inv芍lido, un canal inv芍lido, un token inv芍lido, un token caducado, etc." +Agora.Settings.Agora.APPTOKEN.URL="Solicitar URL de informaci車n de usuario" +Agora.Main.Request.Token.Error="Solicitar de informaci車n de usuario fallida" +Agora.Settings.GetInfo.Mode="Obtener el modo de informaci車n del canal" +Agora.Settings.GetInfo.Mode.Information="Obtener informaci車n sobre APPID, token de aplicaci車n, nombre de canal y uid. Si elige http, debe proporcionar una URL." +Agora.Settings.GetInfo.Mode.Manaul="Ingresar informaci車n manualmente" +Agora.Settings.GetInfo.Mode.Http.Get="Obtener informaci車n mediante solicitud http" +Agora.Setting.TestNet.Start="Iniciar prueba de red" +Agora.Setting.TestNet.Stop="Detener prueba de red" +Agora.Test.Network.Result.Unknown="Se desconoce la calidad de la red." +Agora.Test.Network.Result.Excellent="La calidad de la red es excelente." +Agora.Test.Network.Result.Good="La calidad de la red es buena, pero bitrate puede ser un poco m芍s baja que excelente." +Agora.Test.Network.Result.Poor="Los usuarios pueden sentir que la comunicaci車n est芍 un poco afectada." +Agora.Test.Network.Result.Bad="Los usuarios no pueden comunicarse sin problemas.ㄗSugerir bajo bitrate, fps y resoluci車n.)" +Agora.Test.Network.Result.VBad="La red es tan mala que los usuarios apenas pueden comunicarse." +Agora.Test.Network.Result.Down="La red est芍 inactiva y los usuarios no pueden comunicarse en absoluto."(Verifique la red, aseg迆rese de que la red est谷 bien)" +Agora.Test.Network.Result.UnSupported="Los usuarios no pueden detectar la calidad de la red. (No est芍 en uso)" +Agora.Test.Network.Result.Detecting="Detectando la calidad de la red." +Agora.Settings.NetworkTest="Prueba de red" +Agora.Network.Testing="Probando de red ......" +Agora.Network.Testing.Info="Est芍s probando la red. Deje de probar la red primero." +Basic.Settings.Agora.Save.PCM="Guardar datos de OBS PCM (en la ruta de los registros de obs)" +Agora.System.CPU.Infomation="Se detect車 una alta carga de CPU, esto puede causar un mal funcionamiento del audio e influir en la experiencia de transmisi車n. Intente finalizar las aplicaciones irrelevantes para reducir el uso de la CPU." +Agora.CPU.Threshold="Umbral de CPU" +Agora.Settings.DualStream="Transmisi車n dual" +Camera.Encoder.Settings.Resolution="Resoluci車n del codificador de la c芍mara" +Camera.Encoder.Settings.Bitrate="Bitrate del codificador de la c芍mara" +Camera.Encoder.Settings.FPS="FPS del codificador de c芍mara" +Plugin.Settings.Camera.UID="UID de la c芍mara" +Plugin.Settings.SendObsCamera="Enviar video de c芍mara OBS" +Plugin.OBS.Camera.UID.Empty="El UID de la c芍mara est芍 vac赤o" +Plugin.OBS.Camera.UID.Conflict="El UID de la c芍mara debe ser diferente al UID" +Plugin.Settings.Camera.Token="Token de c芍mara" +Plugin.Settings.Error.EmptyUrl="La URL de la solicitud est芍 vac赤a. Complete una URL http v芍lida" \ No newline at end of file diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 264abc65..bf852a00 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -87,7 +87,7 @@ Agora.Test.Network.Result.Good="The network quality is quite good, but the bitra Agora.Test.Network.Result.Poor="Users can feel the communication slightly impaired." Agora.Test.Network.Result.Bad="Users cannot communicate smoothly.ㄗSuggest low down bitrate, fps and resolution)" Agora.Test.Network.Result.VBad="The network is so bad that users can barely communicate." -Agora.Test.Network.Result.Down="The network is down and users cannot communicate at all.\n(Check network, make sure network is ok)" +Agora.Test.Network.Result.Down="The network is down and users cannot communicate at all."(Check network, make sure network is ok)" Agora.Test.Network.Result.UnSupported="Users cannot detect the network quality. (Not in use.)" Agora.Test.Network.Result.Detecting="Detecting the network quality." Agora.Settings.NetworkTest="Network Test" @@ -96,4 +96,13 @@ Agora.Network.Testing.Info="You are testing network. Stop testing network first. Basic.Settings.Agora.Save.PCM="Save OBS PCM Data(in the path of obs logs)" Agora.System.CPU.Infomation="High CPU load detected, this may cause audio malfunction and influence stream experience. Please try ending irrelevant applications to reduce CPU usage." Agora.CPU.Threshold="CPU Threshold" -Agora.Settings.DualStream="Dual Stream" \ No newline at end of file +Agora.Settings.DualStream="Dual Stream" +Camera.Encoder.Settings.Resolution="Camera Encoder Resolution" +Camera.Encoder.Settings.Bitrate="Camera Encoder Bitrate" +Camera.Encoder.Settings.FPS="Camera Encoder FPS" +Plugin.Settings.Camera.UID="Camera UID" +Plugin.Settings.SendObsCamera="Send OBS Camera Video" +Plugin.OBS.Camera.UID.Empty="Camera UID is empty" +Plugin.OBS.Camera.UID.Conflict="Camera UID should be different from UID" +Plugin.Settings.Camera.Token="Camera token" +Plugin.Settings.Error.EmptyUrl="Reuqest url is empty. Fill valid http url" \ No newline at end of file diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 4503b8d5..b519a269 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -96,4 +96,13 @@ Agora.Network.Testing.Info="蝵蝏瘚霂銝哨霂瑕甇Y蝏瘚霂" Basic.Settings.Agora.Save.PCM="靽摮喲憪唳殷矣bs亙頝臬銝嚗" Agora.System.CPU.Infomation="敶 CPU 韐頧質擃嚗航賢紡渡湔凋葉喲撘撣賂敶勗湔凋撉霂琿箸嗆喟頧臭辣嚗隞亦&靽CPU韐頧賜輕甇撣豢偌撟喋" Agora.CPU.Threshold="CPU" -Agora.Settings.DualStream="憭批瘚" \ No newline at end of file +Agora.Settings.DualStream="憭批瘚" +Camera.Encoder.Settings.Resolution="憭渡颲函" +Camera.Encoder.Settings.Bitrate="憭渡" +Camera.Encoder.Settings.FPS="憭渡撣抒" +Plugin.Settings.Camera.UID="憭帽ID" +Plugin.Settings.SendObsCamera="憭渲憸" +Plugin.OBS.Camera.UID.Empty="憭帽ID銝賭蛹蝛" +Plugin.OBS.Camera.UID.Conflict="憭帽ID銝賢UID詨" +Plugin.Settings.Camera.Token="憭愒oken" +Plugin.Settings.Error.EmptyUrl="霂瑟靽⊥臭蛹蝛箝憛怠交http url" \ No newline at end of file diff --git a/data/locale/zh-TW.ini b/data/locale/zh-TW.ini index 893759a6..042276d1 100644 --- a/data/locale/zh-TW.ini +++ b/data/locale/zh-TW.ini @@ -97,4 +97,13 @@ Agora.Network.Testing.Info="甇冽葫閰衣雯蝯∴隢甇X葫閰艾" Basic.Settings.Agora.Save.PCM="靽摮喲餃憪豢嚗矣bs亙頝臬銝嚗" Agora.System.CPU.Infomation="嗅CPU 鞎頛擃嚗航賢渡湔凋葉喲餌啣虜嚗敶梢輻湔剝撽隢箸急⊿頠擃嚗隞亦Ⅱ靽 CPU 鞎頛蝬剜甇撣豢偌撟喋" Agora.CPU.Threshold="CPU曉" -Agora.Settings.DualStream="潮憭批瘚" \ No newline at end of file +Agora.Settings.DualStream="潮憭批瘚" +Camera.Encoder.Settings.Resolution="剔楊蝣澆颲函" +Camera.Encoder.Settings.Bitrate="剔楊蝣潛Ⅳ" +Camera.Encoder.Settings.FPS="剔楊蝣澆" +Plugin.Settings.Camera.UID="苣ID" +Plugin.Settings.SendObsCamera="潮剔楊蝣潸" +Plugin.OBS.Camera.UID.Empty="苣ID銝賜箇征" +Plugin.OBS.Camera.UID.Conflict="苣ID銝賢UID詨" +Plugin.Settings.Camera.Token="負oken" +Plugin.Settings.Error.EmptyUrl="霂瑟靽⊥臭蛹蝛箝憛怠交http url" \ No newline at end of file diff --git a/installer/agora-tool-obs-25.0.8-32.nsi b/installer/agora-tool-obs-25.0.8-32.nsi deleted file mode 100644 index 88b49528..00000000 --- a/installer/agora-tool-obs-25.0.8-32.nsi +++ /dev/null @@ -1,86 +0,0 @@ -; -; NSIS Installer of Agora Tool for OBS Studio(https://obsproject.com/) -; -; This installer script is designed only for the release process -; of Agora Tool. It requires a lot of files to be in exactly the -; right places. If you're making a fork, it's strongly suggested -; that you make your own installer. - -Unicode true -ManifestDPIAware true - -; Define your application name -!define APPNAME "Agora Tool" - -!ifndef APPVERSION -!define APPVERSION "25.0.8" -!define SHORTVERSION "25.0.8" -!endif - -; Additional script dependencies -!include WinVer.nsh -!include x64.nsh - -; Main Install settings -Name "${APPNAME}" - -!ifdef INSTALL64 - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x64.exe" -!else - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x86.exe" -!endif - -; Use compression -SetCompressor /SOLID LZMA - -; Need Admin -RequestExecutionLevel admin - -; Modern interface settings -!include "MUI.nsh" -!define MUI_ICON "agora.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "agora.bmp" - -!define MUI_ABORTWARNING -!define MUI_FINISHPAGE_RUN - -!define MUI_WELCOMEPAGE_TEXT "This setup will guide you through installing Agora Tool Plugin for OBS Studio.\n\nIt is recommended that you close OBS Studio. This will make it possible to load agora tool for OBS Studio." - -!define MUI_HEADERIMAGE -!define MUI_PAGE_HEADER_TEXT "License Information" -!define MUI_PAGE_HEADER_SUBTEXT "Please review the license terms before installing OBS Studio." -!define MUI_LICENSEPAGE_TEXT_TOP "Press Page Down or scroll to see the rest of the license." -!define MUI_LICENSEPAGE_TEXT_BOTTOM " " -!define MUI_LICENSEPAGE_BUTTON "&Next >" - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "gplv2.txt" -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - -; Set languages (first is default language) -!insertmacro MUI_LANGUAGE "English" -!insertmacro MUI_RESERVEFILE_LANGDLL - -Function .onInit - ReadRegStr $INSTDIR HKLM "Software\OBS Studio" "" - ${If} $INSTDIR == "" - MessageBox MB_OK|MB_ICONSTOP "Please Install OBS Studio First" - Quit - ${EndIf} -FunctionEnd - -InstallDir $INSTDIR - -Section "Agora Tool" SecAgoraTool - SetOutPath "$INSTDIR" - File /r "..\Release\data" - SetOutPath "$INSTDIR" - File /r "..\Release\obs-plugins" - SetOutPath "$INSTDIR" - File /r "..\Release\bin" -SectionEnd - -Section -FinishSection - -SectionEnd \ No newline at end of file diff --git a/installer/agora-tool-obs-25.0.8.nsi b/installer/agora-tool-obs-25.0.8.nsi deleted file mode 100644 index 00dd9547..00000000 --- a/installer/agora-tool-obs-25.0.8.nsi +++ /dev/null @@ -1,86 +0,0 @@ -; -; NSIS Installer of Agora Tool for OBS Studio(https://obsproject.com/) -; -; This installer script is designed only for the release process -; of Agora Tool. It requires a lot of files to be in exactly the -; right places. If you're making a fork, it's strongly suggested -; that you make your own installer. - -Unicode true -ManifestDPIAware true - -; Define your application name -!define APPNAME "Agora Tool" - -!ifndef APPVERSION -!define APPVERSION "25.0.8" -!define SHORTVERSION "25.0.8" -!endif - -; Additional script dependencies -!include WinVer.nsh -!include x64.nsh - -; Main Install settings -Name "${APPNAME}" -!define INSTALL64 -!ifdef INSTALL64 - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x64.exe" -!else - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x86.exe" -!endif - -; Use compression -SetCompressor /SOLID LZMA - -; Need Admin -RequestExecutionLevel admin - -; Modern interface settings -!include "MUI.nsh" -!define MUI_ICON "agora.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "agora.bmp" - -!define MUI_ABORTWARNING -!define MUI_FINISHPAGE_RUN - -!define MUI_WELCOMEPAGE_TEXT "This setup will guide you through installing Agora Tool Plugin for OBS Studio.\n\nIt is recommended that you close OBS Studio. This will make it possible to load agora tool for OBS Studio." - -!define MUI_HEADERIMAGE -!define MUI_PAGE_HEADER_TEXT "License Information" -!define MUI_PAGE_HEADER_SUBTEXT "Please review the license terms before installing OBS Studio." -!define MUI_LICENSEPAGE_TEXT_TOP "Press Page Down or scroll to see the rest of the license." -!define MUI_LICENSEPAGE_TEXT_BOTTOM " " -!define MUI_LICENSEPAGE_BUTTON "&Next >" - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "gplv2.txt" -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - -; Set languages (first is default language) -!insertmacro MUI_LANGUAGE "English" -!insertmacro MUI_RESERVEFILE_LANGDLL - -Function .onInit - ReadRegStr $INSTDIR HKLM "Software\OBS Studio" "" - ${If} $INSTDIR == "" - MessageBox MB_OK|MB_ICONSTOP "Please Install OBS Studio First" - Quit - ${EndIf} -FunctionEnd - -InstallDir $INSTDIR - -Section "Agora Tool" SecAgoraTool - SetOutPath "$INSTDIR" - File /r "..\Release\data" - SetOutPath "$INSTDIR" - File /r "..\Release\obs-plugins" - SetOutPath "$INSTDIR" - File /r "..\Release\bin" -SectionEnd - -Section -FinishSection - -SectionEnd \ No newline at end of file diff --git a/installer/agora-tool-obs-26.0.2-32.nsi b/installer/agora-tool-obs-26.0.2-32.nsi deleted file mode 100644 index 408aa34e..00000000 --- a/installer/agora-tool-obs-26.0.2-32.nsi +++ /dev/null @@ -1,86 +0,0 @@ -; -; NSIS Installer of Agora Tool for OBS Studio(https://obsproject.com/) -; -; This installer script is designed only for the release process -; of Agora Tool. It requires a lot of files to be in exactly the -; right places. If you're making a fork, it's strongly suggested -; that you make your own installer. - -Unicode true -ManifestDPIAware true - -; Define your application name -!define APPNAME "Agora Tool" - -!ifndef APPVERSION -!define APPVERSION "26.0.2" -!define SHORTVERSION "26.0.2" -!endif - -; Additional script dependencies -!include WinVer.nsh -!include x64.nsh - -; Main Install settings -Name "${APPNAME}" - -!ifdef INSTALL64 - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x64.exe" -!else - OutFile "Agora-Tool-${SHORTVERSION}-Installer-x86.exe" -!endif - -; Use compression -SetCompressor /SOLID LZMA - -; Need Admin -RequestExecutionLevel admin - -; Modern interface settings -!include "MUI.nsh" -!define MUI_ICON "agora.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "agora.bmp" - -!define MUI_ABORTWARNING -!define MUI_FINISHPAGE_RUN - -!define MUI_WELCOMEPAGE_TEXT "This setup will guide you through installing Agora Tool Plugin for OBS Studio.\n\nIt is recommended that you close OBS Studio. This will make it possible to load agora tool for OBS Studio." - -!define MUI_HEADERIMAGE -!define MUI_PAGE_HEADER_TEXT "License Information" -!define MUI_PAGE_HEADER_SUBTEXT "Please review the license terms before installing OBS Studio." -!define MUI_LICENSEPAGE_TEXT_TOP "Press Page Down or scroll to see the rest of the license." -!define MUI_LICENSEPAGE_TEXT_BOTTOM " " -!define MUI_LICENSEPAGE_BUTTON "&Next >" - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "gplv2.txt" -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - -; Set languages (first is default language) -!insertmacro MUI_LANGUAGE "English" -!insertmacro MUI_RESERVEFILE_LANGDLL - -Function .onInit - ReadRegStr $INSTDIR HKLM "Software\OBS Studio" "" - ${If} $INSTDIR == "" - MessageBox MB_OK|MB_ICONSTOP "Please Install OBS Studio First" - Quit - ${EndIf} -FunctionEnd - -InstallDir $INSTDIR - -Section "Agora Tool" SecAgoraTool - SetOutPath "$INSTDIR" - File /r "..\Release\data" - SetOutPath "$INSTDIR" - File /r "..\Release\obs-plugins" - SetOutPath "$INSTDIR" - File /r "..\Release\bin" -SectionEnd - -Section -FinishSection - -SectionEnd \ No newline at end of file diff --git a/installer/agora-tool-obs-3.3.0.nsi b/installer/agora-tool-obs-3.3.0.nsi deleted file mode 100644 index 85227ab2..00000000 --- a/installer/agora-tool-obs-3.3.0.nsi +++ /dev/null @@ -1,88 +0,0 @@ -; -; NSIS Installer of Agora Tool for OBS Studio(https://obsproject.com/) -; -; This installer script is designed only for the release process -; of Agora Tool. It requires a lot of files to be in exactly the -; right places. If you're making a fork, it's strongly suggested -; that you make your own installer. - -Unicode true -ManifestDPIAware true - -; Define your application name -!define APPNAME "Agora Tool" - -!ifndef APPVERSION -!define APPVERSION "26.0.2" -!define SHORTVERSION "3.3.0" -!endif - -; Additional script dependencies -!include WinVer.nsh -!include x64.nsh - -; Main Install settings -Name "${APPNAME}" -#!define INSTALL64 -#!ifdef INSTALL64 -# OutFile "Agora-Tool-${SHORTVERSION}-Installer-x64.exe" -#!else -# OutFile "Agora-Tool-${SHORTVERSION}-Installer-x86.exe" -#!endif - -OutFile "Agora-Tool-${SHORTVERSION}-Installer.exe" - -; Use compression -SetCompressor /SOLID LZMA - -; Need Admin -RequestExecutionLevel admin - -; Modern interface settings -!include "MUI.nsh" -!define MUI_ICON "agora.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "agora.bmp" - -!define MUI_ABORTWARNING -!define MUI_FINISHPAGE_RUN - -!define MUI_WELCOMEPAGE_TEXT "This setup will guide you through installing Agora Tool Plugin for OBS Studio.\n\nIt is recommended that you close OBS Studio. This will make it possible to load agora tool for OBS Studio." - -!define MUI_HEADERIMAGE -!define MUI_PAGE_HEADER_TEXT "License Information" -!define MUI_PAGE_HEADER_SUBTEXT "Please review the license terms before installing OBS Studio." -!define MUI_LICENSEPAGE_TEXT_TOP "Press Page Down or scroll to see the rest of the license." -!define MUI_LICENSEPAGE_TEXT_BOTTOM " " -!define MUI_LICENSEPAGE_BUTTON "&Next >" - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "gplv2.txt" -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - -; Set languages (first is default language) -!insertmacro MUI_LANGUAGE "English" -!insertmacro MUI_RESERVEFILE_LANGDLL - -Function .onInit - ReadRegStr $INSTDIR HKLM "Software\OBS Studio" "" - ${If} $INSTDIR == "" - MessageBox MB_OK|MB_ICONSTOP "Please Install OBS Studio First" - Quit - ${EndIf} -FunctionEnd - -InstallDir $INSTDIR - -Section "Agora Tool" SecAgoraTool - SetOutPath "$INSTDIR" - File /r "..\Release\data" - SetOutPath "$INSTDIR" - File /r "..\Release\obs-plugins" - SetOutPath "$INSTDIR" - File /r "..\Release\bin" -SectionEnd - -Section -FinishSection - -SectionEnd \ No newline at end of file diff --git a/installer/agora-tool-obs-3.3.3.nsi b/installer/agora-tool-obs-3.6.200.nsi similarity index 98% rename from installer/agora-tool-obs-3.3.3.nsi rename to installer/agora-tool-obs-3.6.200.nsi index 73fcbb2d..8d0f2a7b 100644 --- a/installer/agora-tool-obs-3.3.3.nsi +++ b/installer/agora-tool-obs-3.6.200.nsi @@ -14,7 +14,7 @@ ManifestDPIAware true !ifndef APPVERSION !define APPVERSION "26.0.2" -!define SHORTVERSION "3.3.3" +!define SHORTVERSION "3.6.200" !endif ; Additional script dependencies diff --git a/src/Agora/agorartcengine.cpp b/src/Agora/agorartcengine.cpp index a18df203..e424ad08 100644 --- a/src/Agora/agorartcengine.cpp +++ b/src/Agora/agorartcengine.cpp @@ -56,10 +56,9 @@ class AgoraRtcEngineEvent :public QObject, public IRtcEngineEventHandler { AgoraRtcEngine &m_engine; - public: - AgoraRtcEngineEvent(AgoraRtcEngine &engine) : m_engine(engine) {} - + AgoraRtcEngineEvent(AgoraRtcEngine &engine) : m_engine(engine){} + virtual void onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) override { emit m_engine.onJoinChannelSuccess(channel, uid, elapsed); @@ -71,7 +70,6 @@ class AgoraRtcEngineEvent :public QObject, } virtual void onLeaveChannel(const RtcStats &stats) override { - Sleep(200); emit m_engine.onLeaveChannel(stats); } @@ -130,6 +128,62 @@ class AgoraRtcEngineEvent :public QObject, AgoraRtcEngine *AgoraRtcEngine::m_agoraEngine = nullptr; agora::media::IAudioFrameObserver::AudioFrame AgoraRtcEngine::m_externalAudioframe; + +void copy_frame_data_line(uint8_t* dst, int line_size, + const struct video_data* src, + uint32_t plane, uint32_t y) +{ + uint32_t pos_src = y * src->linesize[plane]; + uint32_t pos_dst = y * line_size; + uint32_t bytes = line_size < src->linesize[plane] + ? line_size + : src->linesize[plane]; + + memcpy(dst + pos_dst, src->data[plane] + pos_src, bytes); +} + +void copy_frame_data_plane(uint8_t* dst, int line_size, + const struct video_data* src, + uint32_t plane, uint32_t lines) +{ + if (line_size != src->linesize[plane]) { + for (uint32_t y = 0; y < lines; y++) + copy_frame_data_line(dst, line_size, src, plane, y); + } + else { + memcpy(dst, src->data[plane], + line_size * (size_t)lines); + } +} + + +void copy_frame_data_line2(uint8_t* dst, int line_size, + const struct obs_source_frame* src, + uint32_t plane, uint32_t y) +{ + uint32_t pos_src = y * src->linesize[plane]; + uint32_t pos_dst = y * line_size; + uint32_t bytes = line_size < src->linesize[plane] + ? line_size + : src->linesize[plane]; + + memcpy(dst + pos_dst, src->data[plane] + pos_src, bytes); +} + +void copy_frame_data_plane2(uint8_t* dst, int line_size, + const struct obs_source_frame* src, + uint32_t plane, uint32_t lines) +{ + if (line_size != src->linesize[plane]) { + for (uint32_t y = 0; y < lines; y++) + copy_frame_data_line2(dst, line_size, src, plane, y); + } + else { + memcpy(dst, src->data[plane], + line_size * (size_t)lines); + } +} + AgoraRtcEngine *AgoraRtcEngine::GetInstance() { if (m_agoraEngine == nullptr) @@ -147,8 +201,8 @@ void AgoraRtcEngine::ReleaseInstance() } AgoraRtcEngine::AgoraRtcEngine() - : m_rtcEngine(createAgoraRtcEngine()) - , m_eventHandler(new AgoraRtcEngineEvent(*this)) + : m_eventHandler(new AgoraRtcEngineEvent(*this)) + , m_eventHandlerCamera(new IRtcEngineEventHandler()) , logFirstPushVideo(false) , sampleRate(48000) , audioChannel(2) @@ -157,14 +211,14 @@ AgoraRtcEngine::AgoraRtcEngine() , m_audioDeviceManager(nullptr) , m_bInitialize(false) , m_bJoinChannel(false) - { - m_rtcEngine->setParameters("{\"che.audio.input.volume\": 60}"); - m_rtcEngine->setParameters("{\"che.audio.current.recording.boostMode\": -1}"); + //AParameter apm(*m_rtcEngine); + +// apm->setParameters("{\"che.audio.input.volume\": 60}"); +// apm->setParameters("{\"che.audio.current.recording.boostMode\": -1}"); m_externalAudioframe.buffer = NULL; m_externalVideoFrame.buffer = NULL; qRegisterMetaType(); - } AgoraRtcEngine::~AgoraRtcEngine() @@ -192,6 +246,11 @@ void AgoraRtcEngine::release() m_externalVideoFrame.buffer = nullptr; } + if (m_externalVideoFrameCamera.buffer) { + delete[] m_externalVideoFrameCamera.buffer; + m_externalVideoFrameCamera.buffer = nullptr; + } + if (m_rtcEngine) { m_rtcEngine->release(true); m_rtcEngine = NULL; @@ -214,14 +273,14 @@ bool AgoraRtcEngine::InitEngine(std::string appid) } if (!m_rtcEngine) - m_rtcEngine = createAgoraRtcEngine(); + m_rtcEngine = (agora::rtc::IRtcEngineEx*)createAgoraRtcEngine(); int ret = m_rtcEngine->initialize(context); if (0 != ret) { return false; } - m_rtcEngine->queryInterface(agora::AGORA_IID_MEDIA_ENGINE, + m_rtcEngine->queryInterface(agora::rtc::AGORA_IID_MEDIA_ENGINE, (void **)&m_pMediaEngine); SetExternalVideoFrame(); @@ -256,30 +315,232 @@ void AgoraRtcEngine::SetExternalVideoFrame() m_externalVideoFrame.height = agora_out_cy; m_externalVideoFrame.stride = (agora_out_cx << 4) >> 4; m_externalVideoFrame.timestamp = 0; - m_externalVideoFrame.type = ExternalVideoFrame::VIDEO_BUFFER_RAW_DATA; + m_externalVideoFrame.type = agora::media::base::ExternalVideoFrame::VIDEO_BUFFER_RAW_DATA; m_format = ovi.output_format; if (ovi.output_format == VIDEO_FORMAT_I420) { m_externalVideoFrame.format = - agora::media::ExternalVideoFrame::VIDEO_PIXEL_I420; + agora::media::base::VIDEO_PIXEL_I420; m_externalVideoFrame.buffer = new uint8_t[m_externalVideoFrame.stride*m_externalVideoFrame.height * 3 / 2]; } else if (ovi.output_format == VIDEO_FORMAT_NV12) { m_externalVideoFrame.format = - agora::media::ExternalVideoFrame::VIDEO_PIXEL_NV12; + agora::media::base::VIDEO_PIXEL_NV12; m_externalVideoFrame.buffer = new uint8_t[m_externalVideoFrame.stride*m_externalVideoFrame.height * 3 / 2]; } else if (ovi.output_format == VIDEO_FORMAT_RGBA) { m_externalVideoFrame.format = - agora::media::ExternalVideoFrame::VIDEO_PIXEL_BGRA; + agora::media::base::VIDEO_PIXEL_BGRA; m_externalVideoFrame.buffer = new uint8_t[m_externalVideoFrame.stride*m_externalVideoFrame.height * 4]; } else if (ovi.output_format == VIDEO_FORMAT_I444) { m_externalVideoFrame.format = - agora::media::ExternalVideoFrame::VIDEO_PIXEL_BGRA; + agora::media::base::VIDEO_PIXEL_BGRA; m_externalVideoFrame.buffer = new uint8_t[m_externalVideoFrame.stride*m_externalVideoFrame.height * 4]; } } +void AgoraRtcEngine::PushVideoFrame(struct video_data* frame) +{ + if (!m_bInitialize || !m_bJoinChannel) + return; + + struct obs_video_info ovi; + obs_get_video_info(&ovi); + + if (m_externalVideoFrame.stride != ((ovi.output_width << 4) >> 4) + || m_externalVideoFrame.height != ovi.output_height + || m_format != ovi.output_format) { + delete[] m_externalVideoFrame.buffer; + m_externalVideoFrame.buffer = nullptr; + SetExternalVideoFrame(); + } + + uint8_t* dst = (uint8_t*)m_externalVideoFrame.buffer; + switch (ovi.output_format) { + case VIDEO_FORMAT_I420: { + + copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 0, m_externalVideoFrame.height); + dst += m_externalVideoFrame.stride * m_externalVideoFrame.height; + copy_frame_data_plane(dst, m_externalVideoFrame.stride / 2, frame, 1, m_externalVideoFrame.height / 2); + dst += m_externalVideoFrame.stride * m_externalVideoFrame.height / 4; + copy_frame_data_plane(dst, m_externalVideoFrame.stride / 2, frame, 2, m_externalVideoFrame.height / 2); + } + break; + case VIDEO_FORMAT_NV12: { + copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 0, m_externalVideoFrame.height); + dst += m_externalVideoFrame.stride * m_externalVideoFrame.height; + copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 1, m_externalVideoFrame.height / 2); + } + break; + case VIDEO_FORMAT_RGBA: + libyuv::ABGRToARGB(frame->data[0], frame->linesize[0], + (uint8_t*)m_externalVideoFrame.buffer, frame->linesize[0], + ovi.output_width, ovi.output_height); + //copy_frame_data_plane(dst, m_externalVideoFrame.stride * 4, frame, 0, m_externalVideoFrame.height); + break; + + case VIDEO_FORMAT_I444: + libyuv::I444ToARGB( + frame->data[0], frame->linesize[0], + frame->data[1], frame->linesize[1], + frame->data[2], frame->linesize[2], + (uint8_t*)m_externalVideoFrame.buffer, + m_externalVideoFrame.stride * 4, + ovi.output_width, ovi.output_height); + //copy_frame_data_plane(dst, m_externalVideoFrame.stride * 4, frame, 0, m_externalVideoFrame.height); + break; + } + m_externalVideoFrame.timestamp = GetTickCount64(); + m_pMediaEngine->pushVideoFrame(&m_externalVideoFrame); +} + +void AgoraRtcEngine::SetExternalVideoFrameCamera(struct obs_source_frame* frame) +{ + m_externalVideoFrameCamera.buffer = NULL; + m_externalVideoFrameCamera.cropLeft = 0; + m_externalVideoFrameCamera.cropTop = 0; + m_externalVideoFrameCamera.cropRight = 0; + m_externalVideoFrameCamera.cropBottom = 0; + + m_externalVideoFrameCamera.rotation = 0; + m_externalVideoFrameCamera.height = frame->height; + m_externalVideoFrameCamera.stride = frame->width; + m_externalVideoFrameCamera.timestamp = 0; + m_externalVideoFrameCamera.type = agora::media::base::ExternalVideoFrame::VIDEO_BUFFER_RAW_DATA; + m_camera_format = frame->format; + if (frame->format == VIDEO_FORMAT_I420) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_I420; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 3 / 2]; + } + else if (frame->format == VIDEO_FORMAT_NV12) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_NV12; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 3 / 2]; + } + else if (frame->format == VIDEO_FORMAT_BGRA) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_BGRA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + } + else if (frame->format == VIDEO_FORMAT_RGBA) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_RGBA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + } + else if (frame->format == VIDEO_FORMAT_I444) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_BGRA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + } + else if (frame->format == VIDEO_FORMAT_I422) { + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_BGRA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + } + else if (frame->format == VIDEO_FORMAT_YUY2) { //YUY2ToARGB + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_BGRA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + + } + // || frame->format == VIDEO_FORMAT_YVYU // + else if (frame->format == VIDEO_FORMAT_UYVY) { //UYVYToARGB + m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_RGBA; + m_externalVideoFrameCamera.buffer = new uint8_t[m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height * 4]; + } + m_camera_format = frame->format; +} + + +void AgoraRtcEngine::PushCameraVideoFrame(struct obs_source_frame* frame) +{ + if (!m_bJoinChannel) + return; + + if (m_externalVideoFrameCamera.stride != frame->width + || m_externalVideoFrameCamera.height != frame->height + || m_camera_format != frame->format) { + if (m_externalVideoFrameCamera.buffer) { + delete[] m_externalVideoFrameCamera.buffer; + m_externalVideoFrameCamera.buffer = nullptr; + } + SetExternalVideoFrameCamera(frame); + blog(LOG_INFO, "obs camera export to plugin: linesize 0=%d, 1=%d, 2=%d, \ + width=%d, height=%d, format = %d, external format=%d" + , frame->linesize[0], frame->linesize[1], frame->linesize[2] + , frame->width, frame->height, frame->format, m_externalVideoFrameCamera.format); + blog(LOG_INFO, "PushVideoFrame: connection channel=%s, uid=%d", connection.channelId, connection.localUid); + } + + uint8_t* dst = (uint8_t*)m_externalVideoFrameCamera.buffer; + if (frame->format == VIDEO_FORMAT_I420) { + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 0, m_externalVideoFrameCamera.height); + dst += m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride / 2, frame, 1, m_externalVideoFrameCamera.height / 2); + dst += m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height / 4; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride / 2, frame, 2, m_externalVideoFrameCamera.height / 2); + } + else if (frame->format == VIDEO_FORMAT_NV12) { + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 0, m_externalVideoFrameCamera.height); + dst += m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 1, m_externalVideoFrameCamera.height / 2); + } + else if (frame->format == VIDEO_FORMAT_BGRA) { + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride * 4, frame, 0, m_externalVideoFrameCamera.height); + } + else if (frame->format == VIDEO_FORMAT_RGBA) { + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride * 4, frame, 0, m_externalVideoFrameCamera.height); + } + else if (frame->format == VIDEO_FORMAT_I444) { + libyuv::I444ToARGB( + frame->data[0], frame->linesize[0], + frame->data[1], frame->linesize[1], + frame->data[2], frame->linesize[2], + (uint8_t*)m_externalVideoFrameCamera.buffer, + m_externalVideoFrameCamera.stride * 4, + frame->width, frame->height); + } + else if (frame->format == VIDEO_FORMAT_I422) { + /*m_externalVideoFrameCamera.format = + agora::media::base::VIDEO_PIXEL_I422; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 0, m_externalVideoFrameCamera.height); + dst += m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 1, m_externalVideoFrameCamera.height / 2); + dst += m_externalVideoFrameCamera.stride * m_externalVideoFrameCamera.height / 2; + copy_frame_data_plane2(dst, m_externalVideoFrameCamera.stride, frame, 2, m_externalVideoFrameCamera.height / 2);*/ + libyuv::I422ToARGB( + frame->data[0], frame->linesize[0], + frame->data[1], frame->linesize[1], + frame->data[2], frame->linesize[2], + (uint8_t*)m_externalVideoFrameCamera.buffer, + m_externalVideoFrameCamera.stride * 4, + frame->width, frame->height); + } + else if (frame->format == VIDEO_FORMAT_YUY2) { + libyuv::YUY2ToARGB( + frame->data[0], frame->linesize[0], + (uint8_t*)m_externalVideoFrameCamera.buffer, + m_externalVideoFrameCamera.stride * 4, + frame->width, frame->height + ); + } + else if (frame->format == VIDEO_FORMAT_UYVY) { + libyuv::UYVYToARGB( + frame->data[0], frame->linesize[0], + (uint8_t*)m_externalVideoFrameCamera.buffer, + m_externalVideoFrameCamera.stride * 4, + frame->width, frame->height + ); + } + connection.channelId = channelId.c_str(); + connection.localUid = localCameraUid; + m_externalVideoFrame.timestamp = GetTickCount64(); + m_pMediaEngine->pushVideoFrame(&m_externalVideoFrameCamera, connection); +} + + BOOL AgoraRtcEngine::setLogPath(std::string path) { @@ -319,18 +580,18 @@ void AgoraRtcEngine::stopPreview() void *AgoraRtcEngine::AgoraAudioObserver_Create() { m_externalAudioframe.channels = 2; - m_externalAudioframe.samples = 480; + m_externalAudioframe.samplesPerChannel = 480; m_externalAudioframe.samplesPerSec = 48000;//sampleRate; - m_externalAudioframe.bytesPerSample = 2; + m_externalAudioframe.bytesPerSample = TWO_BYTES_PER_SAMPLE; m_externalAudioframe.type = agora::media::IAudioFrameObserver::FRAME_TYPE_PCM16; m_externalAudioframe.buffer = - new uint8_t[m_externalAudioframe.samples * 2 * 2]; - memset(m_externalAudioframe.buffer, 0, m_externalAudioframe.samples * 2 * 2); + new uint8_t[m_externalAudioframe.samplesPerChannel * 2 * 2]; + memset(m_externalAudioframe.buffer, 0, m_externalAudioframe.samplesPerChannel * 2 * 2); m_externalAudioframe.avsync_type = 0; m_externalAudioframe.renderTimeMs = 0; - m_externalAudioFrameSize = m_externalAudioframe.samples * 2 * 2; + m_externalAudioFrameSize = m_externalAudioframe.samplesPerChannel * 2 * 2; return &m_externalAudioframe; } @@ -347,23 +608,6 @@ void AgoraRtcEngine::AgoraAudioObserver_Destroy() } } -bool AgoraRtcEngine::enableExtendPlayDevice(bool bEnable) -{ - int ret = 0; - - AParameter apm(*m_rtcEngine); - - if (bEnable) - ret = apm->setParameters( - "{\"che.audio.external_render\":true}"); - else - ret = apm->setParameters( - "{\"che.audio.external_render\":false}"); - apm->release(); - return ret == 0 ? TRUE : FALSE; -} - - std::string AgoraRtcEngine::CalculateToken(std::string appid, const std::string &appcertificate, const std::string &channel, @@ -385,12 +629,17 @@ void AgoraRtcEngine::SetRecordBoost() } -int AgoraRtcEngine::joinChannel(const std::string &key, - const std::string &channel, unsigned int uid, bool enableDual, bool muteAudio , bool muteVideo) +void AgoraRtcEngine::MuteRemoteVideo(unsigned int uid, bool bMute) +{ + m_rtcEngine->muteRemoteVideoStream(uid, bMute); +} + +int AgoraRtcEngine::joinChannel(const std::string &key, const std::string &channel, + unsigned int uid, bool enableDual, bool muteAudio , bool muteVideo, bool loopbackRecording) { if (m_bJoinChannel) return 0; - AUDIO_PROFILE_TYPE profile = AUDIO_PROFILE_MUSIC_STANDARD; + agora::rtc::AUDIO_PROFILE_TYPE profile = agora::rtc::AUDIO_PROFILE_MUSIC_STANDARD; if (audioChannel == 1 && !m_bHighQuality) { profile = AUDIO_PROFILE_MUSIC_STANDARD; } @@ -406,16 +655,38 @@ int AgoraRtcEngine::joinChannel(const std::string &key, //m_rtcEngine->setAudioProfile(profile, (AUDIO_SCENARIO_TYPE)m_scenario); //apm->setParameters("{\"che.audio.codec.name\":\"OPUSFB\"}"); - AParameter apm(m_rtcEngine); - apm->setParameters("{\"che.audio.specify.codec\": \"OPUSFB\"}"); + //AParameter apm(m_rtcEngine); + //apm->setParameters("{\"che.audio.specify.codec\": \"OPUSFB\"}"); ChannelMediaOptions options; options.autoSubscribeAudio = muteAudio; options.autoSubscribeVideo = muteVideo; - + options.publishCustomAudioTrack = true; + options.publishCustomVideoTrack = true; + options.publishCameraTrack = false; + options.publishAudioTrack = false; + options.clientRoleType = CLIENT_ROLE_BROADCASTER; + options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; if (enableDual) m_rtcEngine->enableDualStreamMode(true); + blog(LOG_INFO, "joinChannel: channel=%s, uid=%u", channel.c_str(), uid); + m_rtcEngine->enableLoopbackRecording(loopbackRecording); + int r = m_rtcEngine->joinChannel(key.data(), channel.data(), uid, options);//joinChannel(key.data(), channel.data(), "", uid, options);// + return r; +} - int r = m_rtcEngine->joinChannel(key.data(), channel.data(), "", uid, options);// +int AgoraRtcEngine::joinChannel(const std::string & key, const std::string & channel, unsigned uid) +{ + ChannelMediaOptions options; + options.autoSubscribeAudio = false; + options.autoSubscribeVideo = false; + options.publishCustomAudioTrack = false; + options.publishCustomVideoTrack = true; + options.publishCameraTrack = false; + options.publishAudioTrack = false; + options.clientRoleType = CLIENT_ROLE_BROADCASTER; + options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING; + blog(LOG_INFO, "joinChannelEx: connection channel=%s, uid=%d", connection.channelId, connection.localUid); + int r = m_rtcEngine->joinChannelEx(key.data(), connection, options, m_eventHandlerCamera.get());//joinChannel(key.data(), channel.data(), "", uid, options);// return r; } @@ -425,8 +696,7 @@ int AgoraRtcEngine::leaveChannel() return -1; m_bJoinChannel = false; int r = m_rtcEngine->leaveChannel(); - bFirstAudioFrame = false; - bFirstVideoFrame = false; + if (fpPCM) { fclose(fpPCM); fpPCM = nullptr; @@ -434,6 +704,11 @@ int AgoraRtcEngine::leaveChannel() return r; } +int AgoraRtcEngine::leaveChannelCamera() +{ + return m_rtcEngine->leaveChannelEx(connection); +} + int AgoraRtcEngine::enableVideo(bool enabled) { return enabled ? m_rtcEngine->enableVideo() @@ -445,7 +720,7 @@ int AgoraRtcEngine::setupRemoteVideo(unsigned int uid, void *view) view_t v = reinterpret_cast(view); VideoCanvas canvas; // (v, RENDER_MODE_FIT, uid); canvas.view = v; - canvas.renderMode = RENDER_MODE_HIDDEN; + canvas.renderMode = agora::media::base::RENDER_MODE_HIDDEN; canvas.uid = uid; return m_rtcEngine->setupRemoteVideo(canvas); @@ -468,10 +743,6 @@ bool AgoraRtcEngine::keepPreRotation(bool bRotate) bool AgoraRtcEngine::setVideoProfileEx(int nWidth, int nHeight, int nFrameRate, int nBitRate, bool Agora) { - if (!Agora) { - AParameter apm(m_rtcEngine); - apm->setParameters("{\"che.video.freestyle_customer\": true}"); - } VideoEncoderConfiguration config; config.dimensions.width = nWidth; config.dimensions.height = nHeight; @@ -486,23 +757,31 @@ bool AgoraRtcEngine::setVideoProfileEx(int nWidth, int nHeight, int nFrameRate, return nRet == 0 ? true : false; } -bool AgoraRtcEngine::enableLocalCameara(bool bEnable) +bool AgoraRtcEngine::setCameraEncoderConfiguration(int w, int h, int fps, int bitrate) { - AParameter apm(*m_rtcEngine); - int ret = -1; - if (!apm.get()) - return false; - - if (!bEnable) - ret = apm->setParameters( - "{\"che.video.local.camera_index\":1024}"); + VideoEncoderConfiguration config; + config.dimensions.width = w; + config.dimensions.height = h; + config.frameRate = (FRAME_RATE)fps; + config.bitrate = bitrate; + if (w < h) + config.orientationMode = ORIENTATION_MODE_FIXED_PORTRAIT; else - ret = apm->setParameters( - "{\"che.video.local.camera_index\":0}"); + config.orientationMode = ORIENTATION_MODE_FIXED_LANDSCAPE; + config.orientationMode = ORIENTATION_MODE_ADAPTIVE; + int nRet = m_rtcEngine->setVideoEncoderConfigurationEx(config, connection); - apm.release(); - return ret == 0; + return nRet == 0 ? true : false; } + +void AgoraRtcEngine::setConnection(const std::string& channel, unsigned uid) +{ + channelId = channel; + connection.channelId = channelId.c_str(); + localCameraUid = uid; + connection.localUid = localCameraUid; +} + /////////////////////////////////////////////////////////////////////////////////////// //agora device /////////////////////////////////////////////////////////////////////////////////////// @@ -602,39 +881,13 @@ void AgoraRtcEngine::SetPlayoutDevice(const char* id) (*m_audioDeviceManager)->setPlaybackDevice(id); } -void copy_frame_data_line(uint8_t *dst, int line_size, - const struct video_data *src, - uint32_t plane, uint32_t y) -{ - uint32_t pos_src = y * src->linesize[plane]; - uint32_t pos_dst = y * line_size; - uint32_t bytes = line_size < src->linesize[plane] - ? line_size - : src->linesize[plane]; - - memcpy(dst + pos_dst, src->data[plane] + pos_src, bytes); -} - - void copy_frame_data_plane(uint8_t *dst, int line_size, - const struct video_data *src, - uint32_t plane, uint32_t lines) -{ - if (line_size != src->linesize[plane]) { - for (uint32_t y = 0; y < lines; y++) - copy_frame_data_line(dst, line_size, src, plane, y); - } - else { - memcpy(dst, src->data[plane], - line_size * (size_t)lines); - } -} - void AgoraRtcEngine::enableLastmileTest(bool bEnable) { + LastmileProbeConfig config; if (bEnable) - m_rtcEngine->enableLastmileTest(); + m_rtcEngine->startLastmileProbeTest(config); else - m_rtcEngine->disableLastmileTest(); + m_rtcEngine->stopLastmileProbeTest(); } void AgoraRtcEngine::SavePcm(bool bSave) @@ -645,68 +898,6 @@ void AgoraRtcEngine::SavePcm(bool bSave) //apm->setParameters("{\"che.audio.start_debug_recording\":\"all\"}"); } -void AgoraRtcEngine::PushVideoFrame(struct video_data *frame) -{ - if (!m_bInitialize || !m_bJoinChannel) - return; - - struct obs_video_info ovi; - obs_get_video_info(&ovi); - - if (m_externalVideoFrame.stride != ((ovi.output_width << 4) >> 4) - || m_externalVideoFrame.height != ovi.output_height - || m_format != ovi.output_format) { - delete[] m_externalVideoFrame.buffer; - m_externalVideoFrame.buffer = nullptr; - SetExternalVideoFrame(); - } - - uint8_t* dst = (uint8_t*)m_externalVideoFrame.buffer; - switch (ovi.output_format) { - case VIDEO_FORMAT_I420: { - - copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 0, m_externalVideoFrame.height); - dst += m_externalVideoFrame.stride *m_externalVideoFrame.height; - copy_frame_data_plane(dst, m_externalVideoFrame.stride / 2, frame, 1, m_externalVideoFrame.height / 2); - dst += m_externalVideoFrame.stride *m_externalVideoFrame.height / 4; - copy_frame_data_plane(dst, m_externalVideoFrame.stride/2, frame, 2, m_externalVideoFrame.height / 2); - } - break; - case VIDEO_FORMAT_NV12: { - copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 0, m_externalVideoFrame.height); - - dst += m_externalVideoFrame.stride *m_externalVideoFrame.height; - copy_frame_data_plane(dst, m_externalVideoFrame.stride, frame, 1, m_externalVideoFrame.height / 2); - } - break; - case VIDEO_FORMAT_RGBA: - libyuv::ABGRToARGB(frame->data[0], frame->linesize[0], - (uint8_t*)m_externalVideoFrame.buffer, frame->linesize[0], - ovi.output_width, ovi.output_height); - //copy_frame_data_plane(dst, m_externalVideoFrame.stride * 4, frame, 0, m_externalVideoFrame.height); - break; - - case VIDEO_FORMAT_I444: - libyuv::I444ToARGB( - frame->data[0], frame->linesize[0], - frame->data[1], frame->linesize[1], - frame->data[2], frame->linesize[2], - (uint8_t*)m_externalVideoFrame.buffer, - m_externalVideoFrame.stride * 4, - ovi.output_width, ovi.output_height); - //copy_frame_data_plane(dst, m_externalVideoFrame.stride * 4, frame, 0, m_externalVideoFrame.height); - break; - } - m_externalVideoFrame.timestamp = GetTickCount64(); - - if (!bFirstVideoFrame) { - auto millisec_since_epoch = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - blog(LOG_INFO, "Agora First PushVideoFrame timestamp: %llu ms(system time)", millisec_since_epoch); - bFirstVideoFrame = true; - } - m_pMediaEngine->pushVideoFrame(&m_externalVideoFrame); -} - void AgoraRtcEngine::SetAudioProfile(int scenario, int channels, bool bHighQuality) { m_scenario = (AUDIO_SCENARIO_TYPE)scenario; @@ -782,11 +973,6 @@ void AgoraRtcEngine::PushAudioFrame(struct encoder_frame *frame) memcpy_s(m_externalAudioframe.buffer, frame->linesize[0], frame->data[0], frame->linesize[0]); - if (!bFirstAudioFrame) { - auto millisec_since_epoch = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - blog(LOG_INFO, "Agora First PushAudioFrame timestamp: %llu ms(system time)", millisec_since_epoch); - bFirstAudioFrame = true; - } int ret = m_pMediaEngine->pushAudioFrame(AUDIO_RECORDING_SOURCE, &m_externalAudioframe, false); diff --git a/src/Agora/agorartcengine.hpp b/src/Agora/agorartcengine.hpp index 8322de8d..b0961271 100644 --- a/src/Agora/agorartcengine.hpp +++ b/src/Agora/agorartcengine.hpp @@ -4,6 +4,7 @@ #include #ifdef _WIN32 #include +#include #else #include #include @@ -48,15 +49,18 @@ class AgoraRtcEngine : public QObject void stopPreview(); void SetRecordBoost(); int joinChannel(const std::string &key, const std::string &channel, - unsigned uid, bool enableDual, bool muteAudio = true, bool muteVideo = true); + unsigned uid, bool enableDual, bool muteAudio = true, + bool muteVideo = true, bool loopbackRecording = false); + + int joinChannel(const std::string& key, const std::string& channel, unsigned uid); int leaveChannel(); - - bool keepPreRotation(bool bRotate); - bool setVideoProfileEx(int nWidth, int nHeight, int nFrameRate, int nBitRate, bool Agora = false); - bool enableLocalCameara(bool bEnable); + int leaveChannelCamera(); + bool keepPreRotation(bool bRotate); + bool setVideoProfileEx(int nWidth, int nHeight, int nFrameRate, int nBitRate, bool Agora = false); + bool setCameraEncoderConfiguration(int w, int h, int fps, int bitrate); + void setConnection(const std::string& channel, unsigned uid); void enableLastmileTest(bool bEnable); - bool enableExtendPlayDevice(bool bEnable); - + void* AgoraAudioObserver_Create(); void AgoraAudioObserver_Destroy(); @@ -72,7 +76,7 @@ class AgoraRtcEngine : public QObject void SetPlayoutDevice(const char* id); int testSpeaker(bool start); void EnableAgoraCaptureMicAudio(bool bCapture); - + void PushCameraVideoFrame(struct obs_source_frame* frame); void PushVideoFrame(struct video_data *frame); void PushAudioFrame(struct encoder_frame *frame); void SavePcm(bool bSave); @@ -101,12 +105,10 @@ class AgoraRtcEngine : public QObject void MuteAllRemoteVideo(bool bMute); void MuteAllRemoteAudio(bool bMute); + void MuteRemoteVideo(unsigned int uid, bool bMute); void release(); void SetJoinChannel(bool bJoin) { m_bJoinChannel = bJoin; } - - bool bFirstVideoFrame = false; - bool bFirstAudioFrame = false; signals: void onJoinChannelSuccess(const char* channel, unsigned int uid, int elapsed); void onLeaveChannel(const RtcStats &stats); @@ -125,11 +127,14 @@ class AgoraRtcEngine : public QObject void onSystemCPU(int cpuUsage); private: friend class AgoraRtcEngineEvent; + void SetExternalVideoFrame(); + void SetExternalVideoFrameCamera(struct obs_source_frame* frame); private: - agora::rtc::IRtcEngine* m_rtcEngine = nullptr; + agora::rtc::IRtcEngineEx* m_rtcEngine = nullptr; static AgoraRtcEngine* m_agoraEngine; std::unique_ptr m_eventHandler; + std::unique_ptr m_eventHandlerCamera; bool m_bJoinChannel = false; bool m_bInitialize = false; bool logFirstPushVideo = false; @@ -139,17 +144,19 @@ class AgoraRtcEngine : public QObject int m_externalVideoFrameSize; enum video_format m_format; - agora::media::ExternalVideoFrame m_externalVideoFrame; + enum video_format m_camera_format; + agora::media::base::ExternalVideoFrame m_externalVideoFrame; + agora::media::base::ExternalVideoFrame m_externalVideoFrameCamera; int m_externalAudioFrameSize; static agora::media::IAudioFrameObserver::AudioFrame m_externalAudioframe; bool m_bHighQuality = false; AUDIO_SCENARIO_TYPE m_scenario = AUDIO_SCENARIO_DEFAULT; - - void SetExternalVideoFrame(); - AAudioDeviceManager* m_audioDeviceManager = nullptr; - int count = 0; + + agora::rtc::RtcConnection connection; + std::string channelId; + agora::rtc::uid_t localCameraUid = 0; }; diff --git a/src/agora-plugin/video-plugin-filter.cpp b/src/agora-plugin/video-plugin-filter.cpp new file mode 100644 index 00000000..ccfe64ed --- /dev/null +++ b/src/agora-plugin/video-plugin-filter.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include "../Agora/agorartcengine.hpp" +#ifndef SEC_TO_NSEC +#define SEC_TO_NSEC 1000000000ULL +#endif + +#ifndef MSEC_TO_NSEC +#define MSEC_TO_NSEC 1000000ULL +#endif + +#define SETTING_DELAY_MS "delay_ms" + +#define TEXT_DELAY_MS obs_module_text("DelayMs") + +struct video_plugin_data { + obs_source_t *context; + + /* contains struct obs_source_frame* */ + struct circlebuf video_frames; + + uint64_t last_video_ts; + uint64_t interval; + uint64_t samplerate; + bool video_delay_reached; + bool reset_video; +}; + +static const char *video_plugin_filter_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("VideoPluginFilter"); +} + +static void free_video_data(struct video_plugin_data *filter, + obs_source_t *parent) +{ + while (filter->video_frames.size) { + struct obs_source_frame *frame; + + circlebuf_pop_front(&filter->video_frames, &frame, + sizeof(struct obs_source_frame *)); + obs_source_release_frame(parent, frame); + } +} + +static void video_plugin_filter_update(void *data, obs_data_t *settings) +{ + struct video_plugin_data *filter = (struct video_plugin_data *)data; + uint64_t new_interval = + (uint64_t)obs_data_get_int(settings, SETTING_DELAY_MS) * + MSEC_TO_NSEC; + + if (new_interval < filter->interval) + free_video_data(filter, obs_filter_get_parent(filter->context)); + + filter->reset_video = true; + filter->interval = new_interval; + filter->video_delay_reached = false; +} + +static void *video_plugin_filter_create(obs_data_t *settings, + obs_source_t *context) +{ + struct video_plugin_data *filter = (struct video_plugin_data *)bzalloc(sizeof(*filter)); + filter->context = context; + video_plugin_filter_update(filter, settings); + return filter; +} + +static void video_plugin_filter_destroy(void *data) +{ + struct video_plugin_data *filter = (struct video_plugin_data *)data; + circlebuf_free(&filter->video_frames); + bfree(data); +} + +static obs_properties_t *video_plugin_filter_properties(void *data) +{ + //obs_properties_t *props = obs_properties_create(); + +// obs_property_t *p = obs_properties_add_int(props, SETTING_DELAY_MS, +// TEXT_DELAY_MS, 0, 20000, 1); +// obs_property_int_set_suffix(p, " ms"); + + UNUSED_PARAMETER(data); + return nullptr; +} + +static void video_plugin_filter_remove(void* data, obs_source_t* parent) +{ + struct video_plugin_data* filter = (struct video_plugin_data *)data; + + free_video_data(filter, parent); +} + +/* due to the fact that we need timing information to be consistent in order to + * measure the current interval of data, if there is an unexpected hiccup or + * jump with the timestamps, reset the cached delay data and start again to + * ensure that the timing is consistent */ +static inline bool is_timestamp_jump(uint64_t ts, uint64_t prev_ts) +{ + return ts < prev_ts || (ts - prev_ts) > SEC_TO_NSEC; +} + +static struct obs_source_frame * +video_plugin_filter_video(void *data, struct obs_source_frame *frame) +{ + /*struct video_plugin_data* filter = (struct video_plugin_data*)data; + obs_source_t *parent = obs_filter_get_parent(filter->context); + struct obs_source_frame *output; + uint64_t cur_interval; + + if (filter->reset_video || + is_timestamp_jump(frame->timestamp, filter->last_video_ts)) { + free_video_data(filter, parent); + filter->video_delay_reached = false; + filter->reset_video = false; + } + + filter->last_video_ts = frame->timestamp; + if (!filter->video_delay_reached) + filter->video_delay_reached = true;*/ + + AgoraRtcEngine::GetInstance()->PushCameraVideoFrame(frame); + + return frame; +} +void video_plugin_filter_load(void* data, obs_data_t* settings) +{ + +} +void RegistePluginVideoSource() +{ + struct obs_source_info video_plugin_filter = {}; + video_plugin_filter.id = "video_plugin_filter"; + video_plugin_filter.type = OBS_SOURCE_TYPE_FILTER; + video_plugin_filter.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_ASYNC; + video_plugin_filter.get_name = video_plugin_filter_name; + video_plugin_filter.create = video_plugin_filter_create; + video_plugin_filter.destroy = video_plugin_filter_destroy; + video_plugin_filter.update = video_plugin_filter_update; + video_plugin_filter.get_properties = video_plugin_filter_properties; + video_plugin_filter.filter_video = video_plugin_filter_video; + video_plugin_filter.filter_remove = video_plugin_filter_remove; + video_plugin_filter.load = video_plugin_filter_load; + obs_register_source(&video_plugin_filter); +} \ No newline at end of file diff --git a/src/agora-ui-main.cpp b/src/agora-ui-main.cpp index b285d68c..7469634d 100644 --- a/src/agora-ui-main.cpp +++ b/src/agora-ui-main.cpp @@ -13,6 +13,7 @@ OBS_MODULE_USE_DEFAULT_LOCALE("agora-tool-ui", "en-US") extern void RegisterAgoraOutput(); extern void RegisterAgoraAudioEncoder(); +extern void RegistePluginVideoSource(); bool obs_module_load(void) { blog(LOG_INFO, "load agora tool plugin to communicate with agora rtc sdk"); @@ -20,6 +21,9 @@ bool obs_module_load(void) blog(LOG_INFO, "register agora audio encoder"); RegisterAgoraOutput(); blog(LOG_INFO, "register agora output"); + + RegistePluginVideoSource(); + initQT(); blog(LOG_INFO, "loaded agora tool!"); return true; diff --git a/src/forms/AgoraBasic.ui b/src/forms/AgoraBasic.ui index e38a9627..062d96e9 100644 --- a/src/forms/AgoraBasic.ui +++ b/src/forms/AgoraBasic.ui @@ -7,8 +7,8 @@ 0 0 - 751 - 598 + 749 + 591 @@ -225,7 +225,7 @@ 0 0 - 751 + 749 22 diff --git a/src/forms/AgoraSettings.ui b/src/forms/AgoraSettings.ui index 28f17c3c..d0a7421a 100644 --- a/src/forms/AgoraSettings.ui +++ b/src/forms/AgoraSettings.ui @@ -81,7 +81,7 @@ - 4 + 1 @@ -113,8 +113,8 @@ 0 0 - 578 - 470 + 679 + 480 @@ -179,6 +179,37 @@ + + + + Agora.Settings.GetInfo.Mode + + + + + + + + Agora.Settings.GetInfo.Mode.Manaul + + + + + Agora.Settings.GetInfo.Mode.Http.Get + + + + + + + + Agora.Settings.Agora.APPTOKEN.URL + + + + + + @@ -243,14 +274,14 @@ - + Basic.Settings.Agora.ChannelName - + @@ -267,86 +298,86 @@ - - + + - Basic.Settings.Agora.PersistSave + Plugin.Settings.Camera.UID - - + + - Basic.Settings.Agora.MutAllRemoteAudioVideo + Agora.CPU.Threshold - - - Basic.Settings.Agora.PersistSaveAppid + + + 95 - - + + - Agora.Settings.Agora.APPTOKEN.URL + Basic.Settings.Agora.MutAllRemoteAudioVideo - - - - - + + - Agora.Settings.GetInfo.Mode + Basic.Settings.Agora.PersistSave - - - - - Agora.Settings.GetInfo.Mode.Manaul - - - - - Agora.Settings.GetInfo.Mode.Http.Get - - - - - - + + - Agora.CPU.Threshold + Plugin.Settings.SendObsCamera - - - - 95 + + + + Basic.Settings.Agora.PersistSaveAppid - + Agora.Settings.DualStream - + Basic.Agora.AutoLoadConfig + + + + + + + + + Plugin.Settings.Camera.Token + + + + + + + + @@ -1081,8 +1112,8 @@ 0 0 - 659 - 275 + 696 + 423 @@ -1282,6 +1313,13 @@ + + + + loopback + + + @@ -1502,7 +1540,85 @@ + + + + Camera.Encoder.Settings.Resolution + + + + + + + 320x180 + + + + + 320x240 + + + + + + + + Camera.Encoder.Settings.Bitrate + + + + + + + + Agora.Bitrate.Default + + + + + Agora.Bitrate.Compatible + + + + + Agora.Bitrate.Standard + + + + + + + + Camera.Encoder.Settings.FPS + + + + + + + + Agora.Settings.Video.FPS5 + + + + + Agora.Settings.Video.FPS7 + + + + + Agora.Settings.Video.FPS10 + + + + + Agora.Settings.Video.FPS15 + + + + + @@ -1600,27 +1716,12 @@ - - - 0 - 60 - - color: rgb(255, 0, 0); - - Qt::PlainText - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - diff --git a/src/forms/window-agora-main.cpp b/src/forms/window-agora-main.cpp index 3fd7bc56..e04b056c 100644 --- a/src/forms/window-agora-main.cpp +++ b/src/forms/window-agora-main.cpp @@ -11,8 +11,7 @@ #include #include #include -#include -#define AGORA_TOOL_VERSION "21.06.23.18.00" +#define AGORA_TOOL_VERSION "21.10.08.15.30" #if _WIN32 #else #include @@ -129,6 +128,11 @@ AgoraBasic::AgoraBasic(QMainWindow *parent) InitBasicConfig(); obs_frontend_add_event_callback(AgoraBasic::OBSEvent, this); + + std::string name = "VideoPluginFilter"; + std::string id = "video_plugin_filter"; + camera_filter = obs_source_create( + id.c_str(), name.c_str(), nullptr, nullptr); } void AgoraBasic::InitGlobalConfig() @@ -243,13 +247,12 @@ void AgoraBasic::InitBasicConfig() if (config_has_user_value(globalAgoraConfig, "AgoraTool", "channelName")) m_agoraToolSettings.channelName = config_get_string(globalAgoraConfig, "AgoraTool", "channelName"); m_agoraToolSettings.uid = config_get_uint(globalAgoraConfig, "AgoraTool", "uid"); - + m_agoraToolSettings.agora_fps = config_get_int(globalAgoraConfig, "AgoraTool", "agora_fps"); m_agoraToolSettings.agora_bitrate = config_get_int(globalAgoraConfig, "AgoraTool", "agora_bitrate"); m_agoraToolSettings.agora_width = config_get_int(globalAgoraConfig, "AgoraTool", "agora_width"); m_agoraToolSettings.agora_height = config_get_int(globalAgoraConfig, "AgoraTool", "agora_height"); - m_agoraToolSettings.rtmp_fps = config_get_int(globalAgoraConfig, "AgoraTool", "rtmp_fps"); m_agoraToolSettings.rtmp_bitrate = config_get_int(globalAgoraConfig, "AgoraTool", "rtmp_bitrate"); m_agoraToolSettings.rtmp_width = config_get_int(globalAgoraConfig, "AgoraTool", "rtmp_width"); @@ -269,6 +272,27 @@ void AgoraBasic::InitBasicConfig() if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CPUThreshold")) m_agoraToolSettings.cpuThreshold = config_get_int(globalAgoraConfig, "AgoraTool", "CPUThreshold"); + + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraUID")) + m_agoraToolSettings.camera_uid = config_get_uint(globalAgoraConfig, "AgoraTool", "CameraUID"); + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraToken")) + m_agoraToolSettings.camera_token = config_get_string(globalAgoraConfig, "AgoraTool", "CameraToken"); + + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "SendOBSCamera")) + m_agoraToolSettings.bSendObsCamera = config_get_bool(globalAgoraConfig, "AgoraTool", "SendOBSCamera"); + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraEncWidth")) + m_agoraToolSettings.plugin_camera_width = config_get_int(globalAgoraConfig, "AgoraTool", "CameraEncWidth"); + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraEncHeight")) + m_agoraToolSettings.plugin_camera_height = config_get_int(globalAgoraConfig, "AgoraTool", "CameraEncHeight"); + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraEncFPS")) + m_agoraToolSettings.plugin_camera_fps = config_get_int(globalAgoraConfig, "AgoraTool", "CameraEncFPS"); + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "CameraEncBitrate")) + m_agoraToolSettings.plugin_camera_bitrate = config_get_int(globalAgoraConfig, "AgoraTool", "CameraEncBitrate"); + + if (config_has_user_value(globalAgoraConfig, "AgoraTool", "loopbackRecording")) + m_agoraToolSettings.loopback = config_get_bool(globalAgoraConfig, "AgoraTool", "loopbackRecording"); + + m_agoraToolSettings.obs_bitrate = config_get_int(globalAgoraConfig, "AgoraTool", "obs_bitrate"); } m_agoraToolSettings.savePersistAppid = config_get_bool(globalAgoraConfig, "AgoraTool", "savePersistAppid"); @@ -301,10 +325,10 @@ AgoraBasic::~AgoraBasic() config_set_uint(globalAgoraConfig, "AgoraTool", "uid", m_agoraToolSettings.uid); } else { - config_set_uint(globalAgoraConfig, "AgoraTool", "uid", 0); - config_set_string(globalAgoraConfig, "AgoraTool", "appid", ""); - config_set_string(globalAgoraConfig, "AgoraTool", "token", ""); - config_set_string(globalAgoraConfig, "AgoraTool", "channelName", ""); + // config_set_uint(globalAgoraConfig, "AgoraTool", "uid", 0); + // config_set_string(globalAgoraConfig, "AgoraTool", "appid", ""); + // config_set_string(globalAgoraConfig, "AgoraTool", "token", ""); + // config_set_string(globalAgoraConfig, "AgoraTool", "channelName", ""); } config_set_uint(globalAgoraConfig, "AgoraTool", "InformationMode", m_agoraToolSettings.info_mode); @@ -333,6 +357,15 @@ AgoraBasic::~AgoraBasic() config_set_bool(globalAgoraConfig, "AgoraTool", "bHighQuality", m_agoraToolSettings.bHighQuality); config_set_bool(globalAgoraConfig, "AgoraTool", "savePersist", m_agoraToolSettings.savePersist); config_set_string(globalAgoraConfig, "AgoraTool", "InformationUrl", m_agoraToolSettings.information_url.c_str()); + + config_set_bool(globalAgoraConfig, "AgoraTool", "SendOBSCamera", m_agoraToolSettings.bSendObsCamera); + config_set_uint(globalAgoraConfig, "AgoraTool", "CameraUID", m_agoraToolSettings.camera_uid); + config_set_string(globalAgoraConfig, "AgoraTool", "CameraToken", m_agoraToolSettings.camera_token.c_str()); + config_set_int(globalAgoraConfig, "AgoraTool", "CameraEncWidth", m_agoraToolSettings.plugin_camera_width); + config_set_int(globalAgoraConfig, "AgoraTool", "CameraEncHeight", m_agoraToolSettings.plugin_camera_height); + config_set_int(globalAgoraConfig, "AgoraTool", "CameraEncFPS", m_agoraToolSettings.plugin_camera_fps); + config_set_int(globalAgoraConfig, "AgoraTool", "CameraEncBitrate", m_agoraToolSettings.plugin_camera_bitrate); + config_set_bool(globalAgoraConfig, "AgoraTool", "loopbackRecording", m_agoraToolSettings.loopback); } else { config_set_uint(globalAgoraConfig, "AgoraTool", "InformationMode", 0); @@ -363,6 +396,10 @@ AgoraBasic::~AgoraBasic() config_set_bool(globalAgoraConfig, "AgoraTool", "DualStream", false); config_set_bool(globalAgoraConfig, "AgoraTool", "bHighQuality", false); config_set_bool(globalAgoraConfig, "AgoraTool", "savePersist", false); + + config_set_bool(globalAgoraConfig, "AgoraTool", "bHighQuality", false); + + config_set_bool(globalAgoraConfig, "AgoraTool", "SendOBSCamera", false); } if(m_agoraToolSettings.savePersistAppid && m_agoraToolSettings.info_mode == 0)//manually @@ -402,6 +439,21 @@ size_t http_callback(void *str, size_t size, size_t count, void *out_str) return size * count; } +bool AgoraBasic::EnumSources(void* data, obs_source_t* source) +{ + AgoraBasic* window = + static_cast(data); + const char* name = obs_source_get_name(source); + const char* id = obs_source_get_id(source); + + if (strcmp(id, "dshow_input") == 0) { + obs_data_t* settings = obs_source_get_settings(source); + std::string video_device_id = obs_data_get_string(settings, "video_device_id"); + window->source_camera = source; + } + return true; +} + void AgoraBasic::on_agoraSteramButton_clicked() { QString str = ui->agoraSteramButton->text(); @@ -455,8 +507,7 @@ void AgoraBasic::on_agoraSteramButton_clicked() } if (res != CURLE_OK) { - emit requestTokenSignal("", -1); - //QMessageBox::information(NULL, QString(""), requertTokenError); + emit requestTokenSignal("", -1); return; } blog(LOG_INFO, "request token result is %s.", json_res.c_str()); @@ -471,14 +522,15 @@ void AgoraBasic::on_agoraSteramButton_clicked() } else { obs_remove_raw_video_callback(RawVideoCallback, this); + obs_source_filter_remove(source_camera, camera_filter); StopAgoraOutput(); AgoraRtcEngine::GetInstance()->stopPreview(); - //ResetEvent(stopSignal); if (joinFailed) AgoraRtcEngine::GetInstance()->SetJoinChannel(true); AgoraRtcEngine::GetInstance()->leaveChannel(); - //SetEvent(stopSignal); + if (m_agoraToolSettings.bSendObsCamera) + AgoraRtcEngine::GetInstance()->leaveChannelCamera(); if (!m_agoraToolSettings.agora_url.empty()) AgoraRtcEngine::GetInstance()->RemovePublishStreamUrl(m_agoraToolSettings.agora_url.c_str()); @@ -516,6 +568,10 @@ void AgoraBasic::joinChannel(std::string token) } if (current_source) { + obs_enum_sources(EnumSources, this); + + if(source_camera) + obs_source_filter_add(source_camera, camera_filter); obs_get_video_info(&ovi); video_scale_info info; info.width = ovi.output_width; @@ -524,8 +580,8 @@ void AgoraBasic::joinChannel(std::string token) info.range = ovi.range; info.colorspace = ovi.colorspace; obs_add_raw_video_callback(&info, RawVideoCallback, (void*)this); - } - + } + StartAgoraOutput(); int output_width = ovi.output_width; @@ -557,12 +613,27 @@ void AgoraBasic::joinChannel(std::string token) (float)ovi.fps_num / (float)ovi.fps_den, m_agoraToolSettings.obs_bitrate); } + + AgoraRtcEngine::GetInstance()->setConnection(m_agoraToolSettings.channelName, m_agoraToolSettings.camera_uid); + joinFailedTimer.stop(); joinFailedTimer.start(10000); blog(LOG_INFO, "agora token:%s", m_agoraToolSettings.token.c_str()); + AgoraRtcEngine::GetInstance()->joinChannel(m_agoraToolSettings.token.c_str() , m_agoraToolSettings.channelName.c_str(), m_agoraToolSettings.uid, m_agoraToolSettings.bDualStream, - !m_agoraToolSettings.muteAllRemoteAudioVideo, !m_agoraToolSettings.muteAllRemoteAudioVideo); + !m_agoraToolSettings.muteAllRemoteAudioVideo, !m_agoraToolSettings.muteAllRemoteAudioVideo, + m_agoraToolSettings.loopback); + if (m_agoraToolSettings.bSendObsCamera) { + AgoraRtcEngine::GetInstance()->joinChannel(m_agoraToolSettings.camera_token.c_str(), + m_agoraToolSettings.channelName.c_str(), m_agoraToolSettings.camera_uid); + AgoraRtcEngine::GetInstance()->setCameraEncoderConfiguration( + m_agoraToolSettings.plugin_camera_width, + m_agoraToolSettings.plugin_camera_height, + m_agoraToolSettings.plugin_camera_fps, + m_agoraToolSettings.plugin_camera_bitrate); + + } ui->agoraSteramButton->setText(starting_text); } @@ -580,7 +651,6 @@ void AgoraBasic::reuquestToken_slot(QString json, int err) } QJsonObject jsonObject = doc.object(); - int code = jsonObject["code"].toInt(); if (code != 0) { QMessageBox::information(NULL, QString(""), requertTokenError); @@ -595,25 +665,24 @@ void AgoraBasic::reuquestToken_slot(QString json, int err) return; } #if _WIN32 - m_agoraToolSettings.appid = jsData["appID"].toString().toUtf8(); - m_agoraToolSettings.channelName = jsData["channelName"].toString().toUtf8(); - m_agoraToolSettings.token = jsData["token"].toString().toUtf8(); + m_agoraToolSettings.appid = jsData["appID"].toString().toUtf8(); + m_agoraToolSettings.channelName = jsData["channelName"].toString().toUtf8(); + m_agoraToolSettings.token = jsData["token"].toString().toUtf8(); #else - m_agoraToolSettings.appid = jsData["appID"].toString().toStdString(); - m_agoraToolSettings.channelName = jsData["channelName"].toString().toStdString(); - m_agoraToolSettings.token = jsData["token"].toString().toStdString(); + m_agoraToolSettings.appid = jsData["appID"].toString().toStdString(); + m_agoraToolSettings.channelName = jsData["channelName"].toString().toStdString(); + m_agoraToolSettings.token = jsData["token"].toString().toStdString(); #endif - - m_agoraToolSettings.uid = strtoul(jsData["uid"].toString().toUtf8().data(), nullptr, 10); + m_agoraToolSettings.camera_token = jsData["cameraToken"].toString().toStdString(); + m_agoraToolSettings.uid = strtoul(jsData["uid"].toString().toStdString().data(), nullptr, 10); + m_agoraToolSettings.camera_uid = strtoul(jsData["cameraUid"].toString().toStdString().data(), nullptr, 10); joinChannel(m_agoraToolSettings.token); - return; } else if(err == -1){ QMessageBox::information(NULL, QString(""), requertTokenError); } - ui->agoraSteramButton->setText(start_text); } @@ -1073,6 +1142,11 @@ void AgoraBasic::onError_slot(int err, const char *msg) void AgoraBasic::onUserJoined_slot(uid_t uid, int elapsed) { + if (uid == m_agoraToolSettings.camera_uid) { + if (m_agoraToolSettings.bSendObsCamera) + AgoraRtcEngine::GetInstance()->MuteRemoteVideo(m_agoraToolSettings.camera_uid, true); + return; + } m_lstUids.push_back(uid); if (m_lstUids.size() > 16) { @@ -1234,6 +1308,9 @@ void AgoraBasic::onConnectionStateChanged_slot(int state, int reason) void AgoraBasic::onRemoteVideoStateChanged_slot(unsigned int uid, int state, int reason, int elapsed) { + if (uid == m_agoraToolSettings.camera_uid) + return; + if (state == REMOTE_VIDEO_STATE_DECODING &&( reason == REMOTE_VIDEO_STATE_REASON_REMOTE_UNMUTED || reason == REMOTE_VIDEO_STATE_REASON_LOCAL_UNMUTED)) { blog(LOG_INFO, "onRemoteVideoStateChanged, reason:%d, uid:%u", reason, uid); @@ -1386,9 +1463,8 @@ void AgoraBasic::onSystemCPU_slot(int cpuUsage) count1++; } } - blog(LOG_INFO, "Agora System CPU Information(first 2 minutes):%s", info.c_str()); int count2 = 0; - info = ""; + std::string lastInfo = ""; for (int i = 0; i < lastMinCpu.size(); ++i) { int cpu = lastMinCpu[i]; char szInfo[10] = { 0 }; @@ -1397,19 +1473,18 @@ void AgoraBasic::onSystemCPU_slot(int cpuUsage) #else snprintf(szInfo, 10, "%d ", cpu); #endif - info += szInfo; + lastInfo += szInfo; if (cpu > m_agoraToolSettings.cpuThreshold) { count2++; } } - blog(LOG_INFO, "Agora System CPU Information(last minute):%s", info.c_str()); - if (count1 > 25 && count2 >= 10) { lastMinCpu.clear(); first2MinCpu.clear(); + blog(LOG_INFO, "Agora System CPU Information(first 2 minutes):%s", info.c_str()); + blog(LOG_INFO, "Agora System CPU Information(last minute):%s", lastInfo.c_str()); QMessageBox::information(this, QString(""), cpuInformation); } } -} - +} \ No newline at end of file diff --git a/src/forms/window-agora-main.hpp b/src/forms/window-agora-main.hpp index dda74d30..a14160d6 100644 --- a/src/forms/window-agora-main.hpp +++ b/src/forms/window-agora-main.hpp @@ -50,6 +50,7 @@ typedef struct tagAgoraToolSettings { int rtmp_width = 1280; int rtmp_height = 720; + bool loopback = false; int audioChannel = 2; int scenario = 0; bool bHighQuality = false; @@ -59,14 +60,18 @@ typedef struct tagAgoraToolSettings { int videoEncoder = 0;//default agora bitrate bool savePersistAppid = false; - std::string information_url = ""; int info_mode = 0;//0:manually 1:http get bool SavePCM = false; - int cpuThreshold = 95; - bool bDualStream = false; + bool bSendObsCamera = false; + unsigned int camera_uid = 0; + std::string camera_token = ""; + int plugin_camera_fps = 15; + int plugin_camera_bitrate = 0; + int plugin_camera_width = 320; + int plugin_camera_height = 180; } AgoraToolSettings, *PAgoraToolSettings; class DisplayResizeEvent : public QObject @@ -148,6 +153,8 @@ class AgoraBasic : public QMainWindow { std::vector first2MinCpu; std::vector lastMinCpu; + obs_source* source_camera = nullptr; + obs_source_t *camera_filter; ConfigFile globalConfig; ConfigFile basicConfig; ConfigFile globalAgoraConfig; @@ -160,6 +167,7 @@ class AgoraBasic : public QMainWindow { virtual void showEvent(QShowEvent *event)override; virtual void hideEvent(QHideEvent *event)override; virtual void closeEvent(QCloseEvent *event)override; + static bool EnumSources(void* data, obs_source_t* source); private: void CreateRemoteVideos(); void DestroyRemoteVideos(); diff --git a/src/forms/window-agora-settings.cpp b/src/forms/window-agora-settings.cpp index 6b3e0fc8..658b17cf 100644 --- a/src/forms/window-agora-settings.cpp +++ b/src/forms/window-agora-settings.cpp @@ -96,7 +96,15 @@ AgoraSettings::AgoraSettings(QWidget *parent) qualityDetecting= tr("Agora.Test.Network.Result.Detecting"); testingNet = tr("Agora.Network.Testing"); + errEmptyCameraUID = tr("Plugin.OBS.Camera.UID.Empty"); + errSameUID = tr("Plugin.OBS.Camera.UID.Conflict"); + testingNetInfo = tr("Agora.Network.Testing.Info"); + + ui->labeCameraUID->setText(tr("Plugin.Settings.Camera.UID")); + ui->chkObsCamera->setText(tr("Plugin.Settings.SendObsCamera")); + + ui->labelCameraToken->setText(tr("Plugin.Settings.Camera.Token")); #if WIN32 #else ui->labUrl->hide(); @@ -152,6 +160,16 @@ AgoraSettings::AgoraSettings(QWidget *parent) ui->cmbAgoraBitrate->setItemText(0, tr("Agora.Bitrate.Default")); ui->cmbAgoraBitrate->setItemText(1, tr("Agora.Bitrate.Compatible")); ui->cmbAgoraBitrate->setItemText(2, tr("Agora.Bitrate.Standard")); + + fps_index = 0; + ui->cmbCameraFPS->setItemText(fps_index++, tr("Agora.Settings.Video.FPS5")); + ui->cmbCameraFPS->setItemText(fps_index++, tr("Agora.Settings.Video.FPS7")); + ui->cmbCameraFPS->setItemText(fps_index++, tr("Agora.Settings.Video.FPS10")); + ui->cmbCameraFPS->setItemText(fps_index++, tr("Agora.Settings.Video.FPS15")); + + ui->cmbCameraBitrate->setItemText(0, tr("Agora.Bitrate.Default")); + ui->cmbCameraBitrate->setItemText(1, tr("Agora.Bitrate.Compatible")); + ui->cmbCameraBitrate->setItemText(2, tr("Agora.Bitrate.Standard")); //listwidget ui->listWidget->item(0)->setText(tr("Agora.Settings.General")); ui->listWidget->item(1)->setText(tr("Agora.Settings.Audio")); @@ -173,6 +191,7 @@ AgoraSettings::AgoraSettings(QWidget *parent) persistSaveAppid = tr("Basic.Settings.Agora.PersistSaveAppid"); persistSaveAppidInfo = tr("Basic.Settings.Agora.PersistSaveAppidInfo"); ui->baseAspect->setText(tr("")); + emptyUrlError = tr("Plugin.Settings.Error.EmptyUrl"); ui->chkPersistSaveAppid->setText(persistSaveAppid); //video encoder @@ -182,6 +201,9 @@ AgoraSettings::AgoraSettings(QWidget *parent) ui->cmbVideoEncoder->setItemText(1, tr("Agora.Settings.Video.OBS.Bitrate")); ui->cmbVideoEncoder->setCurrentIndex(0); + ui->labCameraEncoderRes->setText(tr("Camera.Encoder.Settings.Resolution")); + ui->labCameraEncoderBitrate->setText(tr("Camera.Encoder.Settings.Bitrate")); + ui->labCameraEncoderFPS->setText(tr("Camera.Encoder.Settings.FPS")); obs_frontend_pop_ui_translation(); ui->btnNetworkTest->setText(startTestNet); ui->labelTestNetWork->setText(""); @@ -221,8 +243,21 @@ AgoraSettings::AgoraSettings(QWidget *parent) dimmision.width = 1920; dimmision.height = 1080; m_vecResolution.push_back(dimmision); - + //camera resolution + dimmision.width = 320; + dimmision.height = 180; + m_vecCameraResolution.push_back(dimmision); + dimmision.width = 320; + dimmision.height = 240; + m_vecCameraResolution.push_back(dimmision); + dimmision.width = 180; + dimmision.height = 320; + //m_vecCameraResolution.push_back(dimmision); + dimmision.width = 240; + dimmision.height = 320; + //m_vecCameraResolution.push_back(dimmision); + LoadGeneralSettings(); LoadAudioSettings(); LoadVideoSettings(); @@ -240,6 +275,9 @@ AgoraSettings::AgoraSettings(QWidget *parent) HookWidget(ui->chkMuteAllRemoteAV, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->chkDualStream, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->chkObsCamera, CHECK_CHANGED, GENERAL_CHANGED); + HookWidget(ui->lineEditCameraUID , EDIT_CHANGED, GENERAL_CHANGED); + HookWidget(ui->lineEditCameraToken, EDIT_CHANGED, GENERAL_CHANGED); HookWidget(ui->playoutDevices, COMBO_CHANGED, AUDIO_CHANGED); HookWidget(ui->recordSampleRate, COMBO_CHANGED, AUDIO_CHANGED); @@ -253,6 +291,9 @@ AgoraSettings::AgoraSettings(QWidget *parent) HookWidget(ui->cmbAgoraVideoDevice, COMBO_CHANGED, VIDEO_CHANGED); HookWidget(ui->cmbVideoEncoder, COMBO_CHANGED, VIDEO_CHANGED); + HookWidget(ui->cmbCameraBitrate, COMBO_CHANGED, VIDEO_CHANGED); + HookWidget(ui->cmbCameraFPS, COMBO_CHANGED, VIDEO_CHANGED); + HookWidget(ui->cmbCameraResoltuion, COMBO_CHANGED, VIDEO_CHANGED); HookWidget(ui->lineEditAgoraRTmp, EDIT_CHANGED, RTMP_CHANGED); HookWidget(ui->lineEditAgoraRtmpFPS, EDIT_CHANGED, RTMP_CHANGED); @@ -263,14 +304,13 @@ AgoraSettings::AgoraSettings(QWidget *parent) HookWidget(ui->chkPersistSaving, CHECK_CHANGED, GENERAL_CHANGED); HookWidget(ui->chkSavePCM, CHECK_CHANGED, AUDIO_CHANGED); HookWidget(ui->spinCPU, SPINBOX_CHANGED, GENERAL_CHANGED); + HookWidget(ui->chkLoopback, CHECK_CHANGED, AUDIO_CHANGED); connect(ui->chkPersistSaveAppid, &QCheckBox::toggled, this, &AgoraSettings::onChkSaveAppidSettings); + connect(ui->chkObsCamera, &QCheckBox::toggled, this, &AgoraSettings::on_chkObsCamera_check); connect(AgoraRtcEngine::GetInstance(), &AgoraRtcEngine::onLastmileQuality, this, &AgoraSettings::OnLastmileTest); - - ui->labelTestNetWork->setWordWrap(true); } - AgoraSettings::~AgoraSettings() { @@ -283,7 +323,6 @@ void AgoraSettings::HookWidget(QWidget *widget, const char *signal, widget->setProperty("changed", QVariant(false)); } - void AgoraSettings::GeneralChanged() { if (!loading) { @@ -349,7 +388,7 @@ void AgoraSettings::SaveAudioSettings() settings.scenario = ui->cmbScenario->currentIndex(); settings.audioChannel = ui->cmbRecordChannelSetup->currentIndex() + 1; settings.SavePCM = ui->chkSavePCM->isChecked(); - settings.cpuThreshold = ui->spinCPU->value(); + settings.loopback = ui->chkLoopback->isChecked(); main->SetAgoraSetting(settings); AgoraRtcEngine::GetInstance()->SetAudioProfile(settings.scenario, settings.audioChannel, settings.bHighQuality); } @@ -359,11 +398,16 @@ void AgoraSettings::SaveVideoSettings() AgoraToolSettings settings; main->GetAgoraSetting(settings); - settings.agora_fps = agora_fps[ui->cmbAgoraFPS->currentIndex()]; + settings.agora_fps = agora_fps[ui->cmbAgoraFPS->currentIndex()]; settings.agora_bitrate = agora_bitrate[ui->cmbAgoraBitrate->currentIndex()]; - settings.agora_width = m_vecResolution[ui->agoraResolution->currentIndex()].width; - settings.agora_height = m_vecResolution[ui->agoraResolution->currentIndex()].height; - settings.videoEncoder = ui->cmbVideoEncoder->currentIndex(); + settings.agora_width = m_vecResolution[ui->agoraResolution->currentIndex()].width; + settings.agora_height = m_vecResolution[ui->agoraResolution->currentIndex()].height; + settings.videoEncoder = ui->cmbVideoEncoder->currentIndex(); + + settings.plugin_camera_bitrate = agora_bitrate[ui->cmbCameraBitrate->currentIndex()]; + settings.plugin_camera_fps = agora_fps[ui->cmbCameraFPS->currentIndex()]; + settings.plugin_camera_width = m_vecCameraResolution[ui->cmbCameraResoltuion->currentIndex()].width; + settings.plugin_camera_height = m_vecCameraResolution[ui->cmbCameraResoltuion->currentIndex()].height; main->SetAgoraSetting(settings); } @@ -371,10 +415,10 @@ void AgoraSettings::SaveGeneralSettings() { AgoraToolSettings settings; main->GetAgoraSetting(settings); - QString strAppid = ui->lineEditAppid->text().toUtf8(); + QString strAppid = ui->lineEditAppid->text(); strAppid = strAppid.trimmed(); if (AgoraRtcEngine::GetInstance()->IsInitialize() - && !settings.appid.empty() && settings.appid.compare(strAppid.toUtf8()) != 0) + && !settings.appid.empty() && settings.appid.compare(strAppid.toStdString()) != 0) appid_changed = true; settings.appid = strAppid.toStdString(); @@ -385,19 +429,16 @@ void AgoraSettings::SaveGeneralSettings() settings.info_mode = ui->cmbGetMode->currentIndex(); if (!strAppid.isEmpty()) settings.appid = strAppid.toStdString(); - settings.appCerf = ui->lineEditAppCertificate->text().toStdString(); - settings.token = ui->lineEditToken->text().toStdString(); - settings.channelName = ui->lineEditChannel->text().toStdString(); settings.cpuThreshold = ui->spinCPU->value(); QString strUid = ui->lineEditUID->text(); if (strUid.length() > 0) - settings.uid = strtoul(strUid.toUtf8().data(), NULL, 10); + settings.uid = strtoul(strUid.toStdString().data(), NULL, 10); else settings.uid = 0; QString strExpired = ui->lineEditExpiredTs->text(); if (strExpired.length() > 0) settings.expiredTime = - strtoul(strExpired.toUtf8().data(), NULL, 10); + strtoul(strExpired.toStdString().data(), NULL, 10); else settings.expiredTime = AGORA_SETTINGS_EXPIREDTS; settings.expiredTimeTs = settings.expiredTime * 60 * 60; @@ -406,9 +447,12 @@ void AgoraSettings::SaveGeneralSettings() settings.savePersistAppid = ui->chkPersistSaveAppid->isChecked(); settings.bDualStream = ui->chkDualStream->isChecked(); - - main->SetAgoraSetting(settings); - + QString strCameraUid = ui->lineEditCameraUID->text(); + if (strCameraUid.length() > 0) + settings.camera_uid = strtoul(strCameraUid.toStdString().data(), NULL, 10); + settings.bSendObsCamera = ui->chkObsCamera->isChecked(); + settings.camera_token = ui->lineEditCameraToken->text().toStdString(); + settings.cpuThreshold = ui->spinCPU->value(); SaveCheckBox(ui->chkPersistSaving, "AgoraSettings", "PersistSave"); if (settings.savePersistAppid && !strAppid.isEmpty()) SaveEdit(ui->lineEditAppid, "AgoraSettings", "AppId"); @@ -417,7 +461,7 @@ void AgoraSettings::SaveGeneralSettings() SaveEdit(ui->lineEditUrl, "AgoraSettings", "InformationUrl"); if (!strUid.isEmpty()) - SaveEdit(ui->lineEditUID, "AgoraSettings", "UID"); + SaveEdit(ui->lineEditUID, "AgoraSettings", "uid"); if (!strExpired.isEmpty()) SaveEdit(ui->lineEditExpiredTs, "AgoraSettings", "TokenExpired"); @@ -450,7 +494,14 @@ void AgoraSettings::SaveGeneralSettings() SaveCheckBox(ui->chkDualStream, "AgoraSettings", "DualStream", settings.bDualStream); + + SaveCheckBox(ui->chkObsCamera, "AgoraSettings", + "SendOBSCamera", + settings.bSendObsCamera); } + + main->SetAgoraSetting(settings); + } @@ -520,8 +571,7 @@ void AgoraSettings::LoadGeneralSettings() ui->chkDualStream->setChecked(settings.bDualStream); QString strExpired = QString("%1").arg(settings.expiredTime); ui->lineEditExpiredTs->setText(strExpired); - loading = false; - + ui->lineEditAgoraRTmp->setText( QString::fromUtf8(settings.rtmp_url.data())); @@ -533,6 +583,15 @@ void AgoraSettings::LoadGeneralSettings() ui->lineEditAgoraRtmpWidth->setText(QString("%1").arg(settings.rtmp_width)); ui->lineEditAgoraRtmpHeight->setText(QString("%1").arg(settings.rtmp_height)); ui->spinCPU->setValue(settings.cpuThreshold); + + ui->chkObsCamera->setChecked(settings.bSendObsCamera); + if (settings.camera_uid > 0) { + QString strCameraUid = QString("%1").arg(settings.camera_uid); + ui->lineEditCameraUID->setText(strCameraUid); + } + ui->lineEditCameraToken->setText(QString::fromUtf8(settings.camera_token.data())); + loading = false; + } void AgoraSettings::LoadAudioDevice() @@ -557,7 +616,7 @@ void AgoraSettings::LoadAudioSettings() ui->cmbScenario->setCurrentIndex(settings.scenario); ui->chkSavePCM->setChecked(settings.SavePCM); - + ui->chkLoopback->setChecked(settings.loopback); ui->cmbRecordChannelSetup->setCurrentIndex(settings.audioChannel - 1); loading = false; } @@ -597,7 +656,6 @@ void AgoraSettings::LoadVideoSettings() break; } } - ui->cmbVideoEncoder->setCurrentIndex(setting.videoEncoder); for (int i = 0; i < m_vecResolution.size(); i++) { @@ -607,6 +665,34 @@ void AgoraSettings::LoadVideoSettings() ui->agoraResolution->setCurrentIndex(i); } + //camera + auto addCameraRes = [this](int cx, int cy) { + QString res = ResString(cx, cy).c_str(); + if (ui->cmbCameraResoltuion->findText(res) == -1) + ui->cmbCameraResoltuion->addItem(res); + }; + ui->cmbCameraResoltuion->clear(); + for (int i = 0; i < m_vecCameraResolution.size(); i++) { + addCameraRes(m_vecCameraResolution[i].width, m_vecCameraResolution[i].height); + if (m_vecCameraResolution[i].width == setting.plugin_camera_width + && m_vecCameraResolution[i].height == setting.plugin_camera_height) + ui->cmbCameraResoltuion->setCurrentIndex(i); + } + + for (int i = 0; i < 4; ++i) { + if (agora_fps[i] == setting.plugin_camera_fps) { + ui->cmbCameraFPS->setCurrentIndex(i); + break; + } + } + + for (int i = 0; i < 3; ++i) { + if (agora_bitrate[i] == setting.plugin_camera_bitrate) { + ui->cmbCameraBitrate->setCurrentIndex(i); + break; + } + } + loading = false; } @@ -647,6 +733,7 @@ void AgoraSettings::LoadAgoraSettings() ui->chkDualStream->setChecked(settings.bDualStream); QString strExpired = QString("%1").arg(settings.expiredTime); ui->lineEditExpiredTs->setText(strExpired); + ui->lineEditCameraToken->setText(QString::fromUtf8(settings.token.data())); loading = false; } @@ -680,7 +767,7 @@ void AgoraSettings::on_buttonAppid_clicked() QMessageBox::about(nullptr, title, init_failed_info + appid); return; } - + ui->buttonAppid->setEnabled(false); AgoraToolSettings setting; @@ -693,15 +780,31 @@ void AgoraSettings::on_buttonAppid_clicked() void AgoraSettings::on_buttonBox_clicked(QAbstractButton *button) { - if(!checkTestNetwork()) - return; - QDialogButtonBox::ButtonRole val = ui->buttonBox->buttonRole(button); - if (val == QDialogButtonBox::ApplyRole || val == QDialogButtonBox::AcceptRole) { if (ui->chkSavePCM->isChecked()) { + } + if (!checkTestNetwork()) + return; + + if (ui->cmbGetMode->currentIndex() == 0){ + if (ui->lineEditUrl->text().isEmpty()) { + QMessageBox::about(nullptr, title, emptyUrlError); + return; + } + if (ui->chkObsCamera->isChecked() && ui->lineEditCameraUID->text().isEmpty()) { + QMessageBox::about(nullptr, title, errEmptyCameraUID); + return; + } + + if (ui->chkObsCamera->isChecked() && + ui->lineEditUID->text().compare( + ui->lineEditCameraUID->text()) == 0) { + QMessageBox::about(nullptr, title, errSameUID); + return; + } } SaveSettings(); ClearChanged(); @@ -787,7 +890,6 @@ void AgoraSettings::on_loadConfigButton_clicked() break; } } - } } @@ -820,6 +922,11 @@ void AgoraSettings::on_cmbGetMode_currentIndexChanged(int index) ui->labUrl->show(); ui->lineEditUrl->show(); } + ui->lineEditAppid->setEnabled(index == 0); + ui->lineEditCameraUID->setEnabled(index == 0); + ui->lineEditUID->setEnabled(index == 0); + ui->lineEditToken->setEnabled(index == 0); + ui->lineEditChannel->setEnabled(index == 0); } void AgoraSettings::on_playoutVolumeSld_valueChanged(int value) @@ -835,7 +942,7 @@ void AgoraSettings::showEvent(QShowEvent *event) ui->lineEditAppid->setEnabled(bEnabled); ui->lineEditChannel->setEnabled(bEnabled); ui->lineEditExpiredTs->setEnabled(bEnabled); - ui->lineEditUID->setEnabled(bEnabled); + ui->lineEditUID ->setEnabled(bEnabled); ui->chkAudioHighQuality->setEnabled(bEnabled); ui->cmbRecordChannelSetup->setEnabled(bEnabled); ui->cmbScenario->setEnabled(bEnabled); @@ -843,9 +950,13 @@ void AgoraSettings::showEvent(QShowEvent *event) ui->cmbAgoraBitrate->setEnabled(bEnabled); ui->cmbVideoEncoder->setEnabled(bEnabled); ui->btnNetworkTest->setEnabled(bEnabled); - ui->buttonAppid->setEnabled(!AgoraRtcEngine::GetInstance()->IsInitialize()); -} + ui->lineEditCameraUID->setEnabled(bEnabled); + ui->lineEditCameraToken->setEnabled(bEnabled); + ui->lineEditUrl->setEnabled(bEnabled); + ui->buttonAppid->setEnabled(AgoraRtcEngine::GetInstance()->IsInitialize()); + on_chkObsCamera_check(ui->chkObsCamera->isChecked()); +} /*typedef void(*obs_source_audio_capture_t)(void *param, obs_source_t *source, const struct audio_data *audio_data, @@ -944,4 +1055,15 @@ void AgoraSettings::closeEvent(QCloseEvent *event) return; } close(); +} +void AgoraSettings::on_chkObsCamera_check(bool check) +{ + ui->labeCameraUID->setVisible(check); + ui->lineEditCameraUID->setVisible(check); + ui->labCameraEncoderBitrate->setVisible(check); + ui->cmbCameraBitrate->setVisible(check); + ui->labCameraEncoderFPS->setVisible(check); + ui->cmbCameraFPS->setVisible(check); + ui->labCameraEncoderRes->setVisible(check); + ui->cmbCameraResoltuion->setVisible(check); } \ No newline at end of file diff --git a/src/forms/window-agora-settings.hpp b/src/forms/window-agora-settings.hpp index 6bc69bba..5ce67b96 100644 --- a/src/forms/window-agora-settings.hpp +++ b/src/forms/window-agora-settings.hpp @@ -55,9 +55,13 @@ class AgoraSettings : public QDialog { QString testingNet = ""; QString testingNetInfo = ""; + QString errEmptyCameraUID = ""; + QString errSameUID = ""; + QString emptyUrlError = ""; bool networkTest = false; std::vector m_vecResolution; + std::vector m_vecCameraResolution; inline void EnableApplyButton(bool en) { ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(en); @@ -113,4 +117,5 @@ private slots: void on_cmbGetMode_currentIndexChanged(int index); void on_btnNetworkTest_clicked(); void OnLastmileTest(int quality); + void on_chkObsCamera_check(bool check); };