Skip to content

Commit

Permalink
add project
Browse files Browse the repository at this point in the history
  • Loading branch information
liz3 committed Jan 16, 2025
0 parents commit 454af65
Show file tree
Hide file tree
Showing 20 changed files with 1,551 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
Backup
.idea
.vs
VoiceLink/build
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# vVolume
A tool that adjusts the output volume of each COM channel of vPilot from the Planes radio voice control individually.

## Download and Usage
1. Download the zip from the [Releases](https://github.com/liz3/vVolume/releases/).
2. Run vVolume **as administrator**, it needs admin rights in order to be able to set the volume.

## Building
Its two c# solutions and a CMake c++ Project. Build them and then copy the VoiceLink dll into vVolume and the contents of bin/Release from vPilotAdjust into vVolume/vph
64 changes: 64 additions & 0 deletions VPilotAdjust/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Runtime;

const int PROCESS_ALL_ACCESS = 0x001F0FFF;

[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr handle);


[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten);

Process[] processes = Process.GetProcessesByName("vPilot");
if (processes.Length == 0)
{
Environment.Exit(1);
}
else
{
var value = float.Parse(args[args.Length - 1], CultureInfo.InvariantCulture.NumberFormat);
var id = int.Parse(args[args.Length - 2], CultureInfo.InvariantCulture.NumberFormat);
var targetProcess = processes[0];
byte[] data = new byte[4];

var set = false;
Buffer.BlockCopy(BitConverter.GetBytes(value), 0, data, 0, 4);
using (var dataTarget = DataTarget.AttachToProcess(targetProcess.Id, suspend: false))
{
var runtime = dataTarget.ClrVersions[0].CreateRuntime();

foreach (var enumerateObject in runtime.Heap.EnumerateObjects())
{
if (enumerateObject.ToString().EndsWith("ReceiverSampleProvider"))
{
// if (enumerateObject.ToString().EndsWith("VolumeSampleProvider"))

ushort eid = enumerateObject.ReadField<ushort>("<ID>k__BackingField");
Console.WriteLine($"{eid}");
if (eid != id)
continue;
var vol = enumerateObject.ReadObjectField("volume");
var proc = OpenProcess(PROCESS_ALL_ACCESS, false, targetProcess.Id);
WriteProcessMemory(proc, new IntPtr((long)vol.Address + 8), data, data.Length, out _);
CloseHandle(proc);
set = true;
break;
}
}

runtime.Dispose();
}

Environment.Exit(set ? 0 : 2);
}
24 changes: 24 additions & 0 deletions VPilotAdjust/VPilotAdjust.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<PlatformTarget>x86</PlatformTarget>
<Prefer32bit>true</Prefer32bit>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<PlatformTarget>x86</PlatformTarget>
<Prefer32bit>true</Prefer32bit>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" />
</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions VoiceLink/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.16)
project("VoiceLink")
set(CMAKE_CXX_STANDARD 17)

set(VL_SOURCES src/main.cc)

add_library(VoiceLink SHARED ${VL_SOURCES})
target_include_directories(VoiceLink PRIVATE third-party/SimConnect/include)
if(CMAKE_BUILD_TYPE MATCHES Debug)
target_link_libraries(VoiceLink ${CMAKE_SOURCE_DIR}/third-party/SimConnect/lib/static/SimConnect_debug.lib)
else()
target_link_libraries(VoiceLink ${CMAKE_SOURCE_DIR}/third-party/SimConnect/lib/static/SimConnect.lib)
endif()
target_link_libraries(VoiceLink ws2_32 shlwapi ole32)
155 changes: 155 additions & 0 deletions VoiceLink/src/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#include "main.h"


enum class ComState {
Failed = -1,
Ok = 0,
DoesNotExist = 1,
PoweredOff = 2,
ComFailed = 3
};

