Skip to content

Commit

Permalink
Merge branch 'devmidi'
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmoreno committed Oct 12, 2024
2 parents 78749d5 + 76f8767 commit 8253e1b
Show file tree
Hide file tree
Showing 26 changed files with 882 additions and 49 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ clean:
rm -rf debian/librtpmidid0
rm -rf debian/librtpmidid0-dev

VALGRINDFLAGS := --leak-check=full --error-exitcode=1
VALGRINDFLAGS := --leak-check=full --error-exitcode=1 --num-callers=30 --track-origins=yes
RTPMIDID_ARGS := --ini default.ini --port ${PORT} --name devel --control /tmp/rtpmidid.sock

.PHONY: run run-valgrind run-gdb
run: build-dev
build/src/rtpmidid $(RTPMIDID_ARGS)

run-gdb: build-dev
gdb build/src/rtpmidid -ex=r --args build/src/rtpmidid $(RTPMIDID_ARGS)
gdb build/src/rtpmidid -ex=r --command=scripts/malloc.gdb --args build/src/rtpmidid $(RTPMIDID_ARGS)

run-valgrind: build-dev
valgrind --leak-check=full --show-leak-kinds=all --log-file=/tmp/rtpmidid.valgrind.log -- build/src/rtpmidid $(RTPMIDID_ARGS) || true
Expand Down
97 changes: 91 additions & 6 deletions cli/rtpmidid-cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ def __init__(self, conn: Connection):
"command": self.command_expand_peers,
"help": "Toggle expand peers",
},
{
"key": "n",
"command": self.command_new_peer,
"help": "Create new peer",
},
{"key": "tab", "command": self.command_switch_tab, "help": "Switch tabs"},
]

Expand Down Expand Up @@ -293,13 +298,11 @@ def command_quit(self):
sys.exit(0)

def command_kill(self):
data = self.status["router"]
current_id = data[self.selected_row_index]["id"]
current_id = self.current_row["id"]
self.conn.command({"method": "router.remove", "params": [current_id]})

def command_connect(self):
data = self.status["router"]
current_id = data[self.selected_row_index]["id"]
current_id = self.current_row["id"]
peer_id = self.dialog_ask("Connect to which peer id?")
if not peer_id:
return
Expand All @@ -314,6 +317,25 @@ def command_connect(self):
def command_expand_peers(self):
self.expand_peers = not self.expand_peers

def command_new_peer(self):
data = self.conn.command(
{"method": "router.create", "params": {"type": "list"}}
)

name = self.dialog_select("Type of peer", list(data["result"].keys()))
if not name:
return
params = {"type": name}
for key, description in data["result"][name].items():
value = self.dialog_ask(description)
if value is None:
return
params[key] = value

ret = self.conn.command({"method": "router.create", "params": params})
if "error" in ret:
self.dialog(ret["error"], background=self.ANSI_BG_RED)

def command_switch_tab(self):
if self.tab == self.Tabs.ROUTES:
self.tab = self.Tabs.MDNS
Expand Down Expand Up @@ -376,13 +398,16 @@ def print_square(self, x, y, width, height, color):
self.print(" " * width)
self.print(self.ANSI_RESET)

def dialog(self, text, bottom="Press any key", wait_for_key=True):
def dialog(self, text, bottom="Press any key", wait_for_key=True, background=None):
width = max(len(x) for x in text.split("\n")) + 2
width_2 = width // 2
start_x = self.width // 2 - width_2
start_y = self.height // 3

self.print(self.ANSI_BG_PURPLE + self.ANSI_TEXT_WHITE + self.ANSI_TEXT_BOLD)
if not background:
background = self.ANSI_BG_PURPLE

self.print(background + self.ANSI_TEXT_WHITE + self.ANSI_TEXT_BOLD)
self.terminal_goto(start_x, start_y)
# self.print_padding("", width)
# top border, width, using unicode table characters
Expand Down Expand Up @@ -456,6 +481,66 @@ def dialog_ask(self, question, width=60):

return answer

def dialog_select(self, title: str, options: list[str]):
width = max(len(x) for x in options) + 2
if width < len(title) + 2:
width = len(title) + 2
if width < 20:
width = 20
width_2 = width // 2
start_x = self.width // 2 - width_2
start_y = self.height // 3

selected = 0

def print_select():
# borders and title, then the list with bakc background and selected on white
self.print(self.ANSI_BG_BLUE + self.ANSI_TEXT_WHITE + self.ANSI_TEXT_BOLD)
self.terminal_goto(start_x, start_y)
self.print_padding("", width)
self.terminal_goto(start_x, start_y + 1)
self.print_padding(" " + title, width)
self.terminal_goto(start_x, start_y + 2)
self.print_padding("", width)
for idx, option in enumerate(options):
self.terminal_goto(start_x, start_y + 3 + idx)
if idx == selected:
self.print(self.ANSI_BG_WHITE + self.ANSI_TEXT_BLUE)
else:
self.print(self.ANSI_BG_BLUE + self.ANSI_TEXT_WHITE)
self.print_padding(f" {option}", width)

