Esempio n. 1
0
static bool audio_thread_start(void *data)
{
   audio_thread_t *thr = (audio_thread_t*)data;

   if (!thr)
      return false;

   audio_driver_ctl(RARCH_AUDIO_CTL_SET_CALLBACK_ENABLE, NULL);

   thr->is_paused = false;
   audio_thread_unblock(thr);

   return true;
}
Esempio n. 2
0
static void audio_thread_loop(void *data)
{
   audio_thread_t *thr = (audio_thread_t*)data;

   if (!thr)
      return;

   RARCH_LOG("[Audio Thread]: Initializing audio driver.\n");
   thr->driver_data   = thr->driver->init(thr->device, thr->out_rate, thr->latency);
   slock_lock(thr->lock);
   thr->inited        = thr->driver_data ? 1 : -1;
   if (thr->inited > 0 && thr->driver->use_float)
      thr->use_float  = thr->driver->use_float(thr->driver_data);
   scond_signal(thr->cond);
   slock_unlock(thr->lock);

   if (thr->inited < 0)
      return;

   /* Wait until we start to avoid calling 
    * stop immediately after initialization. */
   slock_lock(thr->lock);
   while (thr->stopped)
      scond_wait(thr->cond, thr->lock);
   slock_unlock(thr->lock);

   RARCH_LOG("[Audio Thread]: Starting audio.\n");

   for (;;)
   {
      slock_lock(thr->lock);

      if (!thr->alive)
      {
         scond_signal(thr->cond);
         slock_unlock(thr->lock);
         thr->stopped_ack = true;
         break;
      }

      if (thr->stopped)
      {
         thr->driver->stop(thr->driver_data);
         while (thr->stopped)
         {
            /* If we stop right after start, we might not be able to properly ack.
             * Signal in the loop instead. */
            thr->stopped_ack = true;
            scond_signal(thr->cond);

            scond_wait(thr->cond, thr->lock);
         }
         thr->driver->start(thr->driver_data);
      }

      slock_unlock(thr->lock);
      audio_driver_ctl(RARCH_AUDIO_CTL_CALLBACK, NULL);
   }

   RARCH_LOG("[Audio Thread]: Tearing down driver.\n");
   thr->driver->free(thr->driver_data);
}
Esempio n. 3
0
/**
 * event_cmd_ctl:
 * @cmd                  : Event command index.
 *
 * Performs program event command with index @cmd.
 *
 * Returns: true (1) on success, otherwise false (0).
 **/
bool event_cmd_ctl(enum event_command cmd, void *data)
{
   unsigned i                = 0;
   bool boolean              = false;
   settings_t *settings      = config_get_ptr();
   rarch_system_info_t *info = NULL;

   runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info);

   (void)i;

   switch (cmd)
   {
      case EVENT_CMD_MENU_REFRESH:
#ifdef HAVE_MENU
         menu_driver_ctl(RARCH_MENU_CTL_REFRESH, NULL);
#endif
         break;
      case EVENT_CMD_SET_PER_GAME_RESOLUTION:
#if defined(GEKKO)
         {
            unsigned width = 0, height = 0;

            event_cmd_ctl(EVENT_CMD_VIDEO_SET_ASPECT_RATIO, NULL);

            if (video_driver_get_video_output_size(&width, &height))
            {
               char msg[128] = {0};

               video_driver_set_video_mode(width, height, true);

               if (width == 0 || height == 0)
                  strlcpy(msg, "Resolution: DEFAULT", sizeof(msg));
               else
                  snprintf(msg, sizeof(msg),"Resolution: %dx%d",width, height);
               runloop_msg_queue_push(msg, 1, 100, true);
            }
         }
#endif
         break;
      case EVENT_CMD_LOAD_CONTENT_PERSIST:
#ifdef HAVE_DYNAMIC
         event_cmd_ctl(EVENT_CMD_LOAD_CORE, NULL);
#endif
         rarch_ctl(RARCH_CTL_LOAD_CONTENT, NULL);
         break;
#ifdef HAVE_FFMPEG
      case EVENT_CMD_LOAD_CONTENT_FFMPEG:
         rarch_ctl(RARCH_CTL_LOAD_CONTENT_FFMPEG, NULL);
         break;
#endif
      case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER:
         rarch_ctl(RARCH_CTL_LOAD_CONTENT_IMAGEVIEWER, NULL);
         break;
      case EVENT_CMD_LOAD_CONTENT:
         {
#ifdef HAVE_DYNAMIC
            event_cmd_ctl(EVENT_CMD_LOAD_CONTENT_PERSIST, NULL);
#else
            char *fullpath = NULL;
            runloop_ctl(RUNLOOP_CTL_GET_CONTENT_PATH, &fullpath);
            runloop_ctl(RUNLOOP_CTL_SET_LIBRETRO_PATH, settings->libretro);
            event_cmd_ctl(EVENT_CMD_EXEC, (void*)fullpath);
            event_cmd_ctl(EVENT_CMD_QUIT, NULL);
#endif
         }
         break;
      case EVENT_CMD_LOAD_CORE_DEINIT:
#ifdef HAVE_MENU
         menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_DEINIT, NULL);
