Improve stream quit;

Start work on gamepad input...
This commit is contained in:
rock88 2020-05-04 22:13:13 +03:00
parent a0eeffdb71
commit b729ccff20
15 changed files with 186 additions and 42 deletions

View file

@ -197,7 +197,7 @@ CXX_SOURCES = $(MOONLIGHT_LIBRETRO_CXX_SOURCES) $(NANOGUI_CXX_SOURCES)
OBJECTS := $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
DEFINES += -DNANOGUI_USE_OPENGL -DNVG_STB_IMAGE_IMPLEMENTATION -DNANOGUI_NO_GLFW \
-DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE
-DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE -D__LIBRETRO__
CFLAGS += -Wall -pedantic $(fpic) -std=gnu11 $(DEFINES)
CXXFLAGS += -std=gnu++17 -fno-permissive $(DEFINES)

View file

@ -560,6 +560,7 @@
3652F046245C292B001FABF3 /* src */ = {
isa = PBXGroup;
children = (
3652F04E245C292B001FABF3 /* Limelight.h */,
3652F047245C292B001FABF3 /* PlatformThreads.h */,
3652F048245C292B001FABF3 /* Input.h */,
3652F049245C292B001FABF3 /* ControlStream.c */,
@ -567,7 +568,6 @@
3652F04B245C292B001FABF3 /* Rtsp.h */,
3652F04C245C292B001FABF3 /* SimpleStun.c */,
3652F04D245C292B001FABF3 /* InputStream.c */,
3652F04E245C292B001FABF3 /* Limelight.h */,
3652F04F245C292B001FABF3 /* RtpFecQueue.h */,
3652F050245C292B001FABF3 /* RtspConnection.c */,
3652F051245C292B001FABF3 /* ByteBuffer.h */,
@ -775,7 +775,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nmake DEBUG=1\n";
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\n#make DEBUG=1\n";
};
/* End PBXShellScriptBuildPhase section */

View file

@ -41,12 +41,8 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<PathRunnable
runnableDebuggingMode = "0"
BundleIdentifier = "libretro.RetroArch"
FilePath = "/Applications/RetroArch.app">
</PathRunnable>
<MacroExpansion>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "36DBDE8D2450BB7E0057C8D3"
@ -54,7 +50,7 @@
BlueprintName = "moonlight"
ReferencedContainer = "container:moonlight.xcodeproj">
</BuildableReference>
</MacroExpansion>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-L /Users/rock88/Documents/Projects/RetroArch/moonlight-libretro/moonlight_libretro.dylib"

View file

@ -124,7 +124,7 @@ void GameStreamClient::start(const std::string &address, STREAM_CONFIGURATION co
m_config = config;
perform_async([this, address, app_id, callback]() {
perform_async([this, address, app_id, callback] {
int status = gs_start_app(&m_server_data[address], &m_config, app_id, false, false, 0);
nanogui::async([this, callback, status] {
@ -136,3 +136,22 @@ void GameStreamClient::start(const std::string &address, STREAM_CONFIGURATION co
});
});
}
void GameStreamClient::quit(const std::string &address, ServerCallback(bool) callback) {
if (m_server_data.count(address) == 0) {
callback(Result<bool>::failure("Firstly call connect() & pair()..."));
return;
}
perform_async([this, address, callback] {
int status = gs_quit_app(&m_server_data[address]);
nanogui::async([this, callback, status] {
if (status == GS_OK) {
callback(Result<bool>::success(true));
} else {
callback(Result<bool>::failure(gs_error != NULL ? gs_error : "Unknown error..."));
}
});
});
}

View file

@ -74,6 +74,7 @@ public:
void pair(const std::string &address, const std::string &pin, ServerCallback(bool) callback);
void applist(const std::string &address, ServerCallback(PAPP_LIST) callback);
void start(const std::string &address, STREAM_CONFIGURATION config, int app_id, ServerCallback(STREAM_CONFIGURATION) callback);
void quit(const std::string &address, ServerCallback(bool) callback);
private:
GameStreamClient() {};

View file

@ -4,7 +4,9 @@
#include "glsym/glsym.h"
#include "Application.hpp"
#include "GameStreamClient.hpp"
#include "moonlight_libretro_wrapper.h"
#include "gl_render.h"
#include "libretro.h"
int main(int argc, const char * argv[]) {
glfwInit();
@ -37,6 +39,15 @@ int main(int argc, const char * argv[]) {
nanogui::scroll_callback_event(x, y);
});
glfwSetKeyCallback(window, [](GLFWwindow *w, int key, int scancode, int action, int mods) {
if (GLFW_KEY_A <= key && key <= GLFW_KEY_Z) {
keyboard_state[RETROK_a + key - GLFW_KEY_A] = action == GLFW_PRESS;
}
keyboard_state[RETROK_w] ? game_pad_state.buttonFlags |= UP_FLAG : game_pad_state.buttonFlags &= ~UP_FLAG;
keyboard_state[RETROK_s] ? game_pad_state.buttonFlags |= DOWN_FLAG : game_pad_state.buttonFlags &= ~DOWN_FLAG;
});
int width, height, fb_width, fb_height;
glfwGetWindowSize(window, &width, &height);
glfwGetFramebufferSize(window, &fb_width, &fb_height);

View file

@ -38,7 +38,7 @@ static retro_audio_sample_t audio_cb;
retro_audio_sample_batch_t audio_batch_cb;
static retro_environment_t environ_cb;
static retro_input_poll_t input_poll_cb;
static retro_input_state_t input_state_cb;
retro_input_state_t input_state_cb;
static retro_log_printf_t log_cb;
void retro_init(void) {
@ -159,6 +159,8 @@ void retro_run(void) {
keyboard_state[i] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, i);
}
moonlight_libretro_wrapper_handle_game_pad();
// Draw
glBindFramebuffer(RARCH_GL_FRAMEBUFFER, hw_render.get_current_framebuffer());

View file

@ -1,10 +1,11 @@
#include "moonlight_libretro_wrapper.h"
#include "libretro.h"
#include "gl_render.h"
#include "Application.hpp"
#include "GameStreamClient.hpp"
#include "gl_render.h"
#include <openssl/ssl.h>
#include "libretro.h"
#include "Limelight.h"
#include <curl/curl.h>
#include <openssl/ssl.h>
static bool moonlight_is_initialized = false;
@ -12,6 +13,9 @@ static Application* app;
static std::string working_dir;
int16_t keyboard_state[RETROK_LAST];
struct GamePadState game_pad_state;
extern retro_input_state_t input_state_cb;
void moonlight_libretro_wrapper_preinit() {
OpenSSL_add_all_algorithms();
@ -32,7 +36,7 @@ void moonlight_libretro_wrapper_init(int width, int height) {
nanogui::init();
app = new Application(Size(width, height), Size(width, height));
nanogui::setup(1.0 / 60.0 * 1000);
//nanogui::setup(1.0 / 60.0 * 1000); no needs anymore?
}
void moonlight_libretro_wrapper_set_working_dir(const char* dir) {
@ -49,6 +53,43 @@ void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int
nanogui::mouse_button_callback_event(button, action, modifiers);
}
static void set_game_pad_state(short flag, int16_t state) {
if (state) {
game_pad_state.buttonFlags |= flag;
} else {
game_pad_state.buttonFlags &= ~flag;
}
}
void moonlight_libretro_wrapper_handle_game_pad() {
game_pad_state.leftStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
game_pad_state.leftStickY = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
game_pad_state.rightStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
game_pad_state.rightStickY = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
#define GAME_PAD_STATE(KEY) \
input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, KEY)
set_game_pad_state(UP_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_UP));
set_game_pad_state(DOWN_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_DOWN));
set_game_pad_state(LEFT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_LEFT));
set_game_pad_state(RIGHT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_RIGHT));
set_game_pad_state(BACK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_SELECT));
set_game_pad_state(PLAY_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_START));
set_game_pad_state(A_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_A));
set_game_pad_state(B_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_B));
set_game_pad_state(X_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_X));
set_game_pad_state(Y_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_Y));
set_game_pad_state(LB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L));
set_game_pad_state(RB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R));
set_game_pad_state(LS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L3));
set_game_pad_state(RS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R3));
}
void moonlight_libretro_wrapper_draw() {
nanogui::draw();
}

View file

@ -9,9 +9,22 @@
EXTERN int16_t keyboard_state[];
struct GamePadState {
short buttonFlags;
unsigned char leftTrigger;
unsigned char rightTrigger;
short leftStickX;
short leftStickY;
short rightStickX;
short rightStickY;
};
EXTERN struct GamePadState game_pad_state;
EXTERN void moonlight_libretro_wrapper_preinit();
EXTERN void moonlight_libretro_wrapper_init(int width, int height);
EXTERN void moonlight_libretro_wrapper_set_working_dir(const char* dir);
EXTERN void moonlight_libretro_wrapper_handle_mouse_move(double x, double y);
EXTERN void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int modifiers);
EXTERN void moonlight_libretro_wrapper_handle_game_pad();
EXTERN void moonlight_libretro_wrapper_draw();

View file

@ -21,4 +21,9 @@ void Application::pop_window() {
m_windows.back()->set_visible(true);
perform_layout();
}
if (m_windows.size() == 1) {
auto main = static_cast<MainWindow *>(m_windows.front());
main->reload();
}
}

View file

@ -57,7 +57,7 @@ AddHostWindow::AddHostWindow(Widget *parent): ContentWindow(parent, "Add Host")
loader->dispose();
if (result.isSuccess()) {
m_host_added_callback(result.value());
this->pop();
} else {
screen()->add<MessageDialog>(MessageDialog::Type::Information, "Error", result.error());
}

View file

@ -5,9 +5,4 @@
class AddHostWindow: public ContentWindow {
public:
AddHostWindow(Widget *parent);
void set_host_added_callback(const std::function<void(SERVER_DATA)> &callback) { m_host_added_callback = callback; }
private:
std::function<void(SERVER_DATA)> m_host_added_callback;
};

View file

@ -47,11 +47,7 @@ void MainWindow::reload() {
auto button = container()->add<Button>("Add Host");
button->set_fixed_size(Size(100, 100));
button->set_callback([this] {
auto add_host = application()->push_window<AddHostWindow>();
add_host->set_host_added_callback([this](auto _) {
this->reload();
this->application()->pop_window();
});
application()->push_window<AddHostWindow>();
});
screen()->perform_layout();

View file

@ -15,13 +15,19 @@ static int start_mouse_x = 0, start_mouse_y = 0;
using namespace nanogui;
static std::weak_ptr<StreamWindow *> _weak;
StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_id): Widget(parent) {
_weak = std::make_shared<StreamWindow *>(this);
m_address = address;
m_app_id = app_id;
m_connection_status_is_poor = false;
m_size = parent->size();
pressed = sent_l_press = sent_r_press = false;
current_mouse_x = parent->width() / 2;
current_mouse_y = parent->height() / 2;
current_mouse_x = width() / 2;
current_mouse_y = height() / 2;
start_mouse_x = start_mouse_y = 0;
LiInitializeStreamConfiguration(&m_config);
@ -54,8 +60,31 @@ StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_i
void StreamWindow::setup_stream() {
perform_async([this] {
CONNECTION_LISTENER_CALLBACKS connection_listener_callbacks = {
.stageStarting = NULL,
.stageComplete = NULL,
.stageFailed = NULL,
.connectionStarted = NULL,
.connectionTerminated = [](int errorCode) {
if (auto stream = _weak.lock()) {
(*stream)->terminate();
}
},
.logMessage = NULL,
.rumble = NULL,
.connectionStatusUpdate = [](int status) {
if (auto stream = _weak.lock()) {
if (status == CONN_STATUS_POOR) {
(*stream)->m_connection_status_is_poor = true;
} else {
(*stream)->m_connection_status_is_poor = false;
}
}
}
};
auto m_data = GameStreamClient::client()->server_data(m_address);
LiStartConnection(&m_data.serverInfo, &m_config, NULL, &video_decoder_callbacks, &audio_decoder_callbacks, NULL, 0, NULL, 0);
LiStartConnection(&m_data.serverInfo, &m_config, &connection_listener_callbacks, &video_decoder_callbacks, &audio_decoder_callbacks, NULL, 0, NULL, 0);
async([this] {
if (m_loader) {
@ -69,7 +98,7 @@ void StreamWindow::setup_stream() {
void StreamWindow::draw(NVGcontext *ctx) {
nvgSave(ctx);
gl_render_setup(1280, 720);
gl_render_setup(width(), height());
if (frame != NULL) {
gl_render_draw(frame->data);
@ -77,23 +106,36 @@ void StreamWindow::draw(NVGcontext *ctx) {
nvgRestore(ctx);
if (m_connection_status_is_poor) {
nvgFillColor(ctx, Color(255, 255, 255, 200));
nvgFontSize(ctx, 20);
nvgFontFace(ctx, "icons");
nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgText(ctx, 20, height() - 30, utf8(FA_EXCLAMATION_TRIANGLE).data(), NULL);
nvgFontFace(ctx, "sans-bold");
nvgText(ctx, 50, height() - 28, "Bad connection...", NULL);
}
// TODO: Get out of here...
if (keyboard_state[RETROK_q]) {
LiStopConnection();
async([this]{
if (m_loader) {
m_loader->dispose();
m_loader = NULL;
}
auto app = static_cast<Application *>(screen());
app->pop_window();
async([this] {
this->terminate();
});
}
LiSendControllerEvent(
game_pad_state.buttonFlags,
game_pad_state.leftTrigger,
game_pad_state.rightTrigger,
game_pad_state.leftStickX,
game_pad_state.leftStickY,
game_pad_state.rightStickX,
game_pad_state.rightStickY
);
}
bool StreamWindow::mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) {
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
if (button == 0) {
if (down && !pressed) {
start_mouse_x = p.x();
@ -117,11 +159,18 @@ bool StreamWindow::mouse_button_event(const nanogui::Vector2i &p, int button, bo
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
}
#else
if (button == 0) {
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} else if (button == 1) {
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
#endif
return true;
}
bool StreamWindow::mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
#if defined(__LAKKA_SWITCH__) || defined(__APPLE__)
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
if (pressed) {
current_mouse_x = std::min(std::max(current_mouse_x + p.x() - start_mouse_x, 0), width());
current_mouse_y = std::min(std::max(current_mouse_y + p.y() - start_mouse_y, 0), height());
@ -136,3 +185,16 @@ bool StreamWindow::mouse_motion_event(const Vector2i &p, const Vector2i &rel, in
#endif
return true;
}
void StreamWindow::terminate() {
if (m_loader) {
m_loader->dispose();
m_loader = NULL;
}
GameStreamClient::client()->quit(m_address, [](auto _) {});
LiStopConnection();
auto app = static_cast<Application *>(screen());
app->pop_window();
}

View file

@ -14,9 +14,12 @@ public:
bool mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) override;
bool mouse_motion_event(const nanogui::Vector2i &p, const nanogui::Vector2i &rel, int button, int modifiers) override;
void terminate();
private:
std::string m_address;
int m_app_id;
STREAM_CONFIGURATION m_config;
LoadingOverlay* m_loader;
bool m_connection_status_is_poor;
};