Permalink
Browse files

audio: Sync game to audio works again

  • Loading branch information...
fzurita committed Feb 25, 2016
1 parent ea7dfe0 commit 33d5969675474f80e7695377d7b7ec276c352eb3
Showing with 69 additions and 17 deletions.
  1. +0 −1 jni/mupen64plus-audio-sles/Android.mk
  2. +69 −16 jni/mupen64plus-audio-sles/main.cpp
@@ -23,7 +23,6 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mupen64plus-audio-sles
-LOCAL_STATIC_LIBRARIES := samplerate
LOCAL_SHARED_LIBRARIES := soundtouch
LOCAL_C_INCLUDES := \
@@ -34,13 +34,6 @@
#include <math.h>
#include <SoundTouch.h>
-#ifdef USE_SRC
-#include <samplerate.h>
-#endif
-#ifdef USE_SPEEX
-#include <speex/speex_resampler.h>
-#endif
-
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_common.h"
#include "m64p_config.h"
@@ -50,6 +43,7 @@
#include "main.h"
#include "osal_dynamiclib.h"
#include "threadqueue.h"
+#include <jni.h>
typedef struct threadLock_
{
@@ -132,6 +126,9 @@ static volatile bool matchGameToAudio = true;
using namespace soundtouch;
static SoundTouch soundTouch;
+double totalElapsedGameTime = 0;
+double gameStartTime = 0;
+
/* Thread Lock */
threadLock lock;
@@ -187,14 +184,17 @@ void queueCallback(SLAndroidSimpleBufferQueueItf caller, void *context);
static void CloseAudio(void)
{
- if(shutdown == 0)
+ if(!shutdown)
{
- shutdown = 1;
+ shutdown = true;
pthread_join(audioConsumerThread,NULL);
thread_queue_cleanup(&audioConsumerQueue, 1);
}
+ gameStartTime = 0.0;
+ totalElapsedGameTime = 0.0;
+
int i = 0;
primaryBufferPos = 0;
@@ -473,7 +473,7 @@ static void InitializeAudio(int freq)
}
thread_queue_init(&audioConsumerQueue);
- shutdown = 0;
+ shutdown = false;
pthread_create( &audioConsumerThread, NULL, audioConsumer, NULL);
return;
@@ -658,14 +658,40 @@ EXPORT void CALL AiDacrateChanged( int SystemType )
InitializeAudio(f);
}
+bool isSpeedLimiterEnabled(void)
+{
+ int e = 1;
+ CoreDoCommand(M64CMD_CORE_STATE_QUERY, M64CORE_SPEED_LIMITER, &e);
+ return e;
+}
+
EXPORT void CALL AiLenChanged(void)
{
+ static const double minSleepNeeded = -0.1;
+ static const double maxSleepNeeded = 0.1;
if (critical_failure == 1)
return;
if (!l_PluginInit)
return;
+
+ static bool resetOnce = false;
+
+ bool limiterEnabled = isSpeedLimiterEnabled();
+ timespec time;
+ clock_gettime(CLOCK_REALTIME, &time);
+ double timeDouble = static_cast<double>(time.tv_sec) +
+ static_cast<double>(time.tv_nsec)/1.0e9;
+
+ //if this is the first time or we are resuming from pause
+ if(gameStartTime == 0 || !resetOnce)
+ {
+ gameStartTime = timeDouble;
+ totalElapsedGameTime = 0.0;
+ resetOnce = true;
+ }
+
unsigned int LenReg = *AudioInfo.AI_LEN_REG;
unsigned char * p = AudioInfo.RDRAM + (*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF);
@@ -676,6 +702,33 @@ EXPORT void CALL AiLenChanged(void)
memcpy(theQueueData->data, p, LenReg);
thread_queue_add(&audioConsumerQueue, theQueueData, 0);
+
+ double speedFactor = static_cast<double>(speed_factor)/100.0;
+ totalElapsedGameTime += 1.0*(LenReg/SLES_SAMPLE_BYTES)/GameFreq/speedFactor;
+
+ //Slow the game down if sync game to audio is enabled
+ if(!limiterEnabled)
+ {
+ double totalRealTimeElapsed = timeDouble - gameStartTime;
+ double sleepNeeded = totalElapsedGameTime - totalRealTimeElapsed;
+
+ if(sleepNeeded < minSleepNeeded || sleepNeeded > maxSleepNeeded)
+ {
+ resetOnce = false;
+ }
+
+ //Useful logging
+ //DebugMessage(M64MSG_ERROR, "Real=%f, Game=%f, sleep=%f, start=%f, time=%f, speed=%d, sleep_before_factor=%f",
+ // totalRealTimeElapsed, totalElapsedGameTime, sleepNeeded, gameStartTime, timeDouble, speed_factor, sleepNeeded*speedFactor);
+
+ if(sleepNeeded > 0.0 && sleepNeeded < maxSleepNeeded)
+ {
+ timespec sleepTime;
+ sleepTime.tv_sec = static_cast<time_t>(sleepNeeded);
+ sleepTime.tv_nsec = (sleepNeeded - sleepTime.tv_sec)*1e9;
+ nanosleep(&sleepTime, NULL );
+ }
+ }
}
double TimeDiff(struct timespec* currTime, struct timespec* prevTime)
@@ -711,7 +764,6 @@ void* audioConsumer(void* param)
soundTouch.setSetting( SETTING_OVERLAP_MS, overlapMS );
soundTouch.setRate(GameFreq*1.0/OutputFreq);
- //soundTouch.setTempo(0.8);
int prevQueueSize = thread_queue_length(&audioConsumerQueue);
int currQueueSize = prevQueueSize;
@@ -733,6 +785,7 @@ void* audioConsumer(void* param)
double slowAdjustment = 0;
double currAdjustment = 0;
const double minSlowAdjustment = 0.05;
+ const double minSlowValue = 0.2;
queueData* currQueueData = NULL;
struct timespec currTime;
struct timespec prevTime;
@@ -742,7 +795,7 @@ void* audioConsumer(void* param)
waitTime.tv_sec = 1;
waitTime.tv_nsec = 0;
- const int feedTimeWindowSize = 50;
+ const int feedTimeWindowSize = 100;
int feedTimeIndex = 0;
bool feedTimesSet = false;
float timePerBuffer = 1.0*SecondaryBufferSize/GameFreq;
@@ -786,7 +839,7 @@ void* audioConsumer(void* param)
if(matchGameToAudio)
{
//Game is running too fast, slow it down a little
- if(queueLength > maxQueueSize && slowAdjustment >= 1.0)
+ if(queueLength > maxQueueSize && slowAdjustment >= 1.0 && isSpeedLimiterEnabled())
{
++matchGameToAudioCurrentPeriod;
if(matchGameToAudioCurrentPeriod >= matchGameToAudioAdjustmentPeriod)
@@ -822,7 +875,7 @@ void* audioConsumer(void* param)
currAdjustment = 1.0;
}
}
- //If we are trying to make audio catch up with video
+ //If we are trying to make audio catch up with video, usually when fast forwarding
else
{
if(queueLength > maxQueueSize)
@@ -841,9 +894,9 @@ void* audioConsumer(void* param)
}
//Allow the tempo to slow down quickly, but restore original speed more slowly
- if( (currAdjustment > 0 &&
+ if( (currAdjustment > minSlowValue &&
( ((slowAdjustment - currAdjustment) > minSlowAdjustment) ||
- ((slowAdjustment - currAdjustment) < -1*minSlowAdjustment*5)))
+ ((currAdjustment - slowAdjustment) < minSlowAdjustment*5)))
|| currAdjustment == 1.0 )
{
slowAdjustment = currAdjustment;

0 comments on commit 33d5969

Please sign in to comment.