#endif
         break;
      case EVENT_CMD_LOAD_CORE_PERSIST:
         event_cmd_ctl(EVENT_CMD_LOAD_CORE_DEINIT, NULL);
         {
#ifdef HAVE_MENU
            bool *ptr = NULL;
            struct retro_system_info *system = NULL;

            menu_driver_ctl(RARCH_MENU_CTL_SYSTEM_INFO_GET, &system);

            if (menu_driver_ctl(RARCH_MENU_CTL_LOAD_NO_CONTENT_GET, &ptr))
            {
               core_info_ctx_find_t info_find;

#if defined(HAVE_DYNAMIC)
               if (!(*settings->libretro))
                  return false;

               libretro_get_system_info(settings->libretro, system,
                     ptr);
#endif
               info_find.path = settings->libretro;

               if (!core_info_ctl(CORE_INFO_CTL_LOAD, &info_find))
                  return false;
            }
#endif
         }
         break;
      case EVENT_CMD_LOAD_CORE:
         event_cmd_ctl(EVENT_CMD_LOAD_CORE_PERSIST, NULL);
#ifndef HAVE_DYNAMIC
         event_cmd_ctl(EVENT_CMD_QUIT, NULL);
#endif
         break;
      case EVENT_CMD_LOAD_STATE:
         /* Immutable - disallow savestate load when
          * we absolutely cannot change game state. */
         if (bsv_movie_ctl(BSV_MOVIE_CTL_IS_INITED, NULL))
            return false;

#ifdef HAVE_NETPLAY
         if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
            return false;
#endif

#ifdef HAVE_CHEEVOS
         if (settings->cheevos.hardcore_mode_enable)
            return false;
#endif

         event_main_state(cmd);
         break;
      case EVENT_CMD_RESIZE_WINDOWED_SCALE:
         {
            unsigned idx = 0;
            unsigned *window_scale = NULL;

            runloop_ctl(RUNLOOP_CTL_GET_WINDOWED_SCALE, &window_scale);

            if (*window_scale == 0)
               return false;

            settings->video.scale = *window_scale;

            if (!settings->video.fullscreen)
               event_cmd_ctl(EVENT_CMD_REINIT, NULL);

            runloop_ctl(RUNLOOP_CTL_SET_WINDOWED_SCALE, &idx);
         }
         break;
      case EVENT_CMD_MENU_TOGGLE:
#ifdef HAVE_MENU
         if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL))
            rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
         else
            rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL);
#endif
         break;
      case EVENT_CMD_CONTROLLERS_INIT:
         event_init_controllers();
         break;
      case EVENT_CMD_RESET:
         RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET));
         runloop_msg_queue_push(msg_hash_to_str(MSG_RESET), 1, 120, true);

#ifdef HAVE_CHEEVOS
         cheevos_ctl(CHEEVOS_CTL_SET_CHEATS, NULL);
#endif
         core_ctl(CORE_CTL_RETRO_RESET, NULL);
         break;
      case EVENT_CMD_SAVE_STATE:
#ifdef HAVE_CHEEVOS
         if (settings->cheevos.hardcore_mode_enable)
            return false;
#endif

         if (settings->savestate_auto_index)
            settings->state_slot++;

         event_main_state(cmd);
         break;
      case EVENT_CMD_SAVE_STATE_DECREMENT:
         /* Slot -1 is (auto) slot. */
         if (settings->state_slot >= 0)
            settings->state_slot--;
         break;
      case EVENT_CMD_SAVE_STATE_INCREMENT:
         settings->state_slot++;
         break;
      case EVENT_CMD_TAKE_SCREENSHOT:
         if (!take_screenshot())
            return false;
         break;
      case EVENT_CMD_UNLOAD_CORE:
         runloop_ctl(RUNLOOP_CTL_PREPARE_DUMMY, NULL);
         event_cmd_ctl(EVENT_CMD_LOAD_CORE_DEINIT, NULL);
         break;
      case EVENT_CMD_QUIT:
         rarch_ctl(RARCH_CTL_QUIT, NULL);
         break;
      case EVENT_CMD_CHEEVOS_HARDCORE_MODE_TOGGLE:
