Add ChiakiFeedbackSender

This commit is contained in:
Florian Märkl 2019-06-30 12:23:42 +02:00
commit 193c056067
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
11 changed files with 352 additions and 32 deletions

View file

@ -127,12 +127,12 @@ void StreamSession::SendFeedbackState()
{
if(!gamepad)
return;
ChiakiFeedbackState state;
ChiakiControllerState state;
state.left_x = static_cast<int16_t>(gamepad->axisLeftX() * 0x7fff);
state.left_y = static_cast<int16_t>(gamepad->axisLeftX() * 0x7fff);
state.right_x = static_cast<int16_t>(gamepad->axisLeftX() * 0x7fff);
state.right_y = static_cast<int16_t>(gamepad->axisLeftX() * 0x7fff);
chiaki_stream_connection_send_feedback_state(&session.stream_connection, &state);
chiaki_session_set_controller_state(&session, &state);
}
void StreamSession::PushAudioFrame(int16_t *buf, size_t samples_count)

View file

@ -27,7 +27,9 @@ set(HEADER_FILES
include/chiaki/stoppipe.h
include/chiaki/reorderqueue.h
include/chiaki/discoveryservice.h
include/chiaki/feedback.h)
include/chiaki/feedback.h
include/chiaki/feedbacksender.h
include/chiaki/controller.h)
set(SOURCE_FILES
src/common.c
@ -57,7 +59,9 @@ set(SOURCE_FILES
src/stoppipe.c
src/reorderqueue.c
src/discoveryservice.c
src/feedback.c)
src/feedback.c
src/feedbacksender.c
src/controller.c)
add_subdirectory(protobuf)
include_directories("${NANOPB_SOURCE_DIR}")

View file

@ -0,0 +1,52 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef CHIAKI_CONTROLLER_H
#define CHIAKI_CONTROLLER_H
#include <stdint.h>
#include <stdbool.h>
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct chiaki_controller_state_t
{
int16_t left_x;
int16_t left_y;
int16_t right_x;
int16_t right_y;
} ChiakiControllerState;
CHIAKI_EXPORT void chiaki_controller_state_set_idle(ChiakiControllerState *state);
static inline bool chiaki_controller_state_equals(ChiakiControllerState *a, ChiakiControllerState *b)
{
return a->left_x == b->left_x
&& a->left_y == b->left_y
&& a->right_x == b->right_x
&& a->right_y == b->right_y;
}
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_CONTROLLER_H

View file

@ -19,6 +19,7 @@
#define CHIAKI_FEEDBACK_H
#include "common.h"
#include "log.h"
#include <stdint.h>

View file

@ -0,0 +1,54 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef CHIAKI_FEEDBACKSENDER_H
#define CHIAKI_FEEDBACKSENDER_H
#include "controller.h"
#include "takion.h"
#include "thread.h"
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct chiaki_feedback_sender_t
{
ChiakiLog *log;
ChiakiTakion *takion;
ChiakiThread thread;
ChiakiSeqNum16 state_seq_num;
bool should_stop;
ChiakiControllerState controller_state_prev;
ChiakiControllerState controller_state;
bool controller_state_changed;
ChiakiMutex state_mutex;
ChiakiCond state_cond;
} ChiakiFeedbackSender;
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_init(ChiakiFeedbackSender *feedback_sender, ChiakiTakion *takion);
CHIAKI_EXPORT void chiaki_feedback_sender_fini(ChiakiFeedbackSender *feedback_sender);
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_set_controller_state(ChiakiFeedbackSender *feedback_sender, ChiakiControllerState *state);
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_FEEDBACKSENDER_H

View file

