9 Commits

Author SHA1 Message Date
c73614133d add link to CHANGELOG in README 2024-06-28 06:56:45 +01:00
2bdabdae03 host now defaults to "localhost"
loglevel flag now uses logrus constants (0 up to 6)

config values are only applied if the corresponding flag wasn't passed
isFlagPassed() added to util.go
2024-06-28 06:55:53 +01:00
31b188280d CHANGELOG added 2024-06-28 06:51:23 +01:00
ccf34e492d Added link to Matrix.
Added some details regarding command line flags.

Matrix, Logging sections added
2024-06-28 06:51:10 +01:00
onyx-and-iris
56ce415d6d typo fix 2022-11-06 07:47:25 +00:00
onyx-and-iris
cfd89fb1ed update readme 2022-11-06 07:37:30 +00:00
onyx-and-iris
73a99e5059 alter port in readme toml example 2022-11-05 19:33:26 +00:00
onyx-and-iris
6221f6a167 add os badges 2022-11-05 19:27:16 +00:00
onyx-and-iris
826df820fc adjust readme header 2022-11-05 19:05:38 +00:00
4 changed files with 127 additions and 56 deletions

31
CHANGELOG.md Normal file
View File

@@ -0,0 +1,31 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Before any major/minor/patch bump all unit tests will be run to verify they pass.
## [Unreleased]
- [x]
# [0.1.0] - 2024-06-28
### Added
- Matrix and Logging sections to README.
### Changed
- `host` flag now defaults to "localhost". Useful if sending VBAN-Text to Matrix
- `loglevel` flag now expects values that correspond to the logrus package loglevels (0 up to 6). See README.
- Config values are only applied if the corresponding flag was not passed on the command line.
# [0.0.1] - 2022-09-23
### Added
- Initial release, package implements VBAN PROTOCOL TXT with a basic CLI for configuring options.
- Ability to load configuration settings from a config.toml.

View File

