Skip to content

Commit

Permalink
create polling rate packts (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
Danil0v3s authored Dec 30, 2024
1 parent 6383004 commit 47fddeb
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public enum MonitorPacketCommand : short
RefreshPresentMonApps = 1,
SelectPresentMonApp = 2,
PresentMonApps = 3,
SelectPollingRate = 4
}
18 changes: 16 additions & 2 deletions HardwareMonitor/HardwareMonitor/Monitor/MonitorPoller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ ILogger<MonitorPoller> logger

private SocketHost _socketHost = new(logger);
private readonly PresentMonPoller _presentMonPoller = new(logger);

private short _pollingRate = 500;
private const short MinimalPollingRate = 50;

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Expand All @@ -36,6 +39,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
_computer.Open();
_computer.Accept(new UpdateVisitor());
_presentMonPoller.Start(stoppingToken);
_presentMonPoller.onUpdateApps += SendPresentMonAppsToClients;
_socketHost.StartServer();
_socketHost.onClientData += OnClientData;
_socketHost.onClientConnected += OnClientConnected;
Expand Down Expand Up @@ -100,11 +104,10 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
GC.Collect();
accumulator = 0;
SendPresentMonAppsToClients();
}

accumulator += 500;
await Task.Delay(500, stoppingToken);
await Task.Delay(_pollingRate, stoppingToken);
}

Stop();
Expand All @@ -128,6 +131,9 @@ private void OnClientData(byte[] data)
case MonitorPacketCommand.SelectPresentMonApp:
SelectPresentMonApp(data);
break;
case MonitorPacketCommand.SelectPollingRate:
SelectPollingRate(data);
break;

// server -> client cases
case MonitorPacketCommand.Data:
Expand All @@ -138,6 +144,14 @@ private void OnClientData(byte[] data)
}
}

private void SelectPollingRate(byte[] data)
{
// start at 2 because the first 2 were the command
var pollingRate = BitConverter.ToInt16(data, 2);
_pollingRate = Math.Max(pollingRate, MinimalPollingRate);
logger.LogInformation("Selected polling rate of {PollingRate}", _pollingRate);
}

private void SelectPresentMonApp(byte[] data)
{
// start at 2 because the first 2 were the command
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ public class PresentMonPoller(ILogger logger)
public PresentMonSensor Frametime { get; private set; }

Check warning on line 15 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Frametime' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public HashSet<string> CurrentApps { get; private set; }

Check warning on line 16 in HardwareMonitor/HardwareMonitor/PresentMon/PresentMonPoller.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'CurrentApps' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

public Action onUpdateApps;

private Process _process;
private CultureInfo _cultureInfo = (CultureInfo)CultureInfo.CurrentCulture.Clone();

private string _currentSelectedApp = NO_SELECTED_APP;


public async void Start(CancellationToken stoppingToken)
{
_cultureInfo.NumberFormat.NumberDecimalSeparator = ".";
Expand Down Expand Up @@ -105,6 +106,7 @@ public void SetSelectedApp(string appName)
}
_currentSelectedApp = appName;
}

private async Task TerminateCurrentPresentMon()
{
var processStartInfo = new ProcessStartInfo
Expand All @@ -128,6 +130,7 @@ private async Task ClearCurrentAppsAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested) return;
await Task.Delay(10_000, cancellationToken);
onUpdateApps?.Invoke();
CurrentApps.Clear();
ClearCurrentAppsAsync(cancellationToken);
}
Expand Down
25 changes: 7 additions & 18 deletions HardwareMonitor/HardwareMonitor/Sockets/SocketHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,28 +61,17 @@ public void SendToAll(byte[] memoryStream)
{
var listWithSize = memoryStream.ToList();
listWithSize.InsertRange(2, BitConverter.GetBytes(listWithSize.Count - 2));
for (var i = 0; i < _clients.Count; i++)
foreach (var client in _clients)
{
if (_clients[i].IsConnected())
try
{
_clients[i].SendAsync(listWithSize.ToArray(), SocketFlags.None);
client.SendAsync(listWithSize.ToArray(), SocketFlags.None);
}
catch (SocketException)
{
continue;
}
}
listWithSize.Clear();
}
}

static class SocketExtensions
{
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException)
{
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ enum class Command(val value: Short) {
Data(0),
RefreshPresentMonApps(1),
SelectPresentMonApp(2),
PresentMonApps(3);
PresentMonApps(3),
SelectPollingRate(4),
;

companion object {
fun fromValue(value: Short) = entries.find { it.value == value } ?: Data
Expand Down Expand Up @@ -53,6 +55,7 @@ object HardwareMonitorReader {
}

is Packet.SelectPresentMonApp -> null
is Packet.SelectPollingRate -> null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,37 @@ private const val COMMAND_SIZE = 2
private const val LENGTH_SIZE = 4

sealed class Packet {
open fun toByteArray(): ByteArray = ByteArray(0)

data class Data(val data: ByteArray) : Packet()
data class PresentMonApps(val data: ByteArray) : Packet()
data class SelectPresentMonApp(val name: String) : Packet()
data class SelectPresentMonApp(val name: String) : Packet() {
override fun toByteArray(): ByteArray {
val nameBytes = name.toByteArray()
val buffer = ByteBuffer.allocate(2 + 2 + nameBytes.count()).order(ByteOrder.LITTLE_ENDIAN).apply {
putShort(Command.SelectPresentMonApp.value)
putShort(nameBytes.size.toShort())
put(nameBytes)
}.array()
return buffer
}
}

data class SelectPollingRate(val interval: Short) : Packet() {
override fun toByteArray(): ByteArray {
val buffer = ByteBuffer.allocate(2 + 2).order(ByteOrder.LITTLE_ENDIAN).apply {
putShort(Command.SelectPollingRate.value)
putShort(interval)
}.array()
return buffer
}
}
}

object SocketClient {

private var socket = Socket()
private var pollingRate = 500L

private val packetChannel = Channel<Packet>(Channel.CONFLATED)
val packetFlow: Flow<Packet> = packetChannel.receiveAsFlow()
Expand All @@ -46,17 +69,17 @@ object SocketClient {
println("Connected ${socket.isConnected}")
} catch (ex: Exception) {
println("Couldn't connect ${ex.message}")
// if (ex !is SocketException) {
if (ex !is SocketException) {
ex.printStackTrace()
// }
}
} finally {
delay(500)
delay(pollingRate)
continue
}
}

val inputStream = socket.inputStream
while(socket.isConnected) {
while (socket.isConnected) {
try {
val command = getCommand(inputStream)
val size = getSize(inputStream)
Expand All @@ -65,6 +88,7 @@ object SocketClient {
Command.PresentMonApps -> packetChannel.trySend(Packet.PresentMonApps(inputStream.readNBytes(size)))
Command.RefreshPresentMonApps -> Unit
Command.SelectPresentMonApp -> Unit
Command.SelectPollingRate -> Unit
}
} catch (e: SocketException) {
socket.close()
Expand All @@ -85,17 +109,15 @@ object SocketClient {
return buffer.int
}

fun sendPacket(selectPresentMonApp: Packet.SelectPresentMonApp) {
fun setPollingRate(pollingRate: Long) {
println("Setting PollingRate to $pollingRate")
this.pollingRate = pollingRate
}

fun sendPacket(packet: Packet) {
if (socket.isConnected) {
val nameBytes = selectPresentMonApp.name.toByteArray()
val buffer = ByteBuffer.allocate(2 + 2 + nameBytes.count()).order(ByteOrder.LITTLE_ENDIAN).apply {
putShort(Command.SelectPresentMonApp.value)
putShort(nameBytes.size.toShort())
put(nameBytes)
}.array()
println("Sending ${buffer.count()} bytes")
socket.outputStream.apply {
write(buffer)
write(packet.toByteArray())
flush()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ data class OverlaySettings(
val positionY: Int = 0,
val isPositionLocked: Boolean = true,
val opacity: Float = 1f,
val pollingRate: Long = 500,
val sensors: Sensors = Sensors(),
) {
@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
Expand Down Expand Up @@ -46,6 +47,7 @@ sealed class SettingsEvent {
data class DarkThemeToggle(val isEnabled: Boolean) : SettingsEvent()
data class FpsApplicationSelect(val applicationName: String) : SettingsEvent()
data class BoundarySet(val sensorType: SensorType, val boundaries: OverlaySettings.Sensor.GraphSensor.Boundaries) : SettingsEvent()
data class PollingRateSelect(val pollingRate: Long) : SettingsEvent()
data object ConsentGiven : SettingsEvent()
}

Expand All @@ -62,6 +64,7 @@ class SettingsViewModel : ViewModel() {
observeData()
observeRecordingHotkey()
observeRecordingState()
sendInitialPollingRate()

_state.update {
it.copy(
Expand Down Expand Up @@ -125,6 +128,18 @@ class SettingsViewModel : ViewModel() {
}
}

private fun sendInitialPollingRate() {
CoroutineScope(Dispatchers.IO).launch {
// wait for first item
HardwareMonitorReader.currentData.first()

_state.value.overlaySettings?.let {
SocketClient.setPollingRate(it.pollingRate)
SocketClient.sendPacket(Packet.SelectPollingRate(it.pollingRate.toShort()))
}
}
}

fun onEvent(event: SettingsEvent) = with(_state.value) {
when (event) {
is SettingsEvent.OptionsToggle -> onOptionsToggle(event.data, this)
Expand All @@ -141,9 +156,21 @@ class SettingsViewModel : ViewModel() {
is SettingsEvent.FpsApplicationSelect -> onFpsApplicationSelect(event.applicationName, this)
is SettingsEvent.BoundarySet -> onBoundarySet(event.sensorType, event.boundaries, this)
is SettingsEvent.ConsentGiven -> onConsentGiven()
is SettingsEvent.PollingRateSelect -> onPollingRateSelect(event.pollingRate, this)
}
}

private fun onPollingRateSelect(pollingRate: Long, settingsState: SettingsState) {
if (settingsState.overlaySettings == null) return

val newSettings = settingsState.overlaySettings.copy(pollingRate = pollingRate)

SocketClient.setPollingRate(pollingRate)
SocketClient.sendPacket(Packet.SelectPollingRate(pollingRate.toShort()))

OverlaySettingsRepository.setOverlaySettings(newSettings)
}

private fun onConsentGiven() {
PreferencesRepository.setPreferenceBoolean(PREFERENCE_PERMISSION_CONSENT, true)
_state.update { it.copy(adminConsent = true) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import app.cleanmeter.target.desktop.data.PreferencesRepository
import app.cleanmeter.target.desktop.model.OverlaySettings
import app.cleanmeter.target.desktop.ui.components.CheckboxWithLabel
import app.cleanmeter.target.desktop.ui.components.StyleCard
import app.cleanmeter.target.desktop.ui.components.dropdown.DropdownMenu
import app.cleanmeter.target.desktop.ui.components.section.Section
import app.cleanmeter.target.desktop.ui.settings.FooterUi
import app.cleanmeter.target.desktop.ui.settings.SettingsEvent
Expand Down Expand Up @@ -102,6 +103,18 @@ fun AppSettingsUi(
}
}

Section(title = "RECORDING") {
val options = listOf("50", "100", "250", "300", "350", "400", "500")
DropdownMenu(
label = "Polling Rate:",
disclaimer = "The interval in milliseconds the app will update data. Be mindful, this can impact performance!",
options = options,
selectedIndex = options.indexOf(overlaySettings.pollingRate.toString()),
onValueChanged = { onEvent(SettingsEvent.PollingRateSelect(options[it].toLong())) },
modifier = Modifier.padding(top = 8.dp)
)
}

FooterUi(modifier = Modifier)
}

Expand Down

0 comments on commit 47fddeb

Please sign in to comment.