diff --git a/.gitignore b/.gitignore
index 76adb92..a6fe2e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
build/
-tests/build/
*.a
*.so
*.pb.c
diff --git a/Makefile b/Makefile
index 0e60318..fc0e340 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ SRC += $(NANOPB_DIR)/pb_common.c
PROTO = $(shell find src/ -type f -name '*.proto')
OBJ = $(PROTO:%.proto=$(BUILD_DIR)/%.pb.c.o)
OBJ += $(SRC:%=$(BUILD_DIR)/%.o)
-H = include/libumumble.h
+INCLUDE = $(shell find include/)
.PHONY: all static shared tests clean install-static install-shared install
@@ -31,16 +31,16 @@ $(BUILD_DIR)/%.c.o: %.c
mkdir -p '$(@D)'
$(CC) -c -o $@ $(INCLUDES) $(CFLAGS) $<
-tests:
+tests: $(SNAME)
$(MAKE) -C tests
clean:
rm -rf $(SNAME) $(DNAME) $(BUILD_DIR) src/*.pb.h src/*.pb.c
$(MAKE) -C tests clean
-install-header: $(H)
+install-header: $(INCLUDE)
install -d $(DESTDIR)$(INCLUDEDIR)
- install -m 644 $^ $(DESTDIR)$(INCLUDEDIR)
+ cp -Rv include/. $(DESTDIR)$(INCLUDEDIR)
install-static: $(SNAME)
install -d $(DESTDIR)$(LIBDIR)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..3120da8
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+- Implement packet creation/send/recv
+- Implement callbacks
+- Implement SRV record lookup
diff --git a/config.mk b/config.mk
index 8a70d53..2525823 100644
--- a/config.mk
+++ b/config.mk
@@ -5,6 +5,7 @@ INCLUDEDIR = $(PREFIX)/include
LIBDIR = $(PREFIX)/lib
BUILD_DIR = build
+BUILD_DIR_TESTS = ../build/tests
NAME = libumumble
SNAME = $(NAME).a
DNAME = $(NAME).so
diff --git a/include/umumble/constants.h b/include/umumble/constants.h
new file mode 100644
index 0000000..5dfded4
--- /dev/null
+++ b/include/umumble/constants.h
@@ -0,0 +1,78 @@
+#ifndef UMUMBLE_CONSTANTS_H
+#define UMUMBLE_CONSTANTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+enum mumble_tcp_packet_type {
+ MUMBLE_TCP_PACKET_Version,
+ MUMBLE_TCP_PACKET_UDPTunnel,
+ MUMBLE_TCP_PACKET_Authenticate,
+ MUMBLE_TCP_PACKET_Ping,
+ MUMBLE_TCP_PACKET_Reject,
+ MUMBLE_TCP_PACKET_ServerSync,
+ MUMBLE_TCP_PACKET_ChannelRemove,
+ MUMBLE_TCP_PACKET_ChannelState,
+ MUMBLE_TCP_PACKET_UserRemove,
+ MUMBLE_TCP_PACKET_UserState,
+ MUMBLE_TCP_PACKET_BanList,
+ MUMBLE_TCP_PACKET_TextMessage,
+ MUMBLE_TCP_PACKET_PermissionDenied,
+ MUMBLE_TCP_PACKET_ACL,
+ MUMBLE_TCP_PACKET_QueryUsers,
+ MUMBLE_TCP_PACKET_CryptSetup,
+ MUMBLE_TCP_PACKET_ContextActionModify,
+ MUMBLE_TCP_PACKET_ContextAction,
+ MUMBLE_TCP_PACKET_UserList,
+ MUMBLE_TCP_PACKET_VoiceTarget,
+ MUMBLE_TCP_PACKET_PermissionQuery,
+ MUMBLE_TCP_PACKET_CodecVersion,
+ MUMBLE_TCP_PACKET_UserStats,
+ MUMBLE_TCP_PACKET_RequestBlob,
+ MUMBLE_TCP_PACKET_ServerConfig,
+ MUMBLE_TCP_PACKET_SuggestConfig,
+ MUMBLE_TCP_PACKET_PluginDataTransmission,
+};
+
+enum mumble_udp_packet_type {
+ MUMBLE_UDP_PACKET_Audio,
+ MUMBLE_UDP_PACKET_Ping
+};
+
+enum mumble_acl {
+ MUMBLE_ACL_None = 0,
+ MUMBLE_ACL_Write = 1,
+ MUMBLE_ACL_Traverse = 1 << 1,
+ MUMBLE_ACL_Enter = 1 << 2,
+ MUMBLE_ACL_Speak = 1 << 3,
+ MUMBLE_ACL_MuteDeafen = 1 << 4,
+ MUMBLE_ACL_Move = 1 << 5,
+ MUMBLE_ACL_MakeChannel = 1 << 6,
+ MUMBLE_ACL_LinkChannel = 1 << 7,
+ MUMBLE_ACL_Whisper = 1 << 8,
+ MUMBLE_ACL_TextMessage = 1 << 9,
+ MUMBLE_ACL_MakeTempChannel = 1 << 10,
+ MUMBLE_ACL_Listen = 1 << 11,
+
+ // Root channel only
+ MUMBLE_ACL_Kick = 1 << 16,
+ MUMBLE_ACL_Ban = 1 << 17,
+ MUMBLE_ACL_Register = 1 << 18,
+ MUMBLE_ACL_SelfRegister = 1 << 19,
+ MUMBLE_ACL_ResetUserContent = 1 << 20
+};
+
+enum mumble_ctx_status {
+ MUMBLE_STATUS_UNINITIALIZED = 0,
+ MUMBLE_STATUS_READY,
+ MUMBLE_STATUS_CONNECTING,
+ MUMBLE_STATUS_CONNECTED,
+ MUMBLE_STATUS_DISCONNECTED
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* UMUMBLE_CONSTANTS_H */
diff --git a/include/libumumble.h b/include/umumble/umumble.h
index 43ba3ec..755be59 100644
--- a/include/libumumble.h
+++ b/include/umumble/umumble.h
@@ -1,23 +1,17 @@
-#ifndef LIBUMUMBLE_H
-#define LIBUMUMBLE_H
+#ifndef UMUMBLE_UMUMBLE_H
+#define UMUMBLE_UMUMBLE_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
+#include "constants.h"
+
#include <uv.h>
#include <tlsuv/tlsuv.h>
-enum mumble_ctx_status {
- UNINITIALIZED = 0,
- READY,
- CONNECTING,
- CONNECTED,
- DISCONNECTED
-};
-
-typedef struct mumble_ctx {
- enum mumble_ctx_status status;
+typedef struct mumble_ctx_s {
+ int status;
int error;
uv_loop_t uv_loop;
uv_getaddrinfo_t uv_resolver;
@@ -52,4 +46,4 @@ int mumble_run(mumble_ctx_t *ctx);
}
#endif /* __cplusplus */
-#endif /* LIBUMUMBLE_H */
+#endif /* UMUMBLE_UMUMBLE_H */
diff --git a/src/connection.c b/src/connection.c
index c484163..2c2bfbd 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1,10 +1,10 @@
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
-#include <libumumble.h>
+#include <umumble/umumble.h>
#include <tlsuv/tlsuv.h>
#include <uv.h>
-#include "Mumble.pb.h"
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = malloc(suggested_size);
@@ -37,10 +37,10 @@ void on_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
if (nread < 0) {
if (nread != UV_EOF) {
ctx->error = nread;
- ctx->status = DISCONNECTED;
+ ctx->status = MUMBLE_STATUS_DISCONNECTED;
}
tlsuv_stream_close((tlsuv_stream_t *) client, on_close_cb);
- ctx->status = DISCONNECTED;
+ ctx->status = MUMBLE_STATUS_DISCONNECTED;
free(buf->base);
free(client);
return;
@@ -62,11 +62,11 @@ void on_connect_cb(uv_connect_t *req, int status)
if (status < 0) {
ctx->error = status;
- ctx->status = DISCONNECTED;
+ ctx->status = MUMBLE_STATUS_DISCONNECTED;
tlsuv_stream_close((tlsuv_stream_t *) req->handle, on_close_cb);
return;
}
- ctx->status = CONNECTED;
+ ctx->status = MUMBLE_STATUS_CONNECTED;
tlsuv_stream_read(tls_stream, alloc_buffer, on_read_cb);
@@ -89,7 +89,7 @@ void on_resolve_cb(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res)
assert(status >= 0);
if (status < 0) {
ctx->error = status;
- ctx->status = DISCONNECTED;
+ ctx->status = MUMBLE_STATUS_DISCONNECTED;
return;
}
diff --git a/src/ctx.c b/src/ctx.c
index 35864d1..2612ffb 100644
--- a/src/ctx.c
+++ b/src/ctx.c
@@ -1,7 +1,7 @@
#include <assert.h>
#include <string.h>
-#include <libumumble.h>
+#include <umumble/umumble.h>
#include <uv.h>
int mumble_ctx_init(mumble_ctx_t *ctx)
@@ -19,7 +19,7 @@ int mumble_ctx_init(mumble_ctx_t *ctx)
ctx->uv_connect_req.data = ctx;
ctx->uv_tcp_socket.data = ctx;
- ctx->status = READY;
+ ctx->status = MUMBLE_STATUS_READY;
return 0;
}
diff --git a/src/message.c b/src/message.c
new file mode 100644
index 0000000..8c066c2
--- /dev/null
+++ b/src/message.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+static void mumble_packet_gen_header(uint8_t *buf, uint16_t type, uint32_t len)
+{
+ uint16_t type_be;
+ uint32_t len_be;
+
+ type_be = htons(type);
+ len_be = htonl(len);
+
+ memcpy(buf, &type_be, 2);
+ memcpy(buf+2, &len_be, 4);
+}
diff --git a/src/Mumble.proto b/src/proto/MumbleTCP.proto
index c3a23f2..4a86e10 100644
--- a/src/Mumble.proto
+++ b/src/proto/MumbleTCP.proto
@@ -5,7 +5,7 @@
syntax = "proto2";
-package MumbleProto;
+package MumbleTCP;
option optimize_for = SPEED;
diff --git a/src/proto/MumbleUDP.proto b/src/proto/MumbleUDP.proto
new file mode 100644
index 0000000..4f27390
--- /dev/null
+++ b/src/proto/MumbleUDP.proto
@@ -0,0 +1,85 @@
+// Copyright 2022 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+syntax = "proto3";
+
+package MumbleUDP;
+
+option optimize_for = SPEED;
+
+message Audio {
+ oneof Header {
+ // When this audio is sent by the client to the server, this is set to the target of the audio data. This target
+ // is a number in the range [0, 2^{32} - 1], where 0 means "normal talking", 2^{5} - 1 means "server loopback"
+ // and all other targets are understood as shout/whisper targets that have previously been registered via a
+ // VoiceTarget message (via TCP).
+ uint32 target = 1;
+ // When this audio is sent by the server to the client, this indicates the context in which the audio has been sent.
+ // 0: Normal speech
+ // 1: Shout to channel
+ // 2: Whisper to user
+ // 3: Received via channel listener
+ uint32 context = 2;
+ };
+
+ // The session of the client (sender) this audio was originally sent from. This field is not required when sending
+ // audio to the server, but will always be set when receiving audio from the server.
+ uint32 sender_session = 3;
+
+ // The number of the first contained audio frame (indicating the position of that frame in the overall audio stream)
+ uint64 frame_number = 4;
+
+ // The actual voice data payload in the Opus format.
+ bytes opus_data = 5;
+
+ // Optional positional data indicating the speaker's position in a virtual world (in meters). This "list" is really
+ // expected to be an array of size 3 containing the X, Y and Z coordinates of the position (in that order).
+ repeated float positional_data = 6;
+
+ // A volume adjustment determined by the server for this audio packet. It is up to the client to apply this adjustment to
+ // the resulting audio (or not). Note: A value of 0 means that this field is unset.
+ float volume_adjustment = 7;
+
+ // Note that we skip the field indices up to (including) 15 in order to have them available for future extensions of the
+ // protocol with fields that are encountered very often. The reason is that all field indices <= 15 require only a single
+ // byte of encoding overhead, whereas the once > 15 require (at least) two bytes. The reason lies in the Protobuf encoding
+ // scheme that uses 1 bit for a varint continuation flag, 3 bit to encode a field's type and the remaining 4 bit of the
+ // first byte are thus available for the field index. Therefore the first 2^4 = 16 field indices (aka values 0 to 15) can
+ // be encoded using only a single byte. For details see https://developers.google.com/protocol-buffers/docs/encoding
+
+ // A flag indicating whether this audio packet represents the end of transmission for the current audio stream
+ bool is_terminator = 16;
+}
+
+/**
+ * Ping message for checking UDP connectivity (and roundtrip ping) and potentially obtaining further server
+ * details (e.g. version).
+ */
+message Ping {
+ // Timestamp as encoded by the client. A server is not supposed to attempt to decode or modify this field. Therefore,
+ // clients may choose an arbitrary format for this timestamp (as long as it fits into a uint64 field).
+ uint64 timestamp = 1;
+
+ // A flag set by the sending client, if it wants to obtain additional information about the server.
+ bool request_extended_information = 2;
+
+
+ // Below are the fields for the "additional information" that are filled out by the server on request.
+
+ // The version of the server in the new version format.
+ // The new protobuf Ping packet introduced with 1.5 drops support for the legacy version format
+ // since both server and client have to support this new format.
+ // (See https://github.com/mumble-voip/mumble/issues/5827)
+ uint64 server_version_v2 = 3;
+
+ // The amount of users currently connected to the server
+ uint32 user_count = 4;
+
+ // The maximum amount of users permitted on this server
+ uint32 max_user_count = 5;
+
+ // The maximum bandwidth each user is allowed to use for sending audio to the server
+ uint32 max_bandwidth_per_user = 6;
+}
diff --git a/tests/Makefile b/tests/Makefile
index 95a146b..b6ee873 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,4 +1,5 @@
include ../config.mk
+BUILD_DIR = $(BUILD_DIR_TESTS)
INCLUDES = -I../include
SRC = $(shell find -type f -name '*.c')
@@ -7,7 +8,7 @@ BIN = $(SRC:%.c=%)
LDLIBS := -l:libumumble.a $(LDLIBS)
LDFLAGS += -L..
-.PHONY: all
+.PHONY: all clean
all: $(BIN)
diff --git a/tests/test.c b/tests/test.c
index 1c673a0..848ec38 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -1,4 +1,4 @@
-#include <libumumble.h>
+#include <umumble/umumble.h>
int main(int argc, char *argv[])
{
|