Skip to content

Commit

Permalink
Merge pull request #9138 from hrydgard/bluetooth-audio-option
Browse files Browse the repository at this point in the history
Add a setting to make the audio buffer sizes bluetooth-friendly on Android.
  • Loading branch information
hrydgard authored Dec 2, 2016
2 parents e1e3358 + 8594e44 commit e049cce
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 15 deletions.
1 change: 1 addition & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ static ConfigSetting soundSettings[] = {
ConfigSetting("Enable", &g_Config.bEnableSound, true, true, true),
ConfigSetting("AudioBackend", &g_Config.iAudioBackend, 0, true, true),
ConfigSetting("AudioLatency", &g_Config.iAudioLatency, 1, true, true),
ConfigSetting("ExtraAudioBuffering", &g_Config.bExtraAudioBuffering, false, true, false),
ConfigSetting("SoundSpeedHack", &g_Config.bSoundSpeedHack, false, true, true),
ConfigSetting("AudioResampler", &g_Config.bAudioResampler, true, true, true),
ConfigSetting("GlobalVolume", &g_Config.iGlobalVolume, VOLUME_MAX, true, true),
Expand Down
1 change: 1 addition & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ struct Config {
int iAudioLatency; // 0 = low , 1 = medium(default) , 2 = high
int iAudioBackend;
int iGlobalVolume;
bool bExtraAudioBuffering; // For bluetooth

// Audio Hack
bool bSoundSpeedHack;
Expand Down
47 changes: 34 additions & 13 deletions Core/HW/StereoResampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@

// 16 bit Stereo

#define MAX_SAMPLES (2*(1024 * 2)) // 2*64ms - had to double it for nVidia Shield which has huge buffers
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
#define MAX_SAMPLES_DEFAULT (4096) // 2*64ms - had to double it for nVidia Shield which has huge buffers
#define MAX_SAMPLES_EXTRA (8192)

#define LOW_WATERMARK_DEFAULT 1680 // 40 ms
#define LOW_WATERMARK_EXTRA 3360 // 80 ms

#define LOW_WATERMARK 1680 // 40 ms
#define MAX_FREQ_SHIFT 200 // per 32000 Hz
#define CONTROL_FACTOR 0.2f // in freq_shift per fifo size offset
#define CONTROL_AVG 32

#include <string.h>
#include <cstring>

#include "base/logging.h"
#include "base/NativeApp.h"
Expand All @@ -45,7 +47,9 @@
#endif

StereoResampler::StereoResampler()
: m_input_sample_rate(44100)
: m_bufsize(MAX_SAMPLES_DEFAULT)
, m_lowwatermark(LOW_WATERMARK_DEFAULT)
, m_input_sample_rate(44100)
, m_indexW(0)
, m_indexR(0)
, m_numLeftI(0.0f)
Expand All @@ -54,7 +58,8 @@ StereoResampler::StereoResampler()
, overrunCount_(0)
, sample_rate_(0.0f)
, lastBufSize_(0) {
m_buffer = new int16_t[MAX_SAMPLES * 2]();
// Need to have space for the worst case in case it changes.
m_buffer = new int16_t[MAX_SAMPLES_EXTRA * 2]();

// Some Android devices are v-synced to non-60Hz framerates. We simply timestretch audio to fit.
// TODO: should only do this if auto frameskip is off?
Expand All @@ -64,12 +69,24 @@ StereoResampler::StereoResampler()
if (refresh != 60.0f && refresh > 50.0f && refresh < 70.0f) {
SetInputSampleRate((int)(44100 * (refresh / 60.0f)));
}

UpdateBufferSize();
}

StereoResampler::~StereoResampler() {
delete[] m_buffer;
}

void StereoResampler::UpdateBufferSize() {
if (g_Config.bExtraAudioBuffering) {
m_bufsize = MAX_SAMPLES_EXTRA;
m_lowwatermark = LOW_WATERMARK_EXTRA;
} else {
m_bufsize = MAX_SAMPLES_DEFAULT;
m_lowwatermark = LOW_WATERMARK_DEFAULT;
}
}

template<bool useShift>
inline void ClampBufferToS16(s16 *out, const s32 *in, size_t size, s8 volShift) {
#ifdef _M_SSE
Expand Down Expand Up @@ -104,7 +121,7 @@ inline void ClampBufferToS16WithVolume(s16 *out, const s32 *in, size_t size) {
}

void StereoResampler::Clear() {
memset(m_buffer, 0, MAX_SAMPLES * 2 * sizeof(int16_t));
memset(m_buffer, 0, m_bufsize * 2 * sizeof(int16_t));
}

// Executed from sound stream thread
Expand All @@ -124,6 +141,8 @@ unsigned int StereoResampler::Mix(short* samples, unsigned int numSamples, bool
u32 indexR = Common::AtomicLoad(m_indexR);
u32 indexW = Common::AtomicLoad(m_indexW);

const int INDEX_MASK = (m_bufsize * 2 - 1);

// We force on the audio resampler if the output sample rate doesn't match the input.
if (!g_Config.bAudioResampler && sample_rate == (int)m_input_sample_rate) {
for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2) {
Expand All @@ -138,7 +157,7 @@ unsigned int StereoResampler::Mix(short* samples, unsigned int numSamples, bool
// Drift prevention mechanism
float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2);
m_numLeftI = (numLeft + m_numLeftI*(CONTROL_AVG - 1)) / CONTROL_AVG;
float offset = (m_numLeftI - LOW_WATERMARK) * CONTROL_FACTOR;
float offset = (m_numLeftI - m_lowwatermark) * CONTROL_FACTOR;
if (offset > MAX_FREQ_SHIFT) offset = MAX_FREQ_SHIFT;
if (offset < -MAX_FREQ_SHIFT) offset = -MAX_FREQ_SHIFT;

Expand Down Expand Up @@ -188,15 +207,17 @@ unsigned int StereoResampler::Mix(short* samples, unsigned int numSamples, bool
}

void StereoResampler::PushSamples(const s32 *samples, unsigned int num_samples) {
UpdateBufferSize();
const int INDEX_MASK = (m_bufsize * 2 - 1);
// Cache access in non-volatile variable
// indexR isn't allowed to cache in the audio throttling loop as it
// needs to get updates to not deadlock.
u32 indexW = Common::AtomicLoad(m_indexW);

u32 cap = MAX_SAMPLES * 2;
u32 cap = m_bufsize * 2;
// If unthottling, no need to fill up the entire buffer, just screws up timing after releasing unthrottle.
if (PSP_CoreParameter().unthrottle)
cap = LOW_WATERMARK * 2;
cap = m_lowwatermark * 2;

// Check if we have enough free space
// indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW
Expand All @@ -207,7 +228,7 @@ void StereoResampler::PushSamples(const s32 *samples, unsigned int num_samples)
return;
}

int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (indexW & INDEX_MASK)) * sizeof(short);
int over_bytes = num_samples * 4 - (m_bufsize * 2 - (indexW & INDEX_MASK)) * sizeof(short);
if (over_bytes > 0) {
ClampBufferToS16WithVolume(&m_buffer[indexW & INDEX_MASK], samples, (num_samples * 4 - over_bytes) / 2);
ClampBufferToS16WithVolume(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes / 2);
Expand All @@ -225,8 +246,8 @@ void StereoResampler::GetAudioDebugStats(AudioDebugStats *stats) {
underrunCount_ = 0;
stats->overrunCount += overrunCount_;
overrunCount_ = 0;
stats->watermark = LOW_WATERMARK;
stats->bufsize = MAX_SAMPLES * 2;
stats->watermark = m_lowwatermark;
stats->bufsize = m_bufsize * 2;
stats->instantSampleRate = sample_rate_;
stats->lastPushSize = lastPushSize_;
}
Expand Down
5 changes: 4 additions & 1 deletion Core/HW/StereoResampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ class StereoResampler {
void GetAudioDebugStats(AudioDebugStats *stats);

protected:
void UpdateBufferSize();
void SetInputSampleRate(unsigned int rate);

unsigned m_input_sample_rate;
int m_bufsize;
int m_lowwatermark;
unsigned int m_input_sample_rate;
int16_t *m_buffer;
volatile u32 m_indexW;
volatile u32 m_indexR;
Expand Down
5 changes: 4 additions & 1 deletion UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,11 @@ void GameSettingsScreen::CreateViews() {

static const char *latency[] = { "Low", "Medium", "High" };
PopupMultiChoice *lowAudio = audioSettings->Add(new PopupMultiChoice(&g_Config.iAudioLatency, a->T("Audio Latency"), latency, 0, ARRAY_SIZE(latency), gr->GetName(), screenManager()));

lowAudio->SetEnabledPtr(&g_Config.bEnableSound);
#if defined(__ANDROID__)
CheckBox *extraAudio = audioSettings->Add(new CheckBox(&g_Config.bExtraAudioBuffering, a->T("AudioBufferingForBluetooth", "Bluetooth-friendly buffer (slower)")));
extraAudio->SetEnabledPtr(&g_Config.bEnableSound);
#endif
if (System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE) == 44100) {
CheckBox *resampling = audioSettings->Add(new CheckBox(&g_Config.bAudioResampler, a->T("Audio sync", "Audio sync (resampling)")));
resampling->SetEnabledPtr(&g_Config.bEnableSound);
Expand Down

1 comment on commit e049cce

@tausifj15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow sir this built also doesmt have tekken bug yhankx again

Please sign in to comment.