Example #1
0
 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);
}
Example #3
0
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;
  }
}