self.print(self.ANSI_BG_BLUE + self.ANSI_TEXT_WHITE)
self.terminal_goto(start_x, start_y + 3 + len(options))
self.print_padding("", width)
self.print(self.ANSI_RESET + self.ANSI_BG_WHITE + self.ANSI_TEXT_BLUE)
self.flush()

print_select()
while True:
key = self.wait_for_input(timeout=10000000)
if key is None:
return None
elif key == "escape":
return None
elif key == "q":
return None
elif key == "\n":
break
elif key == "up":
selected -= 1
if selected < 0:
selected = 0
elif key == "down":
selected += 1
if selected >= len(options):
selected = len(options) - 1
print_select()
self.print(self.ANSI_RESET)
self.print_all()

return options[selected]

def print_padding(self, text, count=None):
if count is None:
count = self.width
Expand Down
13 changes: 13 additions & 0 deletions default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,16 @@ name_positive_regex=.*
name_negative_regex=(System|Timer|Announce)
# hardware | software | all | none. Default none, so set to hardware normally.
type=hardware


[rawmidi]
# This is the ALSA rawmidi device that will be exported to rtpmidi.
name=MIDI C4D0
device=/dev/snd/midiC4D0
# set hostname to 0.0.0.0 or emtpy to create a server
# hostname=
local_udp_port=5104
# or set to a hostname to be a client and connect to a remote server
# hostname=raspberrypi.local
# remote_udp_port=5004

