explicit MoonlightInstance(PP_Instance instance) : pp::Instance(instance), pp::MouseLock(this), m_IsPainting(false), m_RequestIdrFrame(false), m_OpusDecoder(NULL), m_CallbackFactory(this), m_MouseLocked(false), m_KeyModifiers(0), m_WaitingForAllModifiersUp(false), m_AccumulatedTicks(0), openHttpThread(this) { // 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()); LiInitializeStreamConfiguration(&m_StreamConfig); pp::TextInputController(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE); m_GamepadApi = static_cast<const PPB_Gamepad*>(pp::Module::Get()->GetBrowserInterface(PPB_GAMEPAD_INTERFACE)); openHttpThread.Start(); }
void MoonlightInstance::HandleStartStream(int32_t callbackId, pp::VarArray args) { std::string host = args.Get(0).AsString(); std::string width = args.Get(1).AsString(); std::string height = args.Get(2).AsString(); std::string fps = args.Get(3).AsString(); std::string bitrate = args.Get(4).AsString(); std::string rikey = args.Get(5).AsString(); std::string rikeyid = args.Get(6).AsString(); std::string appversion = args.Get(7).AsString(); pp::Var response("Setting stream width to: " + width); PostMessage(response); response = ("Setting stream height to: " + height); PostMessage(response); response = ("Setting stream fps to: " + fps); PostMessage(response); response = ("Setting stream host to: " + host); PostMessage(response); response = ("Setting stream bitrate to: " + bitrate); PostMessage(response); response = ("Setting rikey to: " + rikey); PostMessage(response); response = ("Setting rikeyid to: " + rikeyid); PostMessage(response); response = ("Setting appversion to: " + appversion); PostMessage(response); // Populate the stream configuration LiInitializeStreamConfiguration(&m_StreamConfig); m_StreamConfig.width = stoi(width); m_StreamConfig.height = stoi(height); m_StreamConfig.fps = stoi(fps); m_StreamConfig.bitrate = stoi(bitrate); // kilobits per second m_StreamConfig.streamingRemotely = 0; m_StreamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO; // The overhead of receiving a packet is much higher in NaCl because we must // pass through various layers of abstraction on each recv() call. We're using a // higher than normal default video packet size here to reduce CPU cycles wasted // receiving packets. The possible cost is greater network losses. m_StreamConfig.packetSize = 1392; // Load the rikey and rikeyid into the stream configuration hexStringToBytes(rikey.c_str(), m_StreamConfig.remoteInputAesKey); int rikeyiv = htonl(stoi(rikeyid)); memcpy(m_StreamConfig.remoteInputAesIv, &rikeyiv, sizeof(rikeyiv)); // Store the parameters from the start message m_Host = host; m_AppVersion = appversion; // Initialize the rendering surface before starting the connection if (InitializeRenderingSurface(m_StreamConfig.width, m_StreamConfig.height)) { // Start the worker thread to establish the connection pthread_create(&m_ConnectionThread, NULL, MoonlightInstance::ConnectionThreadFunc, this); } else { // Failed to initialize renderer OnConnectionStopped(0); } pp::VarDictionary ret; ret.Set("callbackId", pp::Var(callbackId)); ret.Set("type", pp::Var("resolve")); ret.Set("ret", pp::VarDictionary()); PostMessage(ret); }
void config_parse(int argc, char* argv[], PCONFIGURATION config) { LiInitializeStreamConfiguration(&config->stream); config->stream.width = 1280; config->stream.height = 720; config->stream.fps = -1; config->stream.bitrate = -1; config->stream.packetSize = 1024; config->stream.streamingRemotely = 0; config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO; config->stream.supportsHevc = false; config->debug_level = 0; config->platform = "auto"; config->app = "Steam"; config->action = NULL; config->address = NULL; config->config_file = NULL; config->audio_device = NULL; config->sops = true; config->localaudio = false; config->fullscreen = true; config->unsupported = false; config->codec = CODEC_UNSPECIFIED; config->inputsCount = 0; config->mapping = get_path("gamecontrollerdb.txt", getenv("XDG_DATA_DIRS")); config->key_dir[0] = 0; char* config_file = get_path("moonlight.conf", "/etc"); if (config_file) config_file_parse(config_file, config); if (argc == 2 && access(argv[1], F_OK) == 0) { config->action = "stream"; if (!config_file_parse(argv[1], config)) exit(EXIT_FAILURE); } else { int option_index = 0; int c; while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:no:p:q:r:stuv:w:xy", long_options, &option_index)) != -1) { parse_argument(c, optarg, config); } } if (config->config_file != NULL) config_save(config->config_file, config); if (config->key_dir[0] == 0x0) { struct passwd *pw = getpwuid(getuid()); const char *dir; if ((dir = getenv("XDG_CACHE_DIR")) != NULL) sprintf(config->key_dir, "%s" MOONLIGHT_PATH, dir); else if ((dir = getenv("HOME")) != NULL) sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir); else sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir); } if (config->stream.fps == -1) config->stream.fps = config->stream.height >= 1080 ? 30 : 60; if (config->stream.bitrate == -1) { if (config->stream.height >= 1080 && config->stream.fps >= 60) config->stream.bitrate = 20000; else if (config->stream.height >= 1080 || config->stream.fps >= 60) config->stream.bitrate = 10000; else config->stream.bitrate = 5000; } }