Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GRPC.tts(...) Lua API #202

Merged
merged 3 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added DCS `time` of the update to units stream (`StreamUnitsResponse`)
- Added `GetBallisticsCount` API
- Added `TtsService/Transmit` to synthesize text to speech and transmit it over SRS
- Added `GRPC.tts(ssml, frequency[, options])` Lua API

### Changed
- Unit objects now return the full group object in the `group` field to make event processing easier. This replaces the `group_name` and `group_category` fields and is a backwards incompatible change.
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,45 @@ You can also check for the present of a `\Logs\grpc.log` file.

The server will be running on port 50051 by default.

## Lua API

`DCS-gRPC` provides the following Lua APIs to interact with the server from within Lua.

- `GRPC.tts(ssml, frequency[, options])` - Synthesize text (`ssml`; SSML tags supported) to speech and transmit it over SRS on the `frequency` with the following optional `options` (and their defaults):
```lua
{
-- The plain text without any transformations made to it for the purpose of getting it spoken out
-- as desired (no SSML tags, no FOUR NINER instead of 49, ...). Even though this field is
-- optional, please consider providing it as it can be used to display the spoken text to players
-- with hearing impairments.
plaintext = null, -- e.g. `= "Hello Pilot"`

-- Name of the SRS client.
srsClientName = "DCS-gRPC",

-- The origin of the transmission. Relevant if the SRS server has "Line of
-- Sight" and/or "Distance Limit" enabled.
position = {
lat = 0.0,
lon = 0.0,
alt = 0.0, -- in meters
},

-- The coalition of the transmission. Relevant if the SRS server has "Secure
-- Coalition Radios" enabled. Supported values are: `blue` and `red`. Defaults
-- to being spectator if not specified.
coalition = null,

-- TTS provider to be use. Defaults to the one configured in your config or to Windows'
-- built-in TTS. Examples:
-- `= { aws = {} }` / `= { aws = { voice = "..." } }` enable AWS TTS
-- `= { azure = {} }` / `= { azure = { voice = "..." } }` enable Azure TTS
-- `= { gcloud = {} }` / `= { gcloud = { voice = "..." } }` enable Google Cloud TTS
-- `= { win = {} }` / `= { win = { voice = "..." } }` enable Windows TTS
provider = null,
}
```

## Client Development

`DCS-gRPC`, as the name implies, uses the [gRPC](https://grpc.io/) framework to handle communication between clients
Expand Down
5 changes: 5 additions & 0 deletions lua/DCS-gRPC/grpc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ GRPC.error = function(msg)
}
end

--
-- APIs exposed to Lua
--
GRPC.tts = grpc.tts

--
-- Logging methods
--
Expand Down
6 changes: 3 additions & 3 deletions protos/dcs/atmosphere/v0/atmosphere.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ message GetWindRequest {
// The position on the map we want the wind information for.
// Requires lat/lon/alt fields to be populated, there are
// no default values
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
}