@ -29,6 +29,7 @@
#include "audio.h"
#include "audioreceiver.h"
#include "videoreceiver.h"
#include "controller.h"
#include <stdint.h>
#include <netdb.h>
@ -138,12 +139,15 @@ typedef struct chiaki_session_t
ChiakiStreamConnection stream_connection;
ChiakiAudioReceiver *audio_receiver;
ChiakiVideoReceiver *video_receiver;
ChiakiControllerState controller_state;
} ChiakiSession;
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, ChiakiConnectInfo *connect_info);
CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_start(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session);
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_set_controller_state(ChiakiSession *session, ChiakiControllerState *state);
static inline void chiaki_session_set_event_cb(ChiakiSession *session, ChiakiEventCallback cb, void *user)
{

View file

@ -18,7 +18,7 @@
#ifndef CHIAKI_STREAMCONNECTION_H
#define CHIAKI_STREAMCONNECTION_H
#include "mirai.h"
#include "feedbacksender.h"
#include "takion.h"
#include "log.h"
#include "ecdh.h"
@ -41,7 +41,16 @@ typedef struct chiaki_stream_connection_t
ChiakiGKCrypt *gkcrypt_local;
ChiakiGKCrypt *gkcrypt_remote;
ChiakiSeqNum16 feedback_state_seq_num;
ChiakiFeedbackSender feedback_sender;
/**
* whether feedback_sender is initialized
* only if this is true, feedback_sender may be accessed!
*/
bool feedback_sender_active;
/**
* protects feedback_sender and feedback_sender_active
*/
ChiakiMutex feedback_sender_mutex;
/**
* signaled on change of state_finished or should_stop
@ -72,8 +81,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_stop(ChiakiStreamConnection *stream_connection);
CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_send_feedback_state(ChiakiStreamConnection *stream_connection, ChiakiFeedbackState *state);
#ifdef __cplusplus
}
#endif

26
lib/src/controller.c Normal file
View file

@ -0,0 +1,26 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <chiaki/controller.h>
CHIAKI_EXPORT void chiaki_controller_state_set_idle(ChiakiControllerState *state)
{
state->left_x = 0;
state->left_y = 0;
state->right_x = 0;
state->right_y = 0;
}

137
lib/src/feedbacksender.c Normal file
View file

@ -0,0 +1,137 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <chiaki/feedbacksender.h>
#define FEEDBACK_STATE_TIMEOUT_MIN_MS 8 // minimum time to wait between sending 2 packets
#define FEEDBACK_STATE_TIMEOUT_MAX_MS 200 // maximum time to wait between sending 2 packets
static void *feedback_sender_thread_func(void *user);
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_init(ChiakiFeedbackSender *feedback_sender, ChiakiTakion *takion)
{
feedback_sender->log = takion->log;
feedback_sender->takion = takion;
chiaki_controller_state_set_idle(&feedback_sender->controller_state_prev);
chiaki_controller_state_set_idle(&feedback_sender->controller_state);
feedback_sender->state_seq_num = 0;
ChiakiErrorCode err = chiaki_mutex_init(&feedback_sender->state_mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
return err;
err = chiaki_cond_init(&feedback_sender->state_cond);
if(err != CHIAKI_ERR_SUCCESS)
goto error_mutex;
err = chiaki_thread_create(&feedback_sender->thread, feedback_sender_thread_func, feedback_sender);
if(err != CHIAKI_ERR_SUCCESS)
goto error_cond;
return CHIAKI_ERR_SUCCESS;
error_cond:
chiaki_cond_fini(&feedback_sender->state_cond);
error_mutex:
chiaki_mutex_fini(&feedback_sender->state_mutex);
return err;
}
CHIAKI_EXPORT void chiaki_feedback_sender_fini(ChiakiFeedbackSender *feedback_sender)
{
chiaki_mutex_lock(&feedback_sender->state_mutex);
feedback_sender->should_stop = true;
chiaki_mutex_unlock(&feedback_sender->state_mutex);
chiaki_cond_signal(&feedback_sender->state_cond);
chiaki_thread_join(&feedback_sender->thread, NULL);
chiaki_cond_fini(&feedback_sender->state_cond);
chiaki_mutex_fini(&feedback_sender->state_mutex);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_feedback_sender_set_controller_state(ChiakiFeedbackSender *feedback_sender, ChiakiControllerState *state)
{
ChiakiErrorCode err = chiaki_mutex_lock(&feedback_sender->state_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
if(chiaki_controller_state_equals(&feedback_sender->controller_state, state))
{
chiaki_mutex_unlock(&feedback_sender->state_mutex);
return CHIAKI_ERR_SUCCESS;
}
feedback_sender->controller_state = *state;
feedback_sender->controller_state_changed = true;
chiaki_mutex_unlock(&feedback_sender->state_mutex);
chiaki_cond_signal(&feedback_sender->state_cond);
return CHIAKI_ERR_SUCCESS;
}
static void feedback_sender_send_state(ChiakiFeedbackSender *feedback_sender)
{
ChiakiFeedbackState state;
state.left_x = feedback_sender->controller_state.left_x;
state.left_y = feedback_sender->controller_state.left_y;
state.right_x = feedback_sender->controller_state.right_x;
state.right_y = feedback_sender->controller_state.right_y;
ChiakiErrorCode err = chiaki_takion_send_feedback_state(feedback_sender->takion, feedback_sender->state_seq_num++, &state);
if(err != CHIAKI_ERR_SUCCESS)
CHIAKI_LOGE(feedback_sender->log, "FeedbackSender failed to send Feedback State\n");
}
static bool state_cond_check(void *user)
{
ChiakiFeedbackSender *feedback_sender = user;
return feedback_sender->should_stop || feedback_sender->controller_state_changed;
}
static void *feedback_sender_thread_func(void *user)
{
ChiakiFeedbackSender *feedback_sender = user;
ChiakiErrorCode err = chiaki_mutex_lock(&feedback_sender->state_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return NULL;
uint64_t next_timeout = FEEDBACK_STATE_TIMEOUT_MAX_MS;
while(true)
{
err = chiaki_cond_timedwait_pred(&feedback_sender->state_cond, &feedback_sender->state_mutex, next_timeout, state_cond_check, feedback_sender);
if(err != CHIAKI_ERR_SUCCESS && err != CHIAKI_ERR_TIMEOUT)
break;
if(feedback_sender->should_stop)
break;
if(feedback_sender->controller_state_changed)
{
// TODO: FEEDBACK_STATE_TIMEOUT_MIN_MS
feedback_sender->controller_state_changed = false;
}
feedback_sender_send_state(feedback_sender);
feedback_sender->controller_state_prev = feedback_sender->controller_state;
}
chiaki_mutex_unlock(&feedback_sender->state_mutex);
return NULL;
}

View file

@ -51,15 +51,19 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki
session->quit_reason = CHIAKI_QUIT_REASON_NONE;
if(chiaki_cond_init(&session->ctrl_cond) != CHIAKI_ERR_SUCCESS)
{
return CHIAKI_ERR_UNKNOWN;
}
ChiakiErrorCode err = chiaki_cond_init(&session->ctrl_cond);
if(err != CHIAKI_ERR_SUCCESS)
goto error;
if(chiaki_mutex_init(&session->ctrl_cond_mutex, false) != CHIAKI_ERR_SUCCESS)
err = chiaki_mutex_init(&session->ctrl_cond_mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
goto error_ctrl_cond;
err = chiaki_stream_connection_init(&session->stream_connection, session);
if(err != CHIAKI_ERR_SUCCESS)
{
chiaki_cond_fini(&session->ctrl_cond);
return CHIAKI_ERR_UNKNOWN;
CHIAKI_LOGE(&session->log, "StreamConnection init failed\n");
goto error_ctrl_cond_mutex;
}
int r = getaddrinfo(connect_info->host, NULL, NULL, &session->connect_info.host_addrinfos);
@ -83,17 +87,26 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki
return CHIAKI_ERR_MEMORY;
}
chiaki_controller_state_set_idle(&session->controller_state);
memcpy(session->connect_info.auth, connect_info->auth, sizeof(session->connect_info.auth));
memcpy(session->connect_info.morning, connect_info->morning, sizeof(session->connect_info.morning));
memcpy(session->connect_info.did, connect_info->did, sizeof(session->connect_info.did));
return CHIAKI_ERR_SUCCESS;
error_ctrl_cond_mutex:
chiaki_mutex_fini(&session->ctrl_cond_mutex);
error_ctrl_cond:
chiaki_cond_fini(&session->ctrl_cond);
error:
return err;
}
CHIAKI_EXPORT void chiaki_session_fini(ChiakiSession *session)
{
if(!session)
return;
chiaki_stream_connection_fini(&session->stream_connection);
chiaki_cond_fini(&session->ctrl_cond);
chiaki_mutex_fini(&session->ctrl_cond_mutex);
free(session->connect_info.regist_key);
@ -111,6 +124,18 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_join(ChiakiSession *session)
return chiaki_thread_join(&session->session_thread, NULL);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_session_set_controller_state(ChiakiSession *session, ChiakiControllerState *state)
{
ChiakiErrorCode err = chiaki_mutex_lock(&session->stream_connection.feedback_sender_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
session->controller_state = *state;
if(session->stream_connection.feedback_sender_active)
chiaki_feedback_sender_set_controller_state(&session->stream_connection.feedback_sender, &session->controller_state);
chiaki_mutex_unlock(&session->stream_connection.feedback_sender_mutex);
return CHIAKI_ERR_SUCCESS;
}
static void session_send_event(ChiakiSession *session, ChiakiEvent *event)
{
if(!session->event_cb)
@ -199,13 +224,6 @@ static void *session_thread_func(void *arg)
goto quit_audio_receiver;
}
err = chiaki_stream_connection_init(&session->stream_connection, session);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(&session->log, "StreamConnection init failed\n");
goto quit_video_receiver;
}
err = chiaki_stream_connection_run(&session->stream_connection);
if(err != CHIAKI_ERR_SUCCESS)
{

View file

@ -72,8 +72,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnecti
stream_connection->gkcrypt_remote = NULL;
stream_connection->gkcrypt_local = NULL;
stream_connection->feedback_state_seq_num = 0;
ChiakiErrorCode err = chiaki_mutex_init(&stream_connection->state_mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
goto error;
@ -82,6 +80,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnecti
if(err != CHIAKI_ERR_SUCCESS)
goto error_state_mutex;
err = chiaki_mutex_init(&stream_connection->feedback_sender_mutex, false);
if(err != CHIAKI_ERR_SUCCESS)
goto error_state_cond;
stream_connection->state = STATE_IDLE;
stream_connection->state_finished = false;
stream_connection->state_failed = false;
@ -89,6 +91,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_init(ChiakiStreamConnecti
return CHIAKI_ERR_SUCCESS;
error_state_cond:
chiaki_cond_fini(&stream_connection->state_cond);
error_state_mutex:
chiaki_mutex_fini(&stream_connection->state_mutex);
error:
@ -102,6 +106,8 @@ CHIAKI_EXPORT void chiaki_stream_connection_fini(ChiakiStreamConnection *stream_
free(stream_connection->ecdh_secret);
chiaki_mutex_fini(&stream_connection->feedback_sender_mutex);
chiaki_cond_fini(&stream_connection->state_cond);
chiaki_mutex_fini(&stream_connection->state_mutex);
}
@ -200,6 +206,19 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio
CHIAKI_LOGI(&session->log, "StreamConnection successfully received streaminfo\n");
err = chiaki_mutex_lock(&stream_connection->feedback_sender_mutex);
assert(err == CHIAKI_ERR_SUCCESS);
err = chiaki_feedback_sender_init(&stream_connection->feedback_sender, &stream_connection->takion);
if(err != CHIAKI_ERR_SUCCESS)
{
chiaki_mutex_unlock(&stream_connection->feedback_sender_mutex);
CHIAKI_LOGE(stream_connection->log, "StreamConnection failed to start Feedback Sender\n");
goto disconnect;
}
stream_connection->feedback_sender_active = true;
chiaki_feedback_sender_set_controller_state(&stream_connection->feedback_sender, &session->controller_state);
chiaki_mutex_unlock(&stream_connection->feedback_sender_mutex);
stream_connection->state = STATE_IDLE;
stream_connection->state_finished = false;
stream_connection->state_failed = false;
@ -216,6 +235,12 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_run(ChiakiStreamConnectio
CHIAKI_LOGI(stream_connection->log, "StreamConnection sent heartbeat\n");
}
err = chiaki_mutex_lock(&stream_connection->feedback_sender_mutex);
assert(err == CHIAKI_ERR_SUCCESS);
stream_connection->feedback_sender_active = false;
chiaki_feedback_sender_fini(&stream_connection->feedback_sender);
chiaki_mutex_unlock(&stream_connection->feedback_sender_mutex);
err = CHIAKI_ERR_SUCCESS;
disconnect:
@ -729,11 +754,3 @@ static ChiakiErrorCode stream_connection_send_heartbeat(ChiakiStreamConnection *
return chiaki_takion_send_message_data(&stream_connection->takion, 1, 1, buf, stream.bytes_written);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_stream_connection_send_feedback_state(ChiakiStreamConnection *stream_connection, ChiakiFeedbackState *state)
{
ChiakiErrorCode err = chiaki_takion_send_feedback_state(&stream_connection->takion, stream_connection->feedback_state_seq_num++, state);
if(err != CHIAKI_ERR_SUCCESS)
CHIAKI_LOGE(stream_connection->log, "StreamConnection failed to send feedback state\n");
return err;
}