Exemplo n.º 1
0
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our 
 * network buffer is full, we simply have to block 
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(void)
{
   int res;

   if (!netplay_data->has_connection)
      return false;

   netplay_data->can_poll = false;

   get_self_input_state(netplay_data);

   /* No network side in spectate mode */
   if (netplay_is_server(netplay_data) && netplay_data->spectate.enabled)
      return true;

   /* Read Netplay input, block if we're configured to stall for input every
    * frame */
   if (netplay_data->stall_frames == 0 &&
       netplay_data->read_frame_count <= netplay_data->self_frame_count)
      res = poll_input(netplay_data, true);
   else
      res = poll_input(netplay_data, false);
   if (res == -1)
   {
      hangup(netplay_data);
      return false;
   }

   /* Simulate the input if we don't have real input */
   if (!netplay_data->buffer[netplay_data->self_ptr].have_remote)
      netplay_simulate_input(netplay_data, netplay_data->self_ptr);

   /* Consider stalling */
   switch (netplay_data->stall)
   {
      case RARCH_NETPLAY_STALL_RUNNING_FAST:
         if (netplay_data->read_frame_count >= netplay_data->self_frame_count)
            netplay_data->stall = RARCH_NETPLAY_STALL_NONE;
         break;

      default: /* not stalling */
         if (netplay_data->read_frame_count + netplay_data->stall_frames 
               <= netplay_data->self_frame_count)
         {
            netplay_data->stall      = RARCH_NETPLAY_STALL_RUNNING_FAST;
            netplay_data->stall_time = cpu_features_get_time_usec();
         }
   }

   /* If we're stalling, consider disconnection */
   if (netplay_data->stall)
   {
      retro_time_t now = cpu_features_get_time_usec();

      /* Don't stall out while they're paused */
      if (netplay_data->remote_paused)
         netplay_data->stall_time = now;
      else if (now - netplay_data->stall_time >= MAX_STALL_TIME_USEC)
      {
         /* Stalled out! */
         hangup(netplay_data);
         return false;
      }
   }

   return true;
}
Exemplo n.º 2
0
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our
 * network buffer is full, we simply have to block
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(netplay_t *netplay)
{
    int res;

    if (!netplay->has_connection)
        return false;

    netplay->can_poll = false;

    if (!get_self_input_state(netplay))
        return false;

    /* We skip reading the first frame so the host has a chance to grab
     * our host info so we don't block forever :') */
    if (netplay->frame_count == 0)
    {
        netplay->buffer[0].used_real        = true;
        netplay->buffer[0].is_simulated     = false;

        memset(netplay->buffer[0].real_input_state,
               0, sizeof(netplay->buffer[0].real_input_state));

        netplay->read_ptr                   = NEXT_PTR(netplay->read_ptr);
        netplay->read_frame_count++;
        return true;
    }

    /* We might have reached the end of the buffer, where we
     * simply have to block. */
    res = poll_input(netplay, netplay->other_ptr == netplay->self_ptr);
    if (res == -1)
    {
        netplay->has_connection = false;
        warn_hangup();
        return false;
    }

    if (res == 1)
    {
        uint32_t first_read = netplay->read_frame_count;
        do
        {
            uint32_t buffer[UDP_FRAME_PACKETS * UDP_WORDS_PER_FRAME];
            if (!receive_data(netplay, buffer, sizeof(buffer)))
            {
                warn_hangup();
                netplay->has_connection = false;
                return false;
            }
            parse_packet(netplay, buffer, UDP_FRAME_PACKETS);

        } while ((netplay->read_frame_count <= netplay->frame_count) &&
                 poll_input(netplay, (netplay->other_ptr == netplay->self_ptr) &&
                            (first_read == netplay->read_frame_count)) == 1);
    }
    else
    {
        /* Cannot allow this. Should not happen though. */
        if (netplay->self_ptr == netplay->other_ptr)
        {
            warn_hangup();
            return false;
        }
    }

    if (netplay->read_ptr != netplay->self_ptr)
        simulate_input(netplay);
    else
        netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;

    return true;
}
Exemplo n.º 3
0
// Poll network to see if we have anything new. If our network buffer is full, we simply have to block for new input data.
static bool netplay_poll(netplay_t *handle)
{
   if (!handle->has_connection)
      return false;

   handle->can_poll = false;

   if (!get_self_input_state(handle))
      return false;

   // We skip reading the first frame so the host has a chance to grab our host info so we don't block forever :')
   if (handle->frame_count == 0)
   {
      handle->buffer[0].used_real = true;
      handle->buffer[0].is_simulated = false;
      handle->buffer[0].real_input_state = 0;
      handle->read_ptr = NEXT_PTR(handle->read_ptr);
      handle->read_frame_count++;
      return true;
   }

   // We might have reached the end of the buffer, where we simply have to block.
   int res = poll_input(handle, handle->other_ptr == handle->self_ptr);
   if (res == -1)
   {
      handle->has_connection = false;
      warn_hangup();
      return false;
   }

   if (res == 1)
   {
      uint32_t first_read = handle->read_frame_count;
      do 
      {
         uint32_t buffer[UDP_FRAME_PACKETS * 2];
         if (!receive_data(handle, buffer, sizeof(buffer)))
         {
            warn_hangup();
            handle->has_connection = false;
            return false;
         }
         parse_packet(handle, buffer, UDP_FRAME_PACKETS);

      } while ((handle->read_frame_count <= handle->frame_count) && 
            poll_input(handle, (handle->other_ptr == handle->self_ptr) && 
               (first_read == handle->read_frame_count)) == 1);
   }
   else
   {
      // Cannot allow this. Should not happen though.
      if (handle->self_ptr == handle->other_ptr)
      {
         warn_hangup();
         return false;
      }
   }

   if (handle->read_ptr != handle->self_ptr)
      simulate_input(handle);
   else
      handle->buffer[PREV_PTR(handle->self_ptr)].used_real = true;

   return true;
}
Exemplo n.º 4
0
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our
 * network buffer is full, we simply have to block
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(void)
{
   int res;
   uint32_t client;
   size_t i;

   netplay_data->can_poll = false;

   if (!get_self_input_state(netplay_data))
      goto catastrophe;

   /* If we're not connected, we're done */
   if (netplay_data->self_mode == NETPLAY_CONNECTION_NONE)
      return true;

   /* Read Netplay input, block if we're configured to stall for input every
    * frame */
   netplay_update_unread_ptr(netplay_data);
   if (netplay_data->stateless_mode &&
       (netplay_data->connected_players>1) &&
       netplay_data->unread_frame_count <= netplay_data->run_frame_count)
      res = netplay_poll_net_input(netplay_data, true);
   else
      res = netplay_poll_net_input(netplay_data, false);
   if (res == -1)
      goto catastrophe;

   /* Resolve and/or simulate the input if we don't have real input */
   netplay_resolve_input(netplay_data, netplay_data->run_ptr, false);

   /* Handle any slaves */
   if (netplay_data->is_server && netplay_data->connected_slaves)
      netplay_handle_slaves(netplay_data);

   netplay_update_unread_ptr(netplay_data);

   /* Figure out how many frames of input latency we should be using to hide
    * network latency */
   if (netplay_data->frame_run_time_avg || netplay_data->stateless_mode)
   {
      /* FIXME: Using fixed 60fps for this calculation */
      unsigned frames_per_frame = netplay_data->frame_run_time_avg ?
                                  (16666/netplay_data->frame_run_time_avg) :
                                   0;
      unsigned frames_ahead = (netplay_data->run_frame_count > netplay_data->unread_frame_count) ?
                              (netplay_data->run_frame_count - netplay_data->unread_frame_count) :
                              0;
      settings_t *settings  = config_get_ptr();
      unsigned input_latency_frames_min = settings->uints.netplay_input_latency_frames_min;
      unsigned input_latency_frames_max = input_latency_frames_min + settings->uints.netplay_input_latency_frames_range;

      /* Assume we need a couple frames worth of time to actually run the
       * current frame */
      if (frames_per_frame > 2)
         frames_per_frame -= 2;
      else
         frames_per_frame = 0;

      /* Shall we adjust our latency? */
      if (netplay_data->stateless_mode)
      {
         /* In stateless mode, we adjust up if we're "close" and down if we
          * have a lot of slack */
         if (netplay_data->input_latency_frames < input_latency_frames_min ||
             (netplay_data->unread_frame_count == netplay_data->run_frame_count + 1 &&
              netplay_data->input_latency_frames < input_latency_frames_max))
         {
            netplay_data->input_latency_frames++;
         }
         else if (netplay_data->input_latency_frames > input_latency_frames_max ||
                  (netplay_data->unread_frame_count > netplay_data->run_frame_count + 2 &&
                   netplay_data->input_latency_frames > input_latency_frames_min))
         {
            netplay_data->input_latency_frames--;
         }

      }
      else if (netplay_data->input_latency_frames < input_latency_frames_min ||
               (frames_per_frame < frames_ahead &&
                netplay_data->input_latency_frames < input_latency_frames_max))
      {
         /* We can't hide this much network latency with replay, so hide some
          * with input latency */
         netplay_data->input_latency_frames++;
      }
      else if (netplay_data->input_latency_frames > input_latency_frames_max ||
               (frames_per_frame > frames_ahead + 2 &&
                netplay_data->input_latency_frames > input_latency_frames_min))
      {
         /* We don't need this much latency (any more) */
         netplay_data->input_latency_frames--;
      }
   }

   /* If we're stalled, consider unstalling */
   switch (netplay_data->stall)
   {
      case NETPLAY_STALL_RUNNING_FAST:
      {
         if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
               > netplay_data->self_frame_count)
         {
            netplay_data->stall = NETPLAY_STALL_NONE;
            for (i = 0; i < netplay_data->connections_size; i++)
            {
               struct netplay_connection *connection = &netplay_data->connections[i];
               if (connection->active && connection->stall)
                  connection->stall = NETPLAY_STALL_NONE;
            }
         }
         break;
      }

      case NETPLAY_STALL_SPECTATOR_WAIT:
         if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING || netplay_data->unread_frame_count > netplay_data->self_frame_count)
            netplay_data->stall = NETPLAY_STALL_NONE;
         break;

      case NETPLAY_STALL_INPUT_LATENCY:
         /* Just let it recalculate momentarily */
         netplay_data->stall = NETPLAY_STALL_NONE;
         break;

      case NETPLAY_STALL_SERVER_REQUESTED:
      {
         /* See if the stall is done */
         if (netplay_data->connections[0].stall_frame == 0)
         {
            /* Stop stalling! */
            netplay_data->connections[0].stall = NETPLAY_STALL_NONE;
            netplay_data->stall = NETPLAY_STALL_NONE;
         }
         else
         {
            netplay_data->connections[0].stall_frame--;
         }
         break;
      }

      case NETPLAY_STALL_NO_CONNECTION:
         /* We certainly haven't fixed this */
         break;

      default: /* not stalling */
         break;
   }

   /* If we're not stalled, consider stalling */
   if (!netplay_data->stall)
   {
      /* Have we not read enough latency frames? */
      if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING &&
          netplay_data->connected_players &&
          netplay_data->run_frame_count + netplay_data->input_latency_frames > netplay_data->self_frame_count)
      {
         netplay_data->stall = NETPLAY_STALL_INPUT_LATENCY;
         netplay_data->stall_time = 0;
      }

      /* Are we too far ahead? */
      if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
            <= netplay_data->self_frame_count)
      {
         netplay_data->stall      = NETPLAY_STALL_RUNNING_FAST;
         netplay_data->stall_time = cpu_features_get_time_usec();

         /* Figure out who to blame */
         if (netplay_data->is_server)
         {
            for (client = 1; client < MAX_CLIENTS; client++)
            {
               struct netplay_connection *connection;
               if (!(netplay_data->connected_players & (1<<client)))
                  continue;
               if (netplay_data->read_frame_count[client] > netplay_data->unread_frame_count)
                  continue;
               connection = &netplay_data->connections[client-1];
               if (connection->active &&
                   connection->mode == NETPLAY_CONNECTION_PLAYING)
               {
                  connection->stall = NETPLAY_STALL_RUNNING_FAST;
                  connection->stall_time = netplay_data->stall_time;
               }
            }
         }

      }

      /* If we're a spectator, are we ahead at all? */
      if (!netplay_data->is_server &&
          (netplay_data->self_mode == NETPLAY_CONNECTION_SPECTATING ||
           netplay_data->self_mode == NETPLAY_CONNECTION_SLAVE) &&
          netplay_data->unread_frame_count <= netplay_data->self_frame_count)
      {
         netplay_data->stall = NETPLAY_STALL_SPECTATOR_WAIT;
         netplay_data->stall_time = cpu_features_get_time_usec();
      }
   }

   /* If we're stalling, consider disconnection */
   if (netplay_data->stall && netplay_data->stall_time)
   {
      retro_time_t now = cpu_features_get_time_usec();

      /* Don't stall out while they're paused */
      if (netplay_data->remote_paused)
         netplay_data->stall_time = now;
      else if (now - netplay_data->stall_time >=
               (netplay_data->is_server ? MAX_SERVER_STALL_TIME_USEC :
                                          MAX_CLIENT_STALL_TIME_USEC))
      {
         /* Stalled out! */
         if (netplay_data->is_server)
         {
            for (i = 0; i < netplay_data->connections_size; i++)
            {
               struct netplay_connection *connection = &netplay_data->connections[i];
               if (connection->active &&
                   connection->mode == NETPLAY_CONNECTION_PLAYING &&
                   connection->stall &&
                   now - connection->stall_time >= MAX_SERVER_STALL_TIME_USEC)
               {
                  netplay_hangup(netplay_data, connection);
               }
            }
         }
         else
            goto catastrophe;
         return false;
      }
   }

   return true;

catastrophe:
   for (i = 0; i < netplay_data->connections_size; i++)
      netplay_hangup(netplay_data, &netplay_data->connections[i]);
   return false;
}