7 changes: 7 additions & 0 deletions include/rtpmidid/packet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ class packet_t {
static packet_type_e get_packet_type(const uint8_t *data, size_t size);
packet_type_e get_packet_type() const;

packet_t slice(size_t offset, size_t length) const {
if (offset + length > size) {
throw std::runtime_error("Slice out of bounds");
}
return packet_t(data + offset, length);
}

std::string to_string() const {
std::string ret = "";
int block_chars = 4;
Expand Down
10 changes: 5 additions & 5 deletions lib/mdns_rtpmidi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ void rtpmidid::mdns_rtpmidi_t::remove_announcement(const std::string &name,
}
}

auto format_as(const AvahiWatchEvent ev) {
const char *format_as(const AvahiWatchEvent ev) {
switch (ev) {
case AVAHI_WATCH_IN:
return "AVAHI_WATCH_IN";
Expand All @@ -643,7 +643,7 @@ auto format_as(const AvahiWatchEvent ev) {
}
}

auto format_as(const AvahiBrowserEvent ev) {
const char *format_as(const AvahiBrowserEvent ev) {
switch (ev) {
case AVAHI_BROWSER_NEW:
return "AVAHI_BROWSER_NEW";
Expand All @@ -660,7 +660,7 @@ auto format_as(const AvahiBrowserEvent ev) {
}
}

auto format_as(const AvahiEntryGroupState state) {
const char *format_as(const AvahiEntryGroupState state) {
switch (state) {
case AVAHI_ENTRY_GROUP_UNCOMMITED:
return "AVAHI_ENTRY_GROUP_UNCOMMITED";
Expand All @@ -676,7 +676,7 @@ auto format_as(const AvahiEntryGroupState state) {
return "AVAHI_ENTRY_GROUP_UNKNOWN";
}
}
auto format_as(const AvahiClientState state) {
const char *format_as(const AvahiClientState state) {
switch (state) {
case AVAHI_CLIENT_S_RUNNING:
return "AVAHI_CLIENT_S_RUNNING";
Expand All @@ -691,7 +691,7 @@ auto format_as(const AvahiClientState state) {
}
}

auto format_as(const AvahiLookupResultFlags flag) {
const char *format_as(const AvahiLookupResultFlags flag) {
switch (flag) {
case AVAHI_LOOKUP_RESULT_CACHED:
return "AVAHI_LOOKUP_RESULT_CACHED";
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ add_library(
midipeer.cpp
rtpmidiremotehandler.cpp
utils.cpp
midi_normalizer.cpp

local_alsa_listener.cpp
local_alsa_multi_listener.cpp
local_alsa_peer.cpp
local_rawmidi_peer.cpp
network_rtpmidi_client.cpp
network_rtpmidi_listener.cpp
network_rtpmidi_multi_listener.cpp
Expand Down
48 changes: 47 additions & 1 deletion src/control_socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ rtpmididns::control_socket_t::~control_socket_t() noexcept {
}
connection_listener.stop();
close(socket);
DEBUG("Closed control socket");
}

void rtpmididns::control_socket_t::connection_ready() {
Expand Down Expand Up @@ -204,7 +205,7 @@ const std::vector<control_socket_ns::command_t> COMMANDS{
return "ok";
}},
{"router.connect",
"Connects two peers at the router. Unidirectional conneciton.",
"Connects two peers at the router. Unidirectional connection.",
[](control_socket_t &control, const json_t &params) {
DEBUG("Params {}", params.dump());
peer_id_t from_peer_id = params["from"];
Expand Down Expand Up @@ -260,6 +261,51 @@ const std::vector<control_socket_ns::command_t> COMMANDS{
control.router, name, hostname, port, control.aseq, "0"));
return json_t{"ok"};
}},
{"router.create", "Create a new peer of the specific type and params",
[](control_socket_t &control, const json_t &params) {
DEBUG("Create peer: {}", params.dump());
std::string type = params["type"];
if (type == "local_rawmidi_t") {
auto peer = make_rawmidi_peer(params["name"], params["device"]);
control.router->add_peer(peer);
return peer->status();
} else if (type == "network_rtpmidi_client_t") {
auto peer = make_network_rtpmidi_client(
params["name"], params["hostname"], to_string(params["port"]));
control.router->add_peer(peer);
return peer->status();
} else if (type == "network_rtpmidi_listener_t") {
auto peer =
make_network_rtpmidi_listener(params["name"], params["udp_port"]);
control.router->add_peer(peer);
return peer->status();
} else if (type == "local_alsa_peer_t") {
auto peer = make_local_alsa_peer(params["name"], control.aseq);
control.router->add_peer(peer);
return peer->status();
} else if (type == "list") {
return json_t{
{"local_rawmidi_t",
{{"name", "Name of the peer"}, {"device", "Path to the device"}}},
//
{"network_rtpmidi_client_t",
{{"name", "Name of the peer"},
{"hostname", "Hostname of the server"},
{"port", "Port of the server"}}},
//
{"network_rtpmidi_listener_t",
{{"name", "Name of the peer"},
{"udp_port", "UDP port to listen [random]"}}},
//
{"local_alsa_peer_t", {{"name", "Name of the peer"}}}
//
};

} else {
ERROR("Unknown peer type or non construtible yet: {}", type);
return json_t{{"error", "Unknown peer type"}};
}
}},
{"mdns.remove", "Delete a mdns announcement",
[](control_socket_t &control, const json_t &params) {
DEBUG("Params {}", params.dump());
Expand Down
17 changes: 15 additions & 2 deletions src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "local_alsa_listener.hpp"
#include "local_alsa_multi_listener.hpp"
#include "local_alsa_peer.hpp"
#include "local_rawmidi_peer.hpp"
#include "midipeer.hpp"
#include "network_rtpmidi_client.hpp"
#include "network_rtpmidi_listener.hpp"
Expand Down Expand Up @@ -66,6 +67,12 @@ std::shared_ptr<midipeer_t>
make_network_rtpmidi_client(std::shared_ptr<rtpmidid::rtpclient_t> peer) {
return std::make_shared<network_rtpmidi_client_t>(peer);
}
std::shared_ptr<midipeer_t>
make_network_rtpmidi_client(const std::string &name,
const std::string &hostname,
const std::string &port) {
return std::make_shared<network_rtpmidi_client_t>(name, hostname, port);
}

std::shared_ptr<midipeer_t>
make_network_rtpmidi_multi_listener(const std::string &name,
Expand All @@ -80,8 +87,14 @@ make_network_rtpmidi_peer(std::shared_ptr<rtpmidid::rtppeer_t> peer) {
}

std::shared_ptr<midipeer_t>
make_network_rtpmidi_listener(const std::string &name) {
return std::make_shared<network_rtpmidi_listener_t>(name);
make_network_rtpmidi_listener(const std::string &name,
const std::string &udp_port) {
return std::make_shared<network_rtpmidi_listener_t>(name, udp_port);
}

std::shared_ptr<midipeer_t> make_rawmidi_peer(const std::string &name,
const std::string &device) {
return std::make_shared<local_rawmidi_peer_t>(name, device);
}

} // namespace rtpmididns
11 changes: 10 additions & 1 deletion src/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,24 @@ std::shared_ptr<midipeer_t> make_local_alsa_peer(const std::string &name,
//
std::shared_ptr<midipeer_t>
make_network_rtpmidi_client(std::shared_ptr<rtpmidid::rtpclient_t> peer);
std::shared_ptr<midipeer_t>
make_network_rtpmidi_client(const std::string &name,
const std::string &hostname,
const std::string &port);

//
std::shared_ptr<midipeer_t>
make_network_rtpmidi_listener(const std::string &name);
make_network_rtpmidi_listener(const std::string &name,
const std::string &udp_port);
//
std::shared_ptr<midipeer_t>
make_local_alsa_listener(std::shared_ptr<midirouter_t> &router,
const std::string &name, const std::string &hostname,
const std::string &port, std::shared_ptr<aseq_t> aseq,
const std::string &udp_port);

//
std::shared_ptr<midipeer_t> make_rawmidi_peer(const std::string &name,
const std::string &device);

} // namespace rtpmididns
Loading

0 comments on commit 8253e1b

Please sign in to comment.