message GetWindResponse {
Expand All @@ -36,7 +36,7 @@ message GetWindWithTurbulenceRequest {
// The position on the map we want the wind information for.
// Requires lat/lon/alt fields to be populated, there are
// no default values
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
}

message GetWindWithTurbulenceResponse {
Expand All @@ -50,7 +50,7 @@ message GetTemperatureAndPressureRequest {
// The position on the map we want the wind information for.
// Requires lat/lon/alt fields to be populated, there are
// no default values
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
}

message GetTemperatureAndPressureResponse {
Expand Down
8 changes: 4 additions & 4 deletions protos/dcs/coalition/v0/coalition.proto
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ message AddGroupRequest {
bool hidden = 2;
bool late_activation = 3;
string name = 4;
dcs.common.v0.Position position = 5;
dcs.common.v0.InputPosition position = 5;
repeated Point waypoints = 6;
uint32 start_time = 7;
string task = 8;
Expand All @@ -71,7 +71,7 @@ message AddGroupRequest {
message GroundUnitTemplate {
string name = 1;
string type = 2;
dcs.common.v0.Position position = 3;
dcs.common.v0.InputPosition position = 3;
optional uint32 unit_id = 4;
optional uint32 heading = 5;
Skill skill = 6;
Expand Down Expand Up @@ -109,7 +109,7 @@ message AddGroupRequest {
POINT_TYPE_LAND = 5;
}

dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
AltitudeType altitude_type = 2;
PointType type = 3;
string action = 4;
Expand Down Expand Up @@ -160,7 +160,7 @@ message AddStaticObjectRequest {
optional uint32 rate = 6;

double heading = 7;
dcs.common.v0.Position position = 8;
dcs.common.v0.InputPosition position = 8;
// cargo mass in kilograms
uint32 cargo_mass = 9;
}
Expand Down
18 changes: 18 additions & 0 deletions protos/dcs/common/v0/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,24 @@ message Position {
double v = 5;
}

/**
* Position used in requests to DCS-gRPC.
*
* Latitude and Longitude are in Decimal Degrees format (e.g. 41.33 / 37.21).
* Negative values are used for West of the meridian and south of the equator.
*
* Altitude is given in meters above Mean Sea Level (MSL) and can be a decimal
* value.
*/
message InputPosition {
// Latitude in Decimal Degrees format
double lat = 1;
// Longitude in Decimal Degrees format
double lon = 2;
// Altitude in Meters above Mean Sea Level (MSL)
double alt = 3;
}

/**
* This type is returned if an object category cannot be determined
*
Expand Down
18 changes: 9 additions & 9 deletions protos/dcs/trigger/v0/trigger.proto
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ message SetUserFlagResponse {

message MarkToAllRequest {
string text = 2;
dcs.common.v0.Position position = 3;
dcs.common.v0.InputPosition position = 3;
bool read_only = 4;
string message = 5;
}
Expand All @@ -131,7 +131,7 @@ message MarkToAllResponse {
message MarkToCoalitionRequest {
uint32 id = 1;
string text = 2;
dcs.common.v0.Position position = 3;
dcs.common.v0.InputPosition position = 3;
dcs.common.v0.Coalition coalition = 4;
bool read_only = 5;
string message = 6;
Expand All @@ -144,7 +144,7 @@ message MarkToCoalitionResponse {
message MarkToGroupRequest {
uint32 id = 1;
string text = 2;
dcs.common.v0.Position position = 3;
dcs.common.v0.InputPosition position = 3;
uint32 group_id = 4;
bool read_only = 5;
string message = 6;
Expand All @@ -162,7 +162,7 @@ message RemoveMarkResponse {
}

message ExplosionRequest {
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
uint32 power = 2;
}

Expand All @@ -181,7 +181,7 @@ message SmokeRequest {

// Altitude parameter will be ignored. Smoke always eminates from ground
// level which will be calculated server-side
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
SmokeColor color = 2;
}

Expand All @@ -191,7 +191,7 @@ message SmokeResponse {
message IlluminationBombRequest {
// The altitude of Illumination Bombs is meters above ground. Ground level
// will be calculated server-side
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
uint32 power = 2;
}

Expand All @@ -209,7 +209,7 @@ message SignalFlareRequest {

// Altitude parameter will be ignored. Signal flares always fire from
// ground level which will be calculated server-side
dcs.common.v0.Position position = 1;
dcs.common.v0.InputPosition position = 1;
FlareColor color = 2;
uint32 azimuth = 3;
}
Expand Down Expand Up @@ -251,7 +251,7 @@ enum Shape {

message MarkupToAllRequest {
Shape shape = 1;
repeated dcs.common.v0.Position points = 2;
repeated dcs.common.v0.InputPosition points = 2;
Color border_color = 3;
Color fill_color = 4;
LineType line_type = 5;
Expand All @@ -266,7 +266,7 @@ message MarkupToAllResponse {
message MarkupToCoalitionRequest {
Shape shape = 1;
dcs.common.v0.Coalition coalition = 2;
repeated dcs.common.v0.Position points = 3;
repeated dcs.common.v0.InputPosition points = 3;
Color border_color = 4;
Color fill_color = 5;
LineType line_type = 6;
Expand Down
4 changes: 2 additions & 2 deletions protos/dcs/tts/v0/tts.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ message TransmitRequest {

// The origin of the transmission. Relevant if the SRS server has "Line of
// Sight" and/or "Distance Limit" enabled.
dcs.common.v0.Position position = 5;
dcs.common.v0.InputPosition position = 5;

// The coalition of the transmission. Relevant if the SRS server has "Secure
// Coalition Radios" enabled. Only Blue and Red are supported, all other
// values will fallback to Blue.
// values will fallback to Spectator.
dcs.common.v0.Coalition coalition = 6;

// Whether to keep the request open until the whole transmission was sent. If
Expand Down
13 changes: 13 additions & 0 deletions src/hot_reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use std::{error, fmt};

use crate::server::TtsOptions;
use crate::Config;
use libloading::{Library, Symbol};
use mlua::prelude::*;
Expand Down Expand Up @@ -59,6 +60,18 @@ pub fn next(lua: &Lua, arg: (i32, Function)) -> LuaResult<bool> {
}
}

pub fn tts(lua: &Lua, arg: (String, u64, Option<TtsOptions>)) -> LuaResult<()> {
if let Some(ref lib) = *LIBRARY.read().unwrap() {
let f: Symbol<fn(lua: &Lua, arg: (String, u64, Option<TtsOptions>)) -> LuaResult<()>> = unsafe {
lib.get(b"tts")
.map_err(|err| mlua::Error::ExternalError(Arc::new(err)))?
};
f(lua, arg).map_err(take_error_ownership)
} else {
Ok(())
}
}

pub fn event(lua: &Lua, event: Value) -> LuaResult<()> {
if let Some(ref lib) = *LIBRARY.read().unwrap() {
let f: Symbol<fn(lua: &Lua, event: Value) -> LuaResult<()>> = unsafe {
Expand Down
15 changes: 14 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use config::Config;
use mlua::{prelude::*, LuaSerdeExt};
use mlua::{Function, Value};
use once_cell::sync::Lazy;
use server::Server;
use server::{Server, TtsOptions};
use stubs::mission::v0::StreamEventsResponse;
use thiserror::Error;

Expand Down Expand Up @@ -167,6 +167,17 @@ pub fn next(lua: &Lua, (env, callback): (i32, Function)) -> LuaResult<bool> {
Ok(false)
}

#[no_mangle]
pub fn tts(_lua: &Lua, (ssml, freq, opts): (String, u64, Option<TtsOptions>)) -> LuaResult<()> {
let start = Instant::now();
if let Some(server) = &*SERVER.read().unwrap() {
let _guard = server.stats().track_block_time(start);
server.tts(ssml, freq, opts);
}

Ok(())
}

#[no_mangle]
pub fn event(lua: &Lua, event: Value) -> LuaResult<()> {
let start = Instant::now();
Expand Down Expand Up @@ -253,6 +264,7 @@ pub fn dcs_grpc_hot_reload(lua: &Lua) -> LuaResult<LuaTable> {
"simulationFrame",
lua.create_function(hot_reload::simulation_frame)?,
)?;
exports.set("tts", lua.create_function(hot_reload::tts)?)?;
exports.set("logError", lua.create_function(hot_reload::log_error)?)?;
exports.set("logWarning", lua.create_function(hot_reload::log_warning)?)?;
exports.set("logInfo", lua.create_function(hot_reload::log_info)?)?;
Expand All @@ -269,6 +281,7 @@ pub fn dcs_grpc(lua: &Lua) -> LuaResult<LuaTable> {
exports.set("next", lua.create_function(next)?)?;
exports.set("event", lua.create_function(event)?)?;
exports.set("simulationFrame", lua.create_function(simulation_frame)?)?;
exports.set("tts", lua.create_function(tts)?)?;
exports.set("logError", lua.create_function(log_error)?)?;
exports.set("logWarning", lua.create_function(log_warning)?)?;
exports.set("logInfo", lua.create_function(log_info)?)?;
Expand Down
Loading