Skip to content

Commit

Permalink
refactor: LibObsRecorder refactor (#252)
Browse files Browse the repository at this point in the history
Made LibObsRecorder a bit neater by separating StartRecording() into multiple methods.
  • Loading branch information
sonicv6 authored Nov 23, 2024
1 parent 46a4452 commit 5c6ac32
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 295 deletions.
510 changes: 238 additions & 272 deletions Classes/Recorders/LibObsRecorder.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Classes/Recorders/PlaysLTCRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public override void Start() {
ltc.VideoCaptureReady += (sender, msg) => {
RecordingService.GetCurrentSession().Pid = msg.Pid;
if (SettingsService.Settings.captureSettings.recordingMode == "automatic")
RecordingService.StartRecording();
RecordingService.StartRecording(false);
};

ltc.ProcessTerminated += (sender, msg) => {
Expand Down
4 changes: 2 additions & 2 deletions Classes/Services/DetectionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static void WindowCreation(IntPtr hwnd, int processId = 0, [CallerMemberN
WindowService.GetExecutablePathFromProcessId(processId, out string executablePath);

if (executablePath != null) {
if (executablePath.ToString().ToLower().StartsWith(@"c:\windows\")) { // if this program is starting from here,
if (executablePath.ToLower().StartsWith(@"c:\windows\")) { // if this program is starting from here,
return; // we can assume it is not a game
}
}
Expand Down Expand Up @@ -252,7 +252,7 @@ public static bool AutoDetectGame(int processId, string executablePath, nint win
bool allowed = SettingsService.Settings.captureSettings.recordingMode is "automatic" or "whitelist";
Logger.WriteLine($"{(allowed ? "Starting capture for" : "Ready to capture")} application: {detailedWindowStr}");
RecordingService.SetCurrentSession(processId, windowHandle, gameTitle, executablePath, gameDetection.forceDisplayCapture);
if (allowed) RecordingService.StartRecording();
if (allowed) RecordingService.StartRecording(false);
}
return isGame;
}
Expand Down
2 changes: 1 addition & 1 deletion Classes/Services/Keybinds/RecordingKeybind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public RecordingKeybind() {
}
public override void Action() {
if (RecordingService.IsRecording) RecordingService.StopRecording(true);
else RecordingService.StartRecording();
else RecordingService.StartRecording(true);
}
}
}
73 changes: 67 additions & 6 deletions Classes/Services/RecordingService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using RePlays.Recorders;
using RePlays.Utils;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Timers;
using static RePlays.Utils.Functions;
using Timer = System.Timers.Timer;


Expand All @@ -21,12 +23,17 @@ public static class RecordingService {
private static bool IsRestarting { get; set; }
public static bool GameInFocus { get; set; }

const int retryInterval = 2000; // 2 second
const int maxRetryAttempts = 20; // 30 retries

public class Session {
public int Pid { get; internal set; }
public nint WindowHandle { get; internal set; }
public string GameTitle { get; internal set; }
public string Exe { get; internal set; }
public bool ForceDisplayCapture { get; internal set; }
public string videoSavePath { get; internal set; }

public Session(int _Pid, nint _WindowHandle, string _GameTitle, string _Exe = null, bool _ForceDisplayCapture = false) {
Pid = _Pid;
WindowHandle = _WindowHandle;
Expand All @@ -48,6 +55,8 @@ public static async void Start(Type type) {
ActiveRecorder = new LibObsRecorder();
Logger.WriteLine("Creating a new ActiveRecorder");
await Task.Run(() => ActiveRecorder.Start());
//Update user settings
WebMessage.SendMessage(GetUserSettings());
await Task.Run(() => DetectionService.CheckTopLevelWindows());
}

Expand All @@ -59,19 +68,69 @@ public static Session GetCurrentSession() {
return currentSession;
}

private static async Task<bool> GetGoodWindowHandle() {
int retryAttempt = 0;
while ((DetectionService.HasBadWordInClassName(currentSession.WindowHandle) || currentSession.WindowHandle == IntPtr.Zero) && retryAttempt < maxRetryAttempts) {
Logger.WriteLine($"Waiting to retrieve process handle... retry attempt #{retryAttempt}");
await Task.Delay(retryInterval);
retryAttempt++;
// alternate on retry attempts, one or the other might get us a better handle
currentSession.WindowHandle = WindowService.GetWindowHandleByProcessId(currentSession.Pid, retryAttempt % 2 == 1);
}
if (retryAttempt >= maxRetryAttempts) {
return false;
}
return true;
}

private static bool HandleManualRecord() {
if (WindowService.GetForegroundWindow(out int processId, out nint hwid)) {
if (processId != 0 || hwid != 0) {
WindowService.GetExecutablePathFromProcessId(processId, out string executablePath);
DetectionService.AutoDetectGame(processId, executablePath, hwid, autoRecord: false);
return true;
}
return false;
}
return false;
}

private static bool SetSessionDetails() {
string dir = Path.Join(GetPlaysFolder(), "/" + MakeValidFolderNameSimple(currentSession.GameTitle) + "/");
try {
Directory.CreateDirectory(dir);
}
catch (Exception e) {
WebMessage.DisplayModal(string.Format("Unable to create folder {0}. Do you have permission to create it?", dir), "Recording Error", "warning");
Logger.WriteLine(e.ToString());
return false;
}
string videoNameTimeStamp = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss");

FileFormat currentFileFormat = SettingsService.Settings.captureSettings.fileFormat ?? (new FileFormat("mp4", "MP4 (.mp4)", true));
Logger.WriteLine($"Output file format: " + currentFileFormat.ToString());
currentSession.videoSavePath = Path.Join(dir, videoNameTimeStamp + "-ses." + currentFileFormat.GetFileExtension());
return true;
}

//[STAThread]
public static async void StartRecording() {
public static async void StartRecording(bool manual) {
if (IsRecording || IsPreRecording) {
Logger.WriteLine($"Cannot start recording, already recording [{currentSession.Pid}][{currentSession.GameTitle}]");
return;
}

IsPreRecording = true;
bool result = await ActiveRecorder.StartRecording();
Logger.WriteLine("Start Success: " + result.ToString());
Logger.WriteLine("Still allowed to record: " + (!IsRecording && result).ToString());
bool result = true;

if (manual) result = HandleManualRecord();
if (result) result = await GetGoodWindowHandle();
if (result) result = SetSessionDetails();
if (result) result = await ActiveRecorder.StartRecording();
Logger.WriteLine("Start Success: " + result);
Logger.WriteLine("Still allowed to record: " + (!IsRecording && result));
if (!IsRecording && result) {
Logger.WriteLine("Current Session PID: " + currentSession.Pid.ToString());
Logger.WriteLine("Current Session PID: " + currentSession.Pid);

startTime = DateTime.Now;
recordingTimer.Elapsed += OnTimedEvent;
Expand Down Expand Up @@ -133,7 +192,9 @@ public static async void RestartRecording() {
IsRestarting = true;

bool stopResult = await ActiveRecorder.StopRecording();
bool startResult = await ActiveRecorder.StartRecording();
bool newSession = SetSessionDetails();
bool startResult = false;
if (newSession) startResult = await ActiveRecorder.StartRecording();

if (stopResult && startResult) {
Logger.WriteLine("Recording restart successful");
Expand Down
13 changes: 7 additions & 6 deletions Classes/Utils/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ public static void GetAudioDevices() {
var inputCache = SettingsService.Settings.captureSettings.inputDevicesCache;
outputCache.Clear();
inputCache.Clear();
outputCache.Add(new("default", "Default Device"));
inputCache.Add(new("default", "Default Device", false));
outputCache.Add(new("default", "Default Device", false));
inputCache.Add(new("default", "Default Device", true, false));
#if WINDOWS
outputCache.Add(new("communications", "Default Communication Device"));
inputCache.Add(new("communications", "Default Communication Device", false));
outputCache.Add(new("communications", "Default Communication Device", false));
inputCache.Add(new("communications", "Default Communication Device", true, false));
ManagementObjectSearcher searcher = new("Select * From Win32_PnPEntity");
ManagementObjectCollection deviceCollection = searcher.Get();
foreach (ManagementObject obj in deviceCollection) {
Expand All @@ -188,12 +188,13 @@ public static void GetAudioDevices() {

if (obj.Properties["PNPClass"].Value.ToString() == "AudioEndpoint") {
string id = obj.Properties["PNPDeviceID"].Value.ToString().Split('\\').Last();
AudioDevice dev = new(id, obj.Properties["Name"].Value.ToString()) {
bool isOutput = id.StartsWith("{0.0.0.00000000}");
AudioDevice dev = new(id, obj.Properties["Name"].Value.ToString(), !isOutput) {
deviceId = id.ToLower(),
deviceLabel = obj.Properties["Name"].Value.ToString(),
deviceVolume = 100
};
if (id.StartsWith("{0.0.0.00000000}")) outputCache.Add(dev);
if (isOutput) outputCache.Add(dev);
else inputCache.Add(dev);
Logger.WriteLine(dev.deviceId + " | " + dev.deviceLabel);

Expand Down
18 changes: 12 additions & 6 deletions Classes/Utils/JSONObjects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ public class Device {

public class AudioDevice {
public AudioDevice() { }
public AudioDevice(string deviceId, string deviceLabel, bool denoiser = false) {
public AudioDevice(string deviceId, string deviceLabel, bool isInput, bool denoiser = false) {
_deviceId = deviceId;
_deviceLabel = deviceLabel;
_isInput = isInput;
_denoiser = denoiser;
}
private string _deviceId = "";
Expand All @@ -100,18 +101,23 @@ public AudioDevice(string deviceId, string deviceLabel, bool denoiser = false) {
public string deviceLabel { get { return _deviceLabel; } set { _deviceLabel = value; } }
private int _deviceVolume = 100;
public int deviceVolume { get { return _deviceVolume; } set { _deviceVolume = value; } }
private bool _isInput;
public bool isInput { get { return _isInput; } set { _isInput = value; } }
private bool _denoiser;
public bool denoiser { get { return _denoiser; } set { _denoiser = value; } }
}

public class AudioApplication {
public AudioApplication() { }
public AudioApplication(string application) {
_application = application;
public AudioApplication(string name, string recordWindow) {
_name = name;
_recordWindow = recordWindow;
}

private string _application;
public string application { get { return _application; } set { _application = value; } }
private string _name;
public string name { get { return _name; } set { _name = value; } }
private string _recordWindow;
public string windowClassNameId { get { return _recordWindow; } set { _recordWindow = value; } }
private int _applicationVolume = 100;
public int applicationVolume { get { return _applicationVolume; } set { _applicationVolume = value; } }
}
Expand Down Expand Up @@ -181,7 +187,7 @@ public class CaptureSettings {
private List<AudioDevice> _outputDevices = new();
public List<AudioDevice> outputDevices { get { return _outputDevices; } set { _outputDevices = value; } }

public List<AudioApplication> _audioApplications = new();
private List<AudioApplication> _audioApplications = new();
public List<AudioApplication> audioApplications { get { return _audioApplications; } set { _audioApplications = value; } }

private bool _hasNvidiaAudioSDK;
Expand Down
2 changes: 1 addition & 1 deletion ClientApp/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ declare global {
deviceId: string;
deviceLabel: string;
deviceVolume: number;
isInput: boolean;
denoiser?: boolean;
isInput?: boolean;
}
interface FileFormat {
title: string;
Expand Down

0 comments on commit 5c6ac32

Please sign in to comment.