Basic streaming and mouse input works

This commit is contained in:
Cameron Gutman 2016-02-13 07:19:57 -05:00
parent 27fa24cfbc
commit 7ea534c692
5 changed files with 196 additions and 5 deletions

View File

@ -22,6 +22,7 @@ SOURCES = \
main.cpp \ main.cpp \
input.cpp \ input.cpp \
gamepad.cpp \ gamepad.cpp \
connectionlistener.cpp \
# Build rules generated by macros from common.mk: # Build rules generated by macros from common.mk:

49
connectionlistener.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "moonlight.hpp"
#include "ppapi/c/ppb_input_event.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/mouse_lock.h"
void MoonlightInstance::ClStageStarting(int stage) {
pp::Var response(std::string("Starting ") + std::string(LiGetStageName(stage)) + std::string("..."));
g_Instance->PostMessage(response);
}
void MoonlightInstance::ClStageFailed(int stage, long errorCode) {
pp::Var response(std::string("Starting ") + std::string(LiGetStageName(stage)) + std::string("failed"));
g_Instance->PostMessage(response);
}
void MoonlightInstance::ClConnectionStarted(void) {
pp::Module::Get()->core()->CallOnMainThread(0,
g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::OnConnectionStarted));
}
void MoonlightInstance::ClConnectionTerminated(long errorCode) {
pp::Module::Get()->core()->CallOnMainThread(0,
g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::OnConnectionStopped), (uint32_t)errorCode);
pp::Var response("Connection terminated");
g_Instance->PostMessage(response);
}
void MoonlightInstance::ClDisplayMessage(char* message) {
pp::Var response(message);
g_Instance->PostMessage(response);
}
void MoonlightInstance::ClDisplayTransientMessage(char* message) {
pp::Var response(message);
g_Instance->PostMessage(response);
}
CONNECTION_LISTENER_CALLBACKS MoonlightInstance::s_ClCallbacks = {
MoonlightInstance::ClStageStarting,
NULL,
MoonlightInstance::ClStageFailed,
MoonlightInstance::ClConnectionStarted,
MoonlightInstance::ClConnectionTerminated,
MoonlightInstance::ClDisplayMessage,
MoonlightInstance::ClDisplayTransientMessage
};

View File

@ -19,12 +19,28 @@ static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
} }
} }
void MoonlightInstance::DidLockMouse(int32_t result) {
m_MouseLocked = (result == PP_OK);
}
void MoonlightInstance::MouseLockLost() {
m_MouseLocked = false;
}
bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) { bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
switch (event.GetType()) { switch (event.GetType()) {
case PP_INPUTEVENT_TYPE_MOUSEDOWN: { case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
// Lock the mouse cursor when the user clicks on the stream
if (!m_MouseLocked) {
g_Instance->LockMouse(g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::DidLockMouse));
// Assume it worked until we get a callback telling us otherwise
m_MouseLocked = true;
}
pp::MouseInputEvent mouseEvent(event); pp::MouseInputEvent mouseEvent(event);
LiSendMouseButtonEvent(ConvertPPButtonToLiButton(mouseEvent.GetButton()), BUTTON_ACTION_PRESS); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, ConvertPPButtonToLiButton(mouseEvent.GetButton()));
return true; return true;
} }
@ -39,7 +55,7 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
case PP_INPUTEVENT_TYPE_MOUSEUP: { case PP_INPUTEVENT_TYPE_MOUSEUP: {
pp::MouseInputEvent mouseEvent(event); pp::MouseInputEvent mouseEvent(event);
LiSendMouseButtonEvent(ConvertPPButtonToLiButton(mouseEvent.GetButton()), BUTTON_ACTION_RELEASE); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, ConvertPPButtonToLiButton(mouseEvent.GetButton()));
return true; return true;
} }

View File