#ifdef HAVE_CHEEVOS
         cheevos_ctl(CHEEVOS_CTL_TOGGLE_HARDCORE_MODE, NULL);
#endif
         break;
      case EVENT_CMD_REINIT:
         {
            struct retro_hw_render_callback *hwr = NULL;
            video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr);

            if (hwr->cache_context)
               video_driver_ctl(
                     RARCH_DISPLAY_CTL_SET_VIDEO_CACHE_CONTEXT, NULL);
            else
               video_driver_ctl(
                     RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL);

            video_driver_ctl(
                  RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT_ACK, NULL);
            event_cmd_ctl(EVENT_CMD_RESET_CONTEXT, NULL);
            video_driver_ctl(
                  RARCH_DISPLAY_CTL_UNSET_VIDEO_CACHE_CONTEXT, NULL);

            /* Poll input to avoid possibly stale data to corrupt things. */
            input_driver_ctl(RARCH_INPUT_CTL_POLL, NULL);

#ifdef HAVE_MENU
            menu_display_ctl(
                  MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL);

            if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL))
               event_cmd_ctl(EVENT_CMD_VIDEO_SET_BLOCKING_STATE, NULL);
#endif
         }
         break;
      case EVENT_CMD_CHEATS_DEINIT:
         cheat_manager_state_free();
         break;
      case EVENT_CMD_CHEATS_INIT:
         event_cmd_ctl(EVENT_CMD_CHEATS_DEINIT, NULL);
         event_init_cheats();
         break;
      case EVENT_CMD_CHEATS_APPLY:
         cheat_manager_apply_cheats();
         break;
      case EVENT_CMD_REWIND_DEINIT:
#ifdef HAVE_NETPLAY
         if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
            return false;
#endif
#ifdef HAVE_CHEEVOS
         if (settings->cheevos.hardcore_mode_enable)
            return false;
#endif

         state_manager_event_deinit();
         break;
      case EVENT_CMD_REWIND_INIT:
#ifdef HAVE_CHEEVOS
         if (settings->cheevos.hardcore_mode_enable)
            return false;
#endif
#ifdef HAVE_NETPLAY
         if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
#endif
            init_rewind();
         break;
      case EVENT_CMD_REWIND_TOGGLE:
         if (settings->rewind_enable)
            event_cmd_ctl(EVENT_CMD_REWIND_INIT, NULL);
         else
            event_cmd_ctl(EVENT_CMD_REWIND_DEINIT, NULL);
         break;
      case EVENT_CMD_AUTOSAVE_DEINIT:
#ifdef HAVE_THREADS
         autosave_event_deinit();
#endif
         break;
      case EVENT_CMD_AUTOSAVE_INIT:
         event_cmd_ctl(EVENT_CMD_AUTOSAVE_DEINIT, NULL);
#ifdef HAVE_THREADS
         autosave_event_init();
#endif
         break;
      case EVENT_CMD_AUTOSAVE_STATE:
         event_save_auto_state();
         break;
      case EVENT_CMD_AUDIO_STOP:
         if (!audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL))
            return false;

         if (!audio_driver_ctl(RARCH_AUDIO_CTL_STOP, NULL))
            return false;
         break;
      case EVENT_CMD_AUDIO_START:
         if (audio_driver_ctl(RARCH_AUDIO_CTL_ALIVE, NULL))
            return false;

         if (!settings->audio.mute_enable && 
               !audio_driver_ctl(RARCH_AUDIO_CTL_START, NULL))
         {
            RARCH_ERR("Failed to start audio driver. "
                  "Will continue without audio.\n");
            audio_driver_ctl(RARCH_AUDIO_CTL_UNSET_ACTIVE, NULL);
         }
         break;
      case EVENT_CMD_AUDIO_MUTE_TOGGLE:
         {
            const char *msg = !settings->audio.mute_enable ?
               msg_hash_to_str(MSG_AUDIO_MUTED):
               msg_hash_to_str(MSG_AUDIO_UNMUTED);

            if (!audio_driver_ctl(RARCH_AUDIO_CTL_MUTE_TOGGLE, NULL))
            {
               RARCH_ERR("%s.\n",
                     msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO));
               return false;
            }

            runloop_msg_queue_push(msg, 1, 180, true);
            RARCH_LOG("%s\n", msg);
         }
         break;
      case EVENT_CMD_OVERLAY_DEINIT:
#ifdef HAVE_OVERLAY
         input_overlay_free();
#endif
         break;
      case EVENT_CMD_OVERLAY_INIT:
         event_cmd_ctl(EVENT_CMD_OVERLAY_DEINIT, NULL);