std::string comStateStr(ComState v) {
if(v == ComState::Failed)
return "FAILED";
if(v == ComState::Ok)
return "OK";
if(v == ComState::DoesNotExist)
return "DOES_NOT_EXIST";
if(v == ComState::PoweredOff)
return "OFF";
if(v == ComState::ComFailed)
return "FAILED";
return "";
}

struct State {
bool initialised = false;
bool hasData = false;
SimData data;
bool connected = false;
HANDLE hSimConnect = NULL;
};

static enum EVENT_ID{
EVENT_SIM_START,
EVENT_1_SEC
};

static enum DATA_DEFINE_ID {
DEFINITION_1,
};

static enum DATA_REQUEST_ID {
REQUEST_1,
};


State state;

bool isReceiving(ComState status, bool isReceiving, bool isAvailable) {
return status == ComState::Ok && isReceiving && isAvailable;
}


void CALLBACK MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
HRESULT hr;

switch(pData->dwID)
{

case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
{
SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;

switch(pObjData->dwRequestID)
{
case REQUEST_1:
{
DWORD ObjectID = pObjData->dwObjectID;
SimData *data = (SimData*)&pObjData->dwData;
if (SUCCEEDED(StringCbLengthA(&data->title[0], sizeof(data->title), NULL))) // security check
{
state.data = *data;
state.hasData = true;
}
break;
}

default:
break;
}
break;
}

case SIMCONNECT_RECV_ID_QUIT:
{

state.connected = false;
break;
}

default:

break;
}
}

void init() {
if(state.initialised)
return;
state.initialised = true;
CoInitialize(nullptr);
}

__declspec(dllexport) SimData getData() {
init();
return state.data;
}

__declspec(dllexport) bool hasData() {
init();
bool v = state.hasData;
state.hasData = false;
return v;
}

__declspec(dllexport) void requestData() {
SimConnect_CallDispatch(state.hSimConnect, MyDispatchProcRD, NULL);
}

__declspec(dllexport) bool connectSim() {
init();
if(state.connected)
return true;
HRESULT hr;
if(state.hSimConnect) {
hr = SimConnect_Close(state.hSimConnect);
state.hSimConnect = NULL;
}

if (SUCCEEDED(SimConnect_Open(&state.hSimConnect, "VoiceLink", NULL, 0, 0, 0))) {
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "Title", NULL, SIMCONNECT_DATATYPE_STRING256);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "ELECTRICAL MASTER BATTERY", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "AVIONICS MASTER SWITCH", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM VOLUME:1", "percent");
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM VOLUME:2", "percent");
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM STATUS:1", "enum", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM STATUS:2", "enum", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM RECEIVE:1", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM RECEIVE:2", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM AVAILABLE:1", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM AVAILABLE:2", "bool", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM ACTIVE FREQUENCY:1", "Khz", SIMCONNECT_DATATYPE_INT32);
hr = SimConnect_AddToDataDefinition(state.hSimConnect, DEFINITION_1, "COM ACTIVE FREQUENCY:2", "Khz", SIMCONNECT_DATATYPE_INT32);

hr = SimConnect_RequestDataOnSimObject(state.hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);

state.connected = true;

return true;
}
return false;
}

35 changes: 35 additions & 0 deletions VoiceLink/src/main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef VOICE_LINK_MAIN_H
#define VOICE_LINK_MAIN_H
#include <windows.h>
#include <SimConnect.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <audiopolicy.h>
#include <string>
#include <strsafe.h>
#include <tlhelp32.h>


extern "C" {
struct SimData
{
char title[256];
int bat_master;
int avionics_master;
double com1percent;
double com2percent;
int com1;
int com2;
int recvCom1;
int recvCom2;
int avCom1;
int avCom2;
uint32_t com1Freq;
uint32_t com2Freq;
};
__declspec(dllexport) bool connectSim();
__declspec(dllexport) void requestData();
__declspec(dllexport) bool hasData();
__declspec(dllexport) SimData getData();
}
#endif
Loading

0 comments on commit 454af65

Please sign in to comment.