diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 2c8a829..9c158f0 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -15,7 +15,8 @@ set(HEADER_FILES
include/chiaki/ecdh.h
include/chiaki/launchspec.h
include/chiaki/random.h
- include/chiaki/gkcrypt.h)
+ include/chiaki/gkcrypt.h
+ include/chiaki/audio.h)
set(SOURCE_FILES
src/common.c
@@ -35,7 +36,7 @@ set(SOURCE_FILES
src/ecdh.c
src/launchspec.c
src/random.c
- src/gkcrypt.c)
+ src/gkcrypt.c src/audio.c)
add_subdirectory(protobuf)
include_directories("${NANOPB_SOURCE_DIR}")
diff --git a/lib/include/chiaki/audio.h b/lib/include/chiaki/audio.h
new file mode 100644
index 0000000..071f77a
--- /dev/null
+++ b/lib/include/chiaki/audio.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of Chiaki.
+ *
+ * Chiaki is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chiaki is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chiaki. If not, see .
+ */
+
+#ifndef CHIAKI_AUDIO_H
+#define CHIAKI_AUDIO_H
+
+#include
+
+#include "common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CHIAKI_AUDIO_HEADER_SIZE 0xe
+
+typedef struct chiaki_audio_header_t
+{
+ uint8_t channels;
+ uint8_t bits;
+ uint32_t rate;
+ uint32_t frame_size;
+ uint32_t unknown;
+} ChiakiAudioHeader;
+
+CHIAKI_EXPORT void chiaki_audio_header_load(ChiakiAudioHeader *audio_header, const uint8_t *buf);
+CHIAKI_EXPORT void chiaki_audio_header_save(ChiakiAudioHeader *audio_header, uint8_t *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CHIAKI_AUDIO_H
diff --git a/lib/include/chiaki/mirai.h b/lib/include/chiaki/mirai.h
index a0a03db..e4db2c2 100644
--- a/lib/include/chiaki/mirai.h
+++ b/lib/include/chiaki/mirai.h
@@ -28,17 +28,18 @@ extern "C" {
typedef struct chiaki_mirai_t
{
- bool expected;
- bool success;
+ int request;
+ int response;
ChiakiMutex mutex;
ChiakiCond cond;
} ChiakiMirai;
CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_init(ChiakiMirai *mirai);
CHIAKI_EXPORT void chiaki_mirai_fini(ChiakiMirai *mirai);
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_signal(ChiakiMirai *mirai, bool success);
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_expect_begin(ChiakiMirai *mirai);
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_expect_wait(ChiakiMirai *mirai, uint64_t timeout_ms);
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_signal(ChiakiMirai *mirai, int response);
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_begin(ChiakiMirai *mirai, int request, bool first);
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_wait(ChiakiMirai *mirai, uint64_t timeout_ms, bool keep_locked);
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_unlock(ChiakiMirai *mirai);
#ifdef __cplusplus
}
diff --git a/lib/include/chiaki/nagare.h b/lib/include/chiaki/nagare.h
index 55984d9..fb958d5 100644
--- a/lib/include/chiaki/nagare.h
+++ b/lib/include/chiaki/nagare.h
@@ -23,6 +23,7 @@
#include "log.h"
#include "ecdh.h"
#include "gkcrypt.h"
+#include "audio.h"
#include
@@ -35,10 +36,11 @@ typedef struct chiaki_nagare_t
struct chiaki_session_t *session;
ChiakiLog *log;
ChiakiTakion takion;
- ChiakiMirai bang_mirai;
+ ChiakiMirai mirai;
uint8_t *ecdh_secret;
ChiakiGKCrypt *gkcrypt_a;
ChiakiGKCrypt *gkcrypt_b;
+ ChiakiAudioHeader audio_header;
} ChiakiNagare;
CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(struct chiaki_session_t *session);
diff --git a/lib/src/audio.c b/lib/src/audio.c
new file mode 100644
index 0000000..e914082
--- /dev/null
+++ b/lib/src/audio.c
@@ -0,0 +1,39 @@
+/*
+ * This file is part of Chiaki.
+ *
+ * Chiaki is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chiaki is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chiaki. If not, see .
+ */
+
+#include
+
+#include
+
+
+void chiaki_audio_header_load(ChiakiAudioHeader *audio_header, const uint8_t *buf)
+{
+ audio_header->bits = buf[0];
+ audio_header->channels = buf[1];
+ audio_header->rate = ntohl(*((uint32_t *)(buf + 2)));
+ audio_header->frame_size = ntohl(*((uint32_t *)(buf + 6)));
+ audio_header->unknown = ntohl(*((uint32_t *)(buf + 0xa)));
+}
+
+void chiaki_audio_header_save(ChiakiAudioHeader *audio_header, uint8_t *buf)
+{
+ buf[0] = audio_header->bits;
+ buf[1] = audio_header->channels;
+ *((uint32_t *)(buf + 2)) = htonl(audio_header->rate);
+ *((uint32_t *)(buf + 6)) = htonl(audio_header->frame_size);
+ *((uint32_t *)(buf + 0xa)) = htonl(audio_header->unknown);
+}
\ No newline at end of file
diff --git a/lib/src/mirai.c b/lib/src/mirai.c
index 153af61..4245bf9 100644
--- a/lib/src/mirai.c
+++ b/lib/src/mirai.c
@@ -19,8 +19,8 @@
CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_init(ChiakiMirai *mirai)
{
- mirai->expected = false;
- mirai->success = false;
+ mirai->request = -1;
+ mirai->response = -1;
ChiakiErrorCode err = chiaki_mutex_init(&mirai->mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
@@ -39,33 +39,39 @@ CHIAKI_EXPORT void chiaki_mirai_fini(ChiakiMirai *mirai)
chiaki_cond_fini(&mirai->cond);
}
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_signal(ChiakiMirai *mirai, bool success)
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_signal(ChiakiMirai *mirai, int response)
{
ChiakiErrorCode err = chiaki_mutex_lock(&mirai->mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
- mirai->success = success;
+ mirai->response = response;
err = chiaki_cond_signal(&mirai->cond);
if(err != CHIAKI_ERR_SUCCESS)
return err;
return chiaki_mutex_unlock(&mirai->mutex);
}
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_expect_begin(ChiakiMirai *mirai)
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_begin(ChiakiMirai *mirai, int request, bool first)
{
- ChiakiErrorCode err = chiaki_mutex_lock(&mirai->mutex);
- mirai->expected = true;
+ ChiakiErrorCode err = first ? chiaki_mutex_lock(&mirai->mutex) : CHIAKI_ERR_SUCCESS;
+ mirai->request = request;
return err;
}
-CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_expect_wait(ChiakiMirai *mirai, uint64_t timeout_ms)
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_wait(ChiakiMirai *mirai, uint64_t timeout_ms, bool keep_locked)
{
ChiakiErrorCode err = chiaki_cond_timedwait(&mirai->cond, &mirai->mutex, timeout_ms);
- if(err != CHIAKI_ERR_SUCCESS && err != CHIAKI_ERR_TIMEOUT)
- return err;
- mirai->expected = false;
- ChiakiErrorCode err2 = chiaki_mutex_unlock(&mirai->mutex);
- if(err2 != CHIAKI_ERR_SUCCESS)
- return err2;
+ mirai->request = -1;
+ if(!keep_locked)
+ {
+ ChiakiErrorCode err2 = chiaki_mutex_unlock(&mirai->mutex);
+ if(err2 != CHIAKI_ERR_SUCCESS)
+ return err2;
+ }
return err;
+}
+
+CHIAKI_EXPORT ChiakiErrorCode chiaki_mirai_request_unlock(ChiakiMirai *mirai)
+{
+ return chiaki_mutex_unlock(&mirai->mutex);
}
\ No newline at end of file
diff --git a/lib/src/nagare.c b/lib/src/nagare.c
index 48d9e8a..0bcb85a 100644
--- a/lib/src/nagare.c
+++ b/lib/src/nagare.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
@@ -36,13 +37,27 @@
#define NAGARE_PORT 9296
-#define BIG_TIMEOUT_MS 5000
+#define EXPECT_TIMEOUT_MS 5000
+
+
+typedef enum {
+ NAGARE_MIRAI_REQUEST_BANG = 0,
+ NAGARE_MIRAI_REQUEST_STREAMINFO,
+} NagareMiraiRequest;
+
+typedef enum {
+ NAGARE_MIRAI_RESPONSE_FAIL = 0,
+ NAGARE_MIRAI_RESPONSE_SUCCESS = 1
+} NagareMiraiResponse;
+
static void nagare_takion_data(uint8_t *buf, size_t buf_size, void *user);
static ChiakiErrorCode nagare_send_big(ChiakiNagare *nagare);
static ChiakiErrorCode nagare_send_disconnect(ChiakiNagare *nagare);
static void nagare_takion_data_expect_bang(ChiakiNagare *nagare, uint8_t *buf, size_t buf_size);
+static void nagare_takion_data_expect_streaminfo(ChiakiNagare *nagare, uint8_t *buf, size_t buf_size);
+static ChiakiErrorCode nagare_send_streaminfo_ack(ChiakiNagare *nagare);
CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
@@ -53,9 +68,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
nagare->ecdh_secret = NULL;
- ChiakiErrorCode err = chiaki_mirai_init(&nagare->bang_mirai);
+ ChiakiErrorCode err = chiaki_mirai_init(&nagare->mirai);
if(err != CHIAKI_ERR_SUCCESS)
- goto error_bang_mirai;
+ goto error_mirai;
ChiakiTakionConnectInfo takion_info;
takion_info.log = nagare->log;
@@ -64,7 +79,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
if(!takion_info.sa)
{
err = CHIAKI_ERR_MEMORY;
- goto error_bang_mirai;
+ goto error_mirai;
}
memcpy(takion_info.sa, session->connect_info.host_addrinfo_selected->ai_addr, takion_info.sa_len);
err = set_port(takion_info.sa, htons(NAGARE_PORT));
@@ -78,12 +93,12 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(&session->log, "Nagare connect failed\n");
- goto error_bang_mirai;
+ goto error_mirai;
}
CHIAKI_LOGI(&session->log, "Nagare sending big\n");
- err = chiaki_mirai_expect_begin(&nagare->bang_mirai);
+ err = chiaki_mirai_request_begin(&nagare->mirai, NAGARE_MIRAI_REQUEST_BANG, true);
assert(err == CHIAKI_ERR_SUCCESS);
err = nagare_send_big(nagare);
@@ -93,14 +108,16 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
goto error_takion;
}
- err = chiaki_mirai_expect_wait(&nagare->bang_mirai, BIG_TIMEOUT_MS);
+ err = chiaki_mirai_request_wait(&nagare->mirai, EXPECT_TIMEOUT_MS, true);
assert(err == CHIAKI_ERR_SUCCESS || err == CHIAKI_ERR_TIMEOUT);
- if(!nagare->bang_mirai.success)
+ if(nagare->mirai.response != NAGARE_MIRAI_RESPONSE_SUCCESS)
{
if(err == CHIAKI_ERR_TIMEOUT)
CHIAKI_LOGE(&session->log, "Nagare bang receive timeout\n");
+ chiaki_mirai_request_unlock(&nagare->mirai);
+
CHIAKI_LOGE(&session->log, "Nagare didn't receive bang\n");
err = CHIAKI_ERR_UNKNOWN;
goto error_takion;
@@ -122,24 +139,43 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
goto error_gkcrypt_a;
}
+ err = chiaki_mirai_request_begin(&nagare->mirai, NAGARE_MIRAI_REQUEST_STREAMINFO, false);
+ assert(err == CHIAKI_ERR_SUCCESS);
+ err = chiaki_mirai_request_wait(&nagare->mirai, EXPECT_TIMEOUT_MS, false);
+ assert(err == CHIAKI_ERR_SUCCESS || err == CHIAKI_ERR_TIMEOUT);
+
+ if(nagare->mirai.response != NAGARE_MIRAI_RESPONSE_SUCCESS)
+ {
+ if(err == CHIAKI_ERR_TIMEOUT)
+ CHIAKI_LOGE(&session->log, "Nagare streaminfo receive timeout\n");
+
+ chiaki_mirai_request_unlock(&nagare->mirai);
+
+ CHIAKI_LOGE(&session->log, "Nagare didn't receive streaminfo\n");
+ err = CHIAKI_ERR_UNKNOWN;
+ goto error_takion;
+ }
+
+ CHIAKI_LOGI(&session->log, "Nagare successfully received streaminfo\n");
while(1)
sleep(1);
-
CHIAKI_LOGI(&session->log, "Nagare is disconnecting\n");
nagare_send_disconnect(nagare);
err = CHIAKI_ERR_SUCCESS;
+
+ // TODO: can't roll everything back like this, takion has to be closed first always.
chiaki_gkcrypt_free(nagare->gkcrypt_b);
error_gkcrypt_a:
chiaki_gkcrypt_free(nagare->gkcrypt_a);
error_takion:
chiaki_takion_close(&nagare->takion);
CHIAKI_LOGI(&session->log, "Nagare closed takion\n");
-error_bang_mirai:
- chiaki_mirai_fini(&nagare->bang_mirai);
+error_mirai:
+ chiaki_mirai_fini(&nagare->mirai);
free(nagare->ecdh_secret);
return err;
@@ -152,10 +188,16 @@ static void nagare_takion_data(uint8_t *buf, size_t buf_size, void *user)
{
ChiakiNagare *nagare = user;
- if(nagare->bang_mirai.expected)
+ switch(nagare->mirai.request)
{
- nagare_takion_data_expect_bang(nagare, buf, buf_size);
- return;
+ case NAGARE_MIRAI_REQUEST_BANG:
+ nagare_takion_data_expect_bang(nagare, buf, buf_size);
+ return;
+ case NAGARE_MIRAI_REQUEST_STREAMINFO:
+ nagare_takion_data_expect_streaminfo(nagare, buf, buf_size);
+ return;
+ default:
+ break;
}
tkproto_TakionMessage msg;
@@ -173,9 +215,9 @@ static void nagare_takion_data(uint8_t *buf, size_t buf_size, void *user)
static void nagare_takion_data_expect_bang(ChiakiNagare *nagare, uint8_t *buf, size_t buf_size)
{
char ecdh_pub_key[128];
- ChiakiPBDecodeBuf ecdh_pub_key_buf = { sizeof(ecdh_pub_key), 0, ecdh_pub_key };
+ ChiakiPBDecodeBuf ecdh_pub_key_buf = { sizeof(ecdh_pub_key), 0, (uint8_t *)ecdh_pub_key };
char ecdh_sig[32];
- ChiakiPBDecodeBuf ecdh_sig_buf = { sizeof(ecdh_sig), 0, ecdh_sig };
+ ChiakiPBDecodeBuf ecdh_sig_buf = { sizeof(ecdh_sig), 0, (uint8_t *)ecdh_sig };
tkproto_TakionMessage msg;
memset(&msg, 0, sizeof(msg));
@@ -245,10 +287,55 @@ static void nagare_takion_data_expect_bang(ChiakiNagare *nagare, uint8_t *buf, s
goto error;
}
- chiaki_mirai_signal(&nagare->bang_mirai, true);
+ chiaki_mirai_signal(&nagare->mirai, NAGARE_MIRAI_RESPONSE_SUCCESS);
return;
error:
- chiaki_mirai_signal(&nagare->bang_mirai, false);
+ chiaki_mirai_signal(&nagare->mirai, NAGARE_MIRAI_RESPONSE_FAIL);
+}
+
+
+static void nagare_takion_data_expect_streaminfo(ChiakiNagare *nagare, uint8_t *buf, size_t buf_size)
+{
+ tkproto_TakionMessage msg;
+ memset(&msg, 0, sizeof(msg));
+
+ uint8_t audio_header[CHIAKI_AUDIO_HEADER_SIZE];
+ ChiakiPBDecodeBuf audio_header_buf = { sizeof(audio_header), 0, (uint8_t *)audio_header };
+ msg.stream_info_payload.audio_header.arg = &audio_header_buf;
+ msg.stream_info_payload.audio_header.funcs.decode = chiaki_pb_decode_buf;
+
+ // TODO: msg.stream_info_payload.resolution
+
+ pb_istream_t stream = pb_istream_from_buffer(buf, buf_size);
+ bool r = pb_decode(&stream, tkproto_TakionMessage_fields, &msg);
+ if(!r)
+ {
+ CHIAKI_LOGE(nagare->log, "Nagare failed to decode data protobuf\n");
+ return;
+ }
+
+ if(msg.type != tkproto_TakionMessage_PayloadType_STREAMINFO || !msg.has_stream_info_payload)
+ {
+ CHIAKI_LOGE(nagare->log, "Nagare expected streaminfo payload but received something else\n");
+ return;
+ }
+
+ if(audio_header_buf.size != CHIAKI_AUDIO_HEADER_SIZE)
+ {
+ CHIAKI_LOGE(nagare->log, "Nagare receoved invalid audio header in streaminfo\n");
+ goto error;
+ }
+
+ chiaki_audio_header_load(&nagare->audio_header, audio_header);
+
+ // TODO: do some checks?
+
+ nagare_send_streaminfo_ack(nagare);
+
+ chiaki_mirai_signal(&nagare->mirai, NAGARE_MIRAI_RESPONSE_SUCCESS);
+ return;
+error:
+ chiaki_mirai_signal(&nagare->mirai, NAGARE_MIRAI_RESPONSE_FAIL);
}
@@ -352,6 +439,27 @@ static ChiakiErrorCode nagare_send_big(ChiakiNagare *nagare)
return err;
}
+static ChiakiErrorCode nagare_send_streaminfo_ack(ChiakiNagare *nagare)
+{
+ tkproto_TakionMessage msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.type = tkproto_TakionMessage_PayloadType_STREAMINFOACK;
+
+ uint8_t buf[3];
+ size_t buf_size;
+
+ pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf));
+ bool pbr = pb_encode(&stream, tkproto_TakionMessage_fields, &msg);
+ if(!pbr)
+ {
+ CHIAKI_LOGE(nagare->log, "Nagare streaminfo ack protobuf encoding failed\n");
+ return CHIAKI_ERR_UNKNOWN;
+ }
+
+ buf_size = stream.bytes_written;
+ return chiaki_takion_send_message_data(&nagare->takion, 0, 1, 9, buf, buf_size);
+}
+
static ChiakiErrorCode nagare_send_disconnect(ChiakiNagare *nagare)
{
tkproto_TakionMessage msg;
diff --git a/lib/src/senkusha.c b/lib/src/senkusha.c
index 71a48f7..20ae0fa 100644
--- a/lib/src/senkusha.c
+++ b/lib/src/senkusha.c
@@ -83,7 +83,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_senkusha_run(ChiakiSession *session)
CHIAKI_LOGI(&session->log, "Senkusha sending big\n");
- err = chiaki_mirai_expect_begin(&senkusha.bang_mirai);
+ err = chiaki_mirai_request_begin(&senkusha.bang_mirai, 1, true);
assert(err == CHIAKI_ERR_SUCCESS);
err = senkusha_send_big(&senkusha);
@@ -93,10 +93,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_senkusha_run(ChiakiSession *session)
goto error_takion;
}
- err = chiaki_mirai_expect_wait(&senkusha.bang_mirai, BIG_TIMEOUT_MS);
+ err = chiaki_mirai_request_wait(&senkusha.bang_mirai, BIG_TIMEOUT_MS, false);
assert(err == CHIAKI_ERR_SUCCESS || err == CHIAKI_ERR_TIMEOUT);
- if(!senkusha.bang_mirai.success)
+ if(!senkusha.bang_mirai.response)
{
if(err == CHIAKI_ERR_TIMEOUT)
CHIAKI_LOGE(&session->log, "Senkusha bang receive timeout\n");
@@ -136,14 +136,14 @@ static void senkusha_takion_data(uint8_t *buf, size_t buf_size, void *user)
return;
}
- if(senkusha->bang_mirai.expected)
+ if(senkusha->bang_mirai.request)
{
if(msg.type != tkproto_TakionMessage_PayloadType_BANG || !msg.has_bang_payload)
{
CHIAKI_LOGE(senkusha->log, "Senkusha expected bang payload but received something else\n");
return;
}
- chiaki_mirai_signal(&senkusha->bang_mirai, true);
+ chiaki_mirai_signal(&senkusha->bang_mirai, 1);
}
}