@@ -1,25 +1,33 @@
# vbantxt ![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white)
![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black)
VBAN sendtext cli utility for sending Voicemeeter string requests over a network. # VBAN Sendtext CLI Utility
Send Voicemeeter string requests over a network or to Matrix
For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
## Tested against ## Tested against
- Basic 1.0.8.4 - Basic 1.0.8.4
- Banana 2.0.6.4 - Banana 2.0.6.4
- Potato 3.0.2.4 - Potato 3.0.2.4
- Matrix 1.0.0.3
## Requirements ## Requirements
- [Voicemeeter](https://voicemeeter.com/) - [Voicemeeter](https://voicemeeter.com/) or [Matrix](https://vb-audio.com/Matrix/)
- Go 1.18 or greater - Go 1.18 or greater (if you want to compile yourself, otherwise check `Releases`)
## `Use` ---
#### Command Line ## `Command Line`
Pass `host`, `port` and `streamname` as flags, for example: Pass `host`, `port` and `streamname` as flags, for example:
`vbantxt-cli -h="gamepc.local" -p=6980 -s=Command1 "strip[0].mute=1 strip[1].mono=1"` ```
vbantxt-cli -h="gamepc.local" -p=6980 -s=Command1 "strip[0].mute=1 strip[1].mono=1"
```
You may also store them in a `config.toml` located in `home directory / .vbantxt_cli /` You may also store them in a `config.toml` located in `home directory / .vbantxt_cli /`
@@ -28,11 +36,19 @@ A valid `config.toml` might look like this:
```toml ```toml
[connection] [connection]
Host="gamepc.local" Host="gamepc.local"
Port=6990 Port=6980
Streamname="Command1" Streamname="Command1"
``` ```
#### Script files - `host` defaults to "localhost"
- `port` defaults to 6980
- `streamname` defaults to "Command1"
Command line flags will override values in a config.toml.
---
## `Script files`
The vbantxt-cli utility accepts a single string request or an array of string requests. This means you can pass scripts stored in files. The vbantxt-cli utility accepts a single string request or an array of string requests. This means you can pass scripts stored in files.
@@ -40,9 +56,34 @@ For example, in Windows with Powershell you could:
`vbantxt-cli $(Get-Content .\script.txt)` `vbantxt-cli $(Get-Content .\script.txt)`
Or with Bash:
`cat script.txt | xargs vbantxt-cli`
to load commands from a file: to load commands from a file:
``` ```
strip[0].mute=0;strip[0].mute=0 strip[0].mute=1;strip[0].mono=0
strip[1].mono=0;strip[1].mono=0 strip[1].mute=0;strip[1].mono=1
bus[3].eq.On=0
``` ```
---
## `Matrix`
Sending commands to VB-Audio Matrix is also possible, for example:
```
vbantxt-cli -s=streamname "Point(ASIO128.IN[2],ASIO128.OUT[1]).dBGain = -8"
```
---
## `Logging`
Log level may be set by passing the `-l` flag with a number from 0 up to 6 where
0 = Panic, 1 = Fatal, 2 = Error, 3 = Warning, 4 = Info, 5 = Debug, 6 = Trace
Log level defaults to Warning level.

71
main.go
View File

@@ -3,7 +3,6 @@ package main
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"flag" "flag"
"fmt" "fmt"
"net" "net"
@@ -44,20 +43,9 @@ type (
} }
) )
func setLogLevel(loglevel int) {
switch loglevel {
case 0:
log.SetLevel(log.WarnLevel)
case 1:
log.SetLevel(log.InfoLevel)
case 2:
log.SetLevel(log.DebugLevel)
}
}
func main() { func main() {
flag.StringVar(&host, "host", "", "vban host") flag.StringVar(&host, "host", "localhost", "vban host")
flag.StringVar(&host, "h", "", "vban host (shorthand)") flag.StringVar(&host, "h", "localhost", "vban host (shorthand)")
flag.IntVar(&port, "port", 6980, "vban server port") flag.IntVar(&port, "port", 6980, "vban server port")
flag.IntVar(&port, "p", 6980, "vban server port (shorthand)") flag.IntVar(&port, "p", 6980, "vban server port (shorthand)")
flag.StringVar(&streamname, "streamname", "Command1", "stream name for text requests") flag.StringVar(&streamname, "streamname", "Command1", "stream name for text requests")
@@ -68,11 +56,13 @@ func main() {
flag.IntVar(&channel, "c", 0, "vban channel (shorthand)") flag.IntVar(&channel, "c", 0, "vban channel (shorthand)")
flag.IntVar(&delay, "delay", 20, "delay between requests") flag.IntVar(&delay, "delay", 20, "delay between requests")
flag.IntVar(&delay, "d", 20, "delay between requests (shorthand)") flag.IntVar(&delay, "d", 20, "delay between requests (shorthand)")
flag.IntVar(&loglevel, "loglevel", 0, "log level") flag.IntVar(&loglevel, "loglevel", int(log.WarnLevel), "log level")
flag.IntVar(&loglevel, "l", 0, "log level (shorthand)") flag.IntVar(&loglevel, "l", int(log.WarnLevel), "log level (shorthand)")
flag.Parse() flag.Parse()
setLogLevel(loglevel) if loglevel >= int(log.PanicLevel) && loglevel <= int(log.TraceLevel) {
log.SetLevel(log.Level(loglevel))
}
c, err := vbanConnect() c, err := vbanConnect()
if err != nil { if err != nil {
@@ -84,52 +74,49 @@ func main() {
for _, arg := range flag.Args() { for _, arg := range flag.Args() {
err := send(c, header, arg) err := send(c, header, arg)
if err != nil { if err != nil {
log.Error(err) log.Error(err.Error())
} }
} }
} }
// vbanConnect establishes a VBAN connection to remote host // vbanConnect establishes a VBAN connection to remote host
func vbanConnect() (*net.UDPConn, error) { func vbanConnect() (*net.UDPConn, error) {
if host == "" { homeDir, err := os.UserHomeDir()
conn, err := connFromToml() if err != nil {
return nil, err
}
f := filepath.Join(homeDir, ".vbantxt_cli", "config.toml")
if _, err := os.Stat(f); err == nil {
conn, err := connFromToml(f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host = conn.Host if !isFlagPassed("h") && !isFlagPassed("host") {
port = conn.Port host = conn.Host
streamname = conn.Streamname }
if host == "" { if !isFlagPassed("p") && !isFlagPassed("port") {
err := errors.New("must provide a host with --host flag or config.toml") port = conn.Port
return nil, err }
if !isFlagPassed("s") && !isFlagPassed("streamname") {
streamname = conn.Streamname
} }
} }
CONNECT := fmt.Sprintf("%s:%d", host, port) log.Debugf("Using values host: %s port: %d streamname: %s", host, port, streamname)
s, _ := net.ResolveUDPAddr("udp4", CONNECT) s, _ := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", host, port))
c, err := net.DialUDP("udp4", nil, s) c, err := net.DialUDP("udp4", nil, s)
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Info("Connected to ", c.RemoteAddr().String()) log.Infof("Connected to %s", c.RemoteAddr())
return c, nil return c, nil
} }
// connFromToml parses connection info from config.toml // connFromToml parses connection info from config.toml
func connFromToml() (*connection, error) { func connFromToml(f string) (*connection, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
f := filepath.Join(homeDir, ".vbantxt_cli", "config.toml")
if _, err := os.Stat(f); err != nil {
err := fmt.Errorf("unable to locate %s", f)
return nil, err
}
var c config var c config
_, err = toml.DecodeFile(f, &c.Connection) _, err := toml.DecodeFile(f, &c.Connection)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -139,7 +126,7 @@ func connFromToml() (*connection, error) {
// send sends a VBAN text request over UDP to remote host // send sends a VBAN text request over UDP to remote host
func send(c *net.UDPConn, h *requestHeader, msg string) error { func send(c *net.UDPConn, h *requestHeader, msg string) error {
log.Debug("Sending '", msg, "' to: ", c.RemoteAddr().String()) log.Debugf("Sending '%s' to: %s", msg, c.RemoteAddr())
data := []byte(msg) data := []byte(msg)
_, err := c.Write(append(h.header(), data...)) _, err := c.Write(append(h.header(), data...))
if err != nil { if err != nil {

12
util.go
View File

@@ -1,5 +1,7 @@
package main package main
import "flag"
// indexOf returns the index of an element in an array // indexOf returns the index of an element in an array
func indexOf[T comparable](collection []T, e T) int { func indexOf[T comparable](collection []T, e T) int {
for i, x := range collection { for i, x := range collection {
@@ -9,3 +11,13 @@ func indexOf[T comparable](collection []T, e T) int {
} }
return -1 return -1
} }
func isFlagPassed(name string) bool {
found := false
flag.Visit(func(f *flag.Flag) {
if f.Name == name {
found = true
}
})
return found
}