@ -1,5 +1,15 @@
#include "moonlight.hpp" #include "moonlight.hpp"
#include <pthread.h>
#include <stdio.h>
#include "ppapi/cpp/input_event.h"
static char s_Host[256];
static STREAM_CONFIGURATION s_StreamConfig;
MoonlightInstance* g_Instance;
MoonlightInstance::~MoonlightInstance() {} MoonlightInstance::~MoonlightInstance() {}
class MoonlightModule : public pp::Module { class MoonlightModule : public pp::Module {
@ -12,6 +22,81 @@ class MoonlightModule : public pp::Module {
} }
}; };
void MoonlightInstance::OnConnectionStarted(uint32_t unused) {
printf("Connection started\n");
// Start receiving input events
g_Instance->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
g_Instance->RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_KEYBOARD);
}
void MoonlightInstance::OnConnectionStopped(uint32_t error) {
// Stop receiving input events
g_Instance->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_KEYBOARD);
// Unlock the mouse
g_Instance->UnlockMouse();
}
void* MoonlightInstance::ConnectionThreadFunc(void* context) {
MoonlightInstance* me = (MoonlightInstance*)context;
int err;
err = LiStartConnection(s_Host,
&s_StreamConfig,
&MoonlightInstance::s_ClCallbacks,
NULL, NULL,
NULL, 0, 4);
if (err != 0) {
pp::Var response("Starting connection failed");
g_Instance->PostMessage(response);
return NULL;
}
for (;;) {
me->PollGamepads();
}
return NULL;
}
void MoonlightInstance::HandleMessage(const pp::Var& var_message) {
// Ignore the message if it is not a string.
if (!var_message.is_string())
return;
std::string host = var_message.AsString();
// Populate the stream configuration
LiInitializeStreamConfiguration(&s_StreamConfig);
s_StreamConfig.width = 1280;
s_StreamConfig.height = 720;
s_StreamConfig.fps = 30;
s_StreamConfig.bitrate = 10; // megabits per second
s_StreamConfig.packetSize = 1024;
s_StreamConfig.streamingRemotely = 0;
s_StreamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
// Store the host
host = host.substr(host.find(":") + 1);
strcpy(s_Host, host.c_str());
// Post a status update before we begin
pp::Var response("Starting connection...");
PostMessage(response);
// Start the worker thread to establish the connection
pthread_t t;
pthread_create(&t, NULL, MoonlightInstance::ConnectionThreadFunc, this);
}
bool MoonlightInstance::Init(uint32_t argc,
const char* argn[],
const char* argv[]) {
g_Instance = this;
return true;
}
namespace pp { namespace pp {
Module* CreateModule() { Module* CreateModule() {
return new MoonlightModule(); return new MoonlightModule();

View File

@ -1,14 +1,23 @@
#include "ppapi/cpp/instance.h" #include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h" #include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h" #include "ppapi/cpp/var.h"
#include "ppapi/cpp/mouse_lock.h"
#include "ppapi/c/ppb_gamepad.h" #include "ppapi/c/ppb_gamepad.h"
#include "ppapi/utility/completion_callback_factory.h"
#include "nacl_io/nacl_io.h" #include "nacl_io/nacl_io.h"
class MoonlightInstance : public pp::Instance { #include <Limelight.h>
class MoonlightInstance : public pp::Instance, public pp::MouseLock {
public: public:
explicit MoonlightInstance(PP_Instance instance) : pp::Instance(instance) { explicit MoonlightInstance(PP_Instance instance) :
pp::Instance(instance),
pp::MouseLock(this),
m_CallbackFactory(this),
m_MouseLocked(false) {
// This function MUST be used otherwise sockets don't work (nacl_io_init() doesn't work!) // This function MUST be used otherwise sockets don't work (nacl_io_init() doesn't work!)
nacl_io_init_ppapi(pp_instance(), pp::Module::Get()->get_browser_interface()); nacl_io_init_ppapi(pp_instance(), pp::Module::Get()->get_browser_interface());
@ -17,11 +26,42 @@ class MoonlightInstance : public pp::Instance {
virtual ~MoonlightInstance(); virtual ~MoonlightInstance();
bool Init(uint32_t argc, const char* argn[], const char* argv[]);
void HandleMessage(const pp::Var& var_message);
bool HandleInputEvent(const pp::InputEvent& event); bool HandleInputEvent(const pp::InputEvent& event);
void PollGamepads(); void PollGamepads();
void DidLockMouse(int32_t result);
void MouseLockLost();
void OnConnectionStopped(uint32_t unused);
void OnConnectionStarted(uint32_t error);
static void* ConnectionThreadFunc(void* context);
static void ClStageStarting(int stage);
static void ClStageFailed(int stage, long errorCode);
static void ClConnectionStarted(void);
static void ClConnectionTerminated(long errorCode);
static void ClDisplayMessage(char* message);
static void ClDisplayTransientMessage(char* message);
private: private:
double m_LastPadTimestamps[4]; double m_LastPadTimestamps[4];
const PPB_Gamepad* m_GamepadApi; const PPB_Gamepad* m_GamepadApi;
static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks;
pp::CompletionCallbackFactory<MoonlightInstance> m_CallbackFactory;
bool m_MouseLocked;
}; };
extern MoonlightInstance* g_Instance;