#ifdef HAVE_OVERLAY
         input_overlay_init();
#endif
         break;
      case EVENT_CMD_OVERLAY_NEXT:
#ifdef HAVE_OVERLAY
         input_overlay_next(settings->input.overlay_opacity);
#endif
         break;
      case EVENT_CMD_DSP_FILTER_DEINIT:
         audio_driver_dsp_filter_free();
         break;
      case EVENT_CMD_DSP_FILTER_INIT:
         event_cmd_ctl(EVENT_CMD_DSP_FILTER_DEINIT, NULL);
         if (!*settings->audio.dsp_plugin)
            break;
         audio_driver_dsp_filter_init(settings->audio.dsp_plugin);
         break;
      case EVENT_CMD_GPU_RECORD_DEINIT:
         video_driver_ctl(RARCH_DISPLAY_CTL_GPU_RECORD_DEINIT, NULL);
         break;
      case EVENT_CMD_RECORD_DEINIT:
         if (!recording_deinit())
            return false;
         break;
      case EVENT_CMD_RECORD_INIT:
         event_cmd_ctl(EVENT_CMD_HISTORY_DEINIT, NULL);
         if (!recording_init())
            return false;
         break;
      case EVENT_CMD_HISTORY_DEINIT:
         if (g_defaults.history)
         {
            content_playlist_write_file(g_defaults.history);
            content_playlist_free(g_defaults.history);
         }
         g_defaults.history = NULL;
         break;
      case EVENT_CMD_HISTORY_INIT:
         event_cmd_ctl(EVENT_CMD_HISTORY_DEINIT, NULL);
         if (!settings->history_list_enable)
            return false;
         RARCH_LOG("%s: [%s].\n",
               msg_hash_to_str(MSG_LOADING_HISTORY_FILE),
               settings->content_history_path);
         g_defaults.history = content_playlist_init(
               settings->content_history_path,
               settings->content_history_size);
         break;
      case EVENT_CMD_CORE_INFO_DEINIT:
         core_info_ctl(CORE_INFO_CTL_LIST_DEINIT, NULL);
         break;
      case EVENT_CMD_CORE_INFO_INIT:
         event_cmd_ctl(EVENT_CMD_CORE_INFO_DEINIT, NULL);

         if (*settings->libretro_directory)
            core_info_ctl(CORE_INFO_CTL_LIST_INIT, NULL);
         break;
      case EVENT_CMD_CORE_DEINIT:
         {
            struct retro_hw_render_callback *hwr = NULL;
            video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr);
            event_deinit_core(true);

            if (hwr)
               memset(hwr, 0, sizeof(*hwr));

            break;
         }
      case EVENT_CMD_CORE_INIT:
         if (!event_init_core(data))
            return false;
         break;
      case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES:
         video_driver_ctl(RARCH_DISPLAY_CTL_APPLY_STATE_CHANGES, NULL);
         break;
      case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE:
         boolean = true; /* fall-through */
      case EVENT_CMD_VIDEO_SET_BLOCKING_STATE:
         video_driver_ctl(RARCH_DISPLAY_CTL_SET_NONBLOCK_STATE, &boolean);
         break;
      case EVENT_CMD_VIDEO_SET_ASPECT_RATIO:
         video_driver_ctl(RARCH_DISPLAY_CTL_SET_ASPECT_RATIO, NULL);
         break;
      case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE:
         boolean = true; /* fall-through */
      case EVENT_CMD_AUDIO_SET_BLOCKING_STATE:
         audio_driver_set_nonblocking_state(boolean);
         break;
      case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR:
#ifdef HAVE_OVERLAY
         input_overlay_set_scale_factor(settings->input.overlay_scale);
#endif
         break;
      case EVENT_CMD_OVERLAY_SET_ALPHA_MOD:
#ifdef HAVE_OVERLAY
         input_overlay_set_alpha_mod(settings->input.overlay_opacity);
#endif
         break;
      case EVENT_CMD_AUDIO_REINIT:
         {
            int flags = DRIVER_AUDIO;
            driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags);
            driver_ctl(RARCH_DRIVER_CTL_INIT, &flags);
         }
         break;
      case EVENT_CMD_RESET_CONTEXT:
         {
            /* RARCH_DRIVER_CTL_UNINIT clears the callback struct so we
             * need to make sure to keep a copy */
            struct retro_hw_render_callback *hwr = NULL;
            struct retro_hw_render_callback hwr_copy;
            int flags = DRIVERS_CMD_ALL;

            video_driver_ctl(RARCH_DISPLAY_CTL_HW_CONTEXT_GET, &hwr);

            memcpy(&hwr_copy, hwr, sizeof(hwr_copy));

            driver_ctl(RARCH_DRIVER_CTL_UNINIT, &flags);

            memcpy(hwr, &hwr_copy, sizeof(*hwr));

            driver_ctl(RARCH_DRIVER_CTL_INIT, &flags);
         }
         break;
      case EVENT_CMD_QUIT_RETROARCH:
         rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL);
         break;
      case EVENT_CMD_SHUTDOWN:
#if defined(__linux__) && !defined(ANDROID)
         runloop_msg_queue_push("Shutting down...", 1, 180, true);
         rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL);
         system("shutdown -P now");
#endif
         break;
      case EVENT_CMD_REBOOT:
#if defined(__linux__) && !defined(ANDROID)
         runloop_msg_queue_push("Rebooting...", 1, 180, true);
         rarch_ctl(RARCH_CTL_FORCE_QUIT, NULL);
         system("shutdown -r now");
#endif
         break;
      case EVENT_CMD_RESUME:
         rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL);
         if (ui_companion_is_on_foreground())
            ui_companion_driver_toggle();
         break;
      case EVENT_CMD_RESTART_RETROARCH:
         if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART))
            return false;
         break;
      case EVENT_CMD_MENU_SAVE_CURRENT_CONFIG:
         event_save_current_config();
         break;
      case EVENT_CMD_MENU_SAVE_CONFIG:
         if (!event_save_core_config())
            return false;
         break;
      case EVENT_CMD_SHADERS_APPLY_CHANGES:
#ifdef HAVE_MENU
         menu_shader_manager_apply_changes();
#endif
         break;
      case EVENT_CMD_PAUSE_CHECKS:
         if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL))
         {
            RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED));
            event_cmd_ctl(EVENT_CMD_AUDIO_STOP, NULL);

            if (settings->video.black_frame_insertion)
               video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL);
         }
         else
         {
            RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED));
            event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL);
         }
         break;
      case EVENT_CMD_PAUSE_TOGGLE:
         boolean = runloop_ctl(RUNLOOP_CTL_IS_PAUSED,  NULL);
         boolean = !boolean;
         runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
         event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL);
         break;
      case EVENT_CMD_UNPAUSE:
         boolean = false;

         runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
         event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL);
         break;
      case EVENT_CMD_PAUSE:
         boolean = true;

         runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
         event_cmd_ctl(EVENT_CMD_PAUSE_CHECKS, NULL);
         break;
      case EVENT_CMD_MENU_PAUSE_LIBRETRO:
#ifdef HAVE_MENU
         if (menu_driver_ctl(RARCH_MENU_CTL_IS_ALIVE, NULL))
         {
            if (settings->menu.pause_libretro)
               event_cmd_ctl(EVENT_CMD_AUDIO_STOP, NULL);
            else
               event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL);
         }
         else
         {
            if (settings->menu.pause_libretro)
               event_cmd_ctl(EVENT_CMD_AUDIO_START, NULL);
         }
#endif
         break;
      case EVENT_CMD_SHADER_DIR_DEINIT:
         runloop_ctl(RUNLOOP_CTL_SHADER_DIR_DEINIT, NULL);
         break;
      case EVENT_CMD_SHADER_DIR_INIT:
         event_cmd_ctl(EVENT_CMD_SHADER_DIR_DEINIT, NULL);

         if (!runloop_ctl(RUNLOOP_CTL_SHADER_DIR_INIT, NULL))
            return false;
         break;
      case EVENT_CMD_SAVEFILES:
         {
            global_t  *global         = global_get_ptr();
            if (!global->savefiles || !global->sram.use)
               return false;

            for (i = 0; i < global->savefiles->size; i++)
            {
               ram_type_t ram;
               ram.type    = global->savefiles->elems[i].attr.i;
               ram.path    = global->savefiles->elems[i].data;

               RARCH_LOG("%s #%u %s \"%s\".\n",
                     msg_hash_to_str(MSG_SAVING_RAM_TYPE),
                     ram.type,
                     msg_hash_to_str(MSG_TO),
                     ram.path);
               content_ctl(CONTENT_CTL_SAVE_RAM_FILE, &ram);
            }
         }
         return true;
      case EVENT_CMD_SAVEFILES_DEINIT:
         {
            global_t  *global         = global_get_ptr();
            if (!global)
               break;

            if (global->savefiles)
               string_list_free(global->savefiles);
            global->savefiles = NULL;
         }
         break;
      case EVENT_CMD_SAVEFILES_INIT:
         {
            global_t  *global         = global_get_ptr();
            global->sram.use = global->sram.use && !global->sram.save_disable;
#ifdef HAVE_NETPLAY
            global->sram.use = global->sram.use && 
               (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)
                || !global->netplay.is_client);
#endif

            if (!global->sram.use)
               RARCH_LOG("%s\n",
                     msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED));

            if (global->sram.use)
               event_cmd_ctl(EVENT_CMD_AUTOSAVE_INIT, NULL);
         }
         break;
      case EVENT_CMD_BSV_MOVIE_DEINIT:
         bsv_movie_ctl(BSV_MOVIE_CTL_DEINIT, NULL);
         break;
      case EVENT_CMD_BSV_MOVIE_INIT:
         event_cmd_ctl(EVENT_CMD_BSV_MOVIE_DEINIT, NULL);
         bsv_movie_ctl(BSV_MOVIE_CTL_INIT, NULL);
         break;
      case EVENT_CMD_NETPLAY_DEINIT:
#ifdef HAVE_NETPLAY
         deinit_netplay();
#endif
         break;
      case EVENT_CMD_NETWORK_DEINIT:
#ifdef HAVE_NETWORKING
         network_deinit();
#endif
         break;
      case EVENT_CMD_NETWORK_INIT:
#ifdef HAVE_NETWORKING
         network_init();
#endif
         break;
      case EVENT_CMD_NETPLAY_INIT:
         event_cmd_ctl(EVENT_CMD_NETPLAY_DEINIT, NULL);
#ifdef HAVE_NETPLAY
         if (!init_netplay())
            return false;
#endif
         break;
      case EVENT_CMD_NETPLAY_FLIP_PLAYERS:
#ifdef HAVE_NETPLAY
         netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, NULL);
#endif
         break;
      case EVENT_CMD_FULLSCREEN_TOGGLE:
         if (!video_driver_ctl(RARCH_DISPLAY_CTL_HAS_WINDOWED, NULL))
            return false;

         /* If we go fullscreen we drop all drivers and
          * reinitialize to be safe. */
         settings->video.fullscreen = !settings->video.fullscreen;
         event_cmd_ctl(EVENT_CMD_REINIT, NULL);
         break;
      case EVENT_CMD_COMMAND_DEINIT:
         input_driver_ctl(RARCH_INPUT_CTL_COMMAND_DEINIT, NULL);
         break;
      case EVENT_CMD_COMMAND_INIT:
         event_cmd_ctl(EVENT_CMD_COMMAND_DEINIT, NULL);
         input_driver_ctl(RARCH_INPUT_CTL_COMMAND_INIT, NULL);
         break;
      case EVENT_CMD_REMOTE_DEINIT:
         input_driver_ctl(RARCH_INPUT_CTL_REMOTE_DEINIT, NULL);
         break;
      case EVENT_CMD_REMOTE_INIT:
         event_cmd_ctl(EVENT_CMD_REMOTE_DEINIT, NULL);
         input_driver_ctl(RARCH_INPUT_CTL_REMOTE_INIT, NULL);
         break;
      case EVENT_CMD_TEMPORARY_CONTENT_DEINIT:
         content_ctl(CONTENT_CTL_DEINIT, NULL);
         break;
      case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT:
         {
            global_t  *global         = global_get_ptr();
            if (!global)
               break;

            if (global->subsystem_fullpaths)
               string_list_free(global->subsystem_fullpaths);
            global->subsystem_fullpaths = NULL;
         }
         break;
      case EVENT_CMD_LOG_FILE_DEINIT:
         retro_main_log_file_deinit();
         break;
      case EVENT_CMD_DISK_APPEND_IMAGE:
         {
            const char *path = (const char*)data;
            if (string_is_empty(path))
               return false;
            return event_disk_control_append_image(path);
         }
      case EVENT_CMD_DISK_EJECT_TOGGLE:
         if (info && info->disk_control_cb.get_num_images)
         {
            const struct retro_disk_control_callback *control =
               (const struct retro_disk_control_callback*)
               &info->disk_control_cb;

            if (control)
            {
               bool new_state = !control->get_eject_state();
               event_disk_control_set_eject(new_state, true);
            }
         }
         else
            runloop_msg_queue_push(
                  msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
                  1, 120, true);
         break;
      case EVENT_CMD_DISK_NEXT:
         if (info && info->disk_control_cb.get_num_images)
         {
            const struct retro_disk_control_callback *control =
               (const struct retro_disk_control_callback*)
               &info->disk_control_cb;

            if (!control)
               return false;

            if (!control->get_eject_state())
               return false;

            event_check_disk_next(control);
         }
         else
            runloop_msg_queue_push(
                  msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
                  1, 120, true);
         break;
      case EVENT_CMD_DISK_PREV:
         if (info && info->disk_control_cb.get_num_images)
         {
            const struct retro_disk_control_callback *control =
               (const struct retro_disk_control_callback*)
               &info->disk_control_cb;

            if (!control)
               return false;

            if (!control->get_eject_state())
               return false;

            event_check_disk_prev(control);
         }
         else
            runloop_msg_queue_push(
                  msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS),
                  1, 120, true);
         break;
      case EVENT_CMD_RUMBLE_STOP:
         for (i = 0; i < MAX_USERS; i++)
         {
            input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0);
            input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0);
         }
         break;
      case EVENT_CMD_GRAB_MOUSE_TOGGLE:
         {
            bool ret = false;
            static bool grab_mouse_state  = false;

            grab_mouse_state = !grab_mouse_state;

            if (grab_mouse_state)
               ret = input_driver_ctl(RARCH_INPUT_CTL_GRAB_MOUSE, NULL);
            else
               ret = input_driver_ctl(RARCH_INPUT_CTL_UNGRAB_MOUSE, NULL);

            if (!ret)
               return false;

            RARCH_LOG("%s: %s.\n",
                  msg_hash_to_str(MSG_GRAB_MOUSE_STATE),
                  grab_mouse_state ? "yes" : "no");

            if (grab_mouse_state)
               video_driver_ctl(RARCH_DISPLAY_CTL_HIDE_MOUSE, NULL);
            else
               video_driver_ctl(RARCH_DISPLAY_CTL_SHOW_MOUSE, NULL);
         }
         break;
      case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG:
         rarch_perf_log();
         break;
      case EVENT_CMD_VOLUME_UP:
         event_set_volume(0.5f);
         break;
      case EVENT_CMD_VOLUME_DOWN:
         event_set_volume(-0.5f);
         break;
      case EVENT_CMD_SET_FRAME_LIMIT:
         runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL);
         break;
      case EVENT_CMD_EXEC:
         return event_cmd_exec(data);
      case EVENT_CMD_NONE:
      default:
         return false;
   }

   return true;
}
bool core_ctl(enum core_ctl_state state, void *data)
{
    static bool   has_set_input_descriptors = false;
    static struct retro_callbacks retro_ctx;

    switch (state)
    {
    case CORE_CTL_RETRO_CHEAT_SET:
    {
        retro_ctx_cheat_info_t *info = (retro_ctx_cheat_info_t*)data;
        core.retro_cheat_set(info->index, info->enabled, info->code);
    }
    break;
    case CORE_CTL_RETRO_CHEAT_RESET:
        core.retro_cheat_reset();
        break;
    case CORE_CTL_RETRO_API_VERSION:
    {
        retro_ctx_api_info_t *api = (retro_ctx_api_info_t*)data;
        api->version = core.retro_api_version();
    }
    break;
    case CORE_CTL_SET_POLL_TYPE:
    {
        unsigned *poll_type = (unsigned*)data;
        core_poll_type = *poll_type;
    }
    break;
    case CORE_CTL_RETRO_SYMBOLS_INIT:
    {
        enum rarch_core_type *core_type = (enum rarch_core_type*)data;

        if (!core_type)
            return false;
        init_libretro_sym(*core_type, &core);
    }
    break;
    case CORE_CTL_RETRO_SET_CONTROLLER_PORT_DEVICE:
    {
        retro_ctx_controller_info_t *pad = (retro_ctx_controller_info_t*)data;
        if (!pad)
            return false;
        core.retro_set_controller_port_device(pad->port, pad->device);
    }
    break;
    case CORE_CTL_RETRO_GET_MEMORY:
    {
        retro_ctx_memory_info_t *info = (retro_ctx_memory_info_t*)data;
        if (!info)
            return false;
        info->size  = core.retro_get_memory_size(info->id);
        info->data  = core.retro_get_memory_data(info->id);
    }
    break;
    case CORE_CTL_RETRO_LOAD_GAME:
    {
        retro_ctx_load_content_info_t *load_info =
            (retro_ctx_load_content_info_t*)data;
        if (!load_info)
            return false;

        if (load_info->special)
            return core.retro_load_game_special(load_info->special->id, load_info->info, load_info->content->size);
        return core.retro_load_game(*load_info->content->elems[0].data ? load_info->info : NULL);
    }
    case CORE_CTL_RETRO_GET_SYSTEM_INFO:
    {
        struct retro_system_info *system = (struct retro_system_info*)data;
        if (!system)
            return false;
        core.retro_get_system_info(system);
    }
    break;
    case CORE_CTL_RETRO_UNSERIALIZE:
    {
        retro_ctx_serialize_info_t *info = (retro_ctx_serialize_info_t*)data;
        if (!info)
            return false;
        if (!core.retro_unserialize(info->data_const, info->size))
            return false;
    }
    break;
    case CORE_CTL_RETRO_SERIALIZE:
    {
        retro_ctx_serialize_info_t *info = (retro_ctx_serialize_info_t*)data;
        if (!info)
            return false;
        if (!core.retro_serialize(info->data, info->size))
            return false;
    }
    break;
    case CORE_CTL_RETRO_SERIALIZE_SIZE:
    {
        retro_ctx_size_info_t *info = (retro_ctx_size_info_t *)data;
        if (!info)
            return false;
        info->size = core.retro_serialize_size();
    }
    break;
    case CORE_CTL_RETRO_CTX_FRAME_CB:
    {
        retro_ctx_frame_info_t *info = (retro_ctx_frame_info_t*)data;
        if (!info || !retro_ctx.frame_cb)
            return false;

        retro_ctx.frame_cb(
            info->data, info->width, info->height, info->pitch);
    }
    break;
    case CORE_CTL_RETRO_CTX_POLL_CB:
        if (!retro_ctx.poll_cb)
            return false;
        retro_ctx.poll_cb();
        break;
    case CORE_CTL_RETRO_SET_ENVIRONMENT:
    {
        retro_ctx_environ_info_t *info = (retro_ctx_environ_info_t*)data;
        if (!info)
            return false;
        core.retro_set_environment(info->env);
    }
    break;
    case CORE_CTL_RETRO_GET_SYSTEM_AV_INFO:
    {
        struct retro_system_av_info *av_info = (struct retro_system_av_info*)data;
        if (!av_info)
            return false;
        core.retro_get_system_av_info(av_info);
    }
    break;
    case CORE_CTL_RETRO_RESET:
        core.retro_reset();
        break;
    case CORE_CTL_RETRO_INIT:
        core.retro_init();
        break;
    case CORE_CTL_RETRO_DEINIT:
        core.retro_deinit();
        uninit_libretro_sym(&core);
        break;
    case CORE_CTL_RETRO_UNLOAD_GAME:
        video_driver_ctl(RARCH_DISPLAY_CTL_DEINIT_HW_CONTEXT, NULL);
        audio_driver_ctl(RARCH_AUDIO_CTL_STOP, NULL);
        core.retro_unload_game();
        break;
    case CORE_CTL_RETRO_RUN:
        switch (core_poll_type)
        {
        case POLL_TYPE_EARLY:
            input_poll();
            break;
        case POLL_TYPE_LATE:
            core_input_polled = false;
            break;
        }
        if (core.retro_run)
            core.retro_run();
        if (core_poll_type == POLL_TYPE_LATE && !core_input_polled)
            input_poll();
        break;
    case CORE_CTL_SET_CBS:
        return retro_set_default_callbacks(data);
    case CORE_CTL_SET_CBS_REWIND:
        retro_set_rewind_callbacks();
        break;
    case CORE_CTL_INIT:
    {
        settings_t *settings = config_get_ptr();
        core_poll_type = settings->input.poll_type_behavior;
        if (!core_ctl(CORE_CTL_VERIFY_API_VERSION, NULL))
            return false;
        if (!retro_init_libretro_cbs(&retro_ctx))
            return false;
        core_ctl(CORE_CTL_RETRO_GET_SYSTEM_AV_INFO,
                 video_viewport_get_system_av_info());
        runloop_ctl(RUNLOOP_CTL_SET_FRAME_LIMIT, NULL);
    }
    break;
    case CORE_CTL_DEINIT:
        return retro_uninit_libretro_cbs(&retro_ctx);
    case CORE_CTL_VERIFY_API_VERSION:
    {
        unsigned api_version = core.retro_api_version();
        RARCH_LOG("Version of libretro API: %u\n", api_version);
        RARCH_LOG("Compiled against API: %u\n",    RETRO_API_VERSION);

        if (api_version != RETRO_API_VERSION)
        {
            RARCH_WARN("%s\n", msg_hash_to_str(MSG_LIBRETRO_ABI_BREAK));
            return false;
        }
    }
    break;
    case CORE_CTL_HAS_SET_INPUT_DESCRIPTORS:
        return has_set_input_descriptors;
    case CORE_CTL_SET_INPUT_DESCRIPTORS:
        has_set_input_descriptors = true;
        break;
    case CORE_CTL_UNSET_INPUT_DESCRIPTORS:
        has_set_input_descriptors = false;
        break;
    case CORE_CTL_NONE:
    default:
        break;
    }

    return true;
}