Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix audio stuttering when first playing a sound #885

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions es-app/src/FileData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void FileData::launchGame(Window* window)
window->init();
InputManager::getInstance()->init();
VolumeControl::getInstance()->init();
AudioManager::getInstance()->init();
window->normalizeNextUpdate();

//update number of times the game has been launched
Expand Down
59 changes: 20 additions & 39 deletions es-app/src/VolumeControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,49 +20,19 @@ std::weak_ptr<VolumeControl> VolumeControl::sInstance;


VolumeControl::VolumeControl()
: originalVolume(0), internalVolume(0)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
, mixerIndex(0), mixerHandle(nullptr), mixerElem(nullptr), mixerSelemId(nullptr)
: mixerIndex(0), mixerHandle(nullptr), mixerElem(nullptr), mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr), endpointVolume(nullptr)
: mixerHandle(nullptr), endpointVolume(nullptr)
#endif
{
init();

//get original volume levels for system
originalVolume = getVolume();
}

VolumeControl::VolumeControl(const VolumeControl & right):
originalVolume(0), internalVolume(0)
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
, mixerIndex(0), mixerHandle(nullptr), mixerElem(nullptr), mixerSelemId(nullptr)
#elif defined(WIN32) || defined(_WIN32)
, mixerHandle(nullptr), endpointVolume(nullptr)
#endif
{
(void)right;
sInstance = right.sInstance;
}

VolumeControl & VolumeControl::operator=(const VolumeControl & right)
{
if (this != &right) {
sInstance = right.sInstance;
}

return *this;
}

VolumeControl::~VolumeControl()
{
//set original volume levels for system
//setVolume(originalVolume);

deinit();
}

Expand Down Expand Up @@ -152,16 +122,18 @@ void VolumeControl::init()
}
#elif defined(WIN32) || defined(_WIN32)
//get windows version information
OSVERSIONINFOEXA osVer = {sizeof(OSVERSIONINFO)};
::GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&osVer));
OSVERSIONINFO osVer = {sizeof(OSVERSIONINFO)};
GetVersionEx(&osVer);
//check windows version
if(osVer.dwMajorVersion < 6)
{
//Windows older than Vista. use mixer API. open default mixer
if (mixerHandle == nullptr)
{
LOG(LogDebug) << "VolumeControl::init() - Attempt to use mixer API";
if (mixerOpen(&mixerHandle, 0, NULL, 0, 0) == MMSYSERR_NOERROR)
{
LOG(LogDebug) << "VolumeControl::init() - Opened mixer API";
//retrieve info on the volume slider control for the "Speaker Out" line
MIXERLINECONTROLS mixerLineControls;
mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
Expand All @@ -171,7 +143,11 @@ void VolumeControl::init()
mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; //Get volume control
mixerLineControls.pamxctrl = &mixerControl;
mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)
{
LOG(LogDebug) << "VolumeControl::init() - Mixer initialized";
}
else
{
LOG(LogError) << "VolumeControl::init() - Failed to get mixer volume control!";
mixerClose(mixerHandle);
Expand All @@ -189,19 +165,26 @@ void VolumeControl::init()
//Windows Vista or above. use EndpointVolume API. get device enumerator
if (endpointVolume == nullptr)
{
LOG(LogDebug) << "VolumeControl::init() - Attempt to use EndpointVolume API";
CoInitialize(nullptr);
IMMDeviceEnumerator * deviceEnumerator = nullptr;
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
if (deviceEnumerator != nullptr)
{
LOG(LogDebug) << "VolumeControl::init() - MMDevice enumerate succeeded";
//get default endpoint
IMMDevice * defaultDevice = nullptr;
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
if (defaultDevice != nullptr)
{
LOG(LogDebug) << "VolumeControl::init() - Acquired default audio endpoint";
//retrieve endpoint volume
defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&endpointVolume);
if (endpointVolume == nullptr)
if (endpointVolume != nullptr)
{
LOG(LogDebug) << "VolumeControl::init() - Volume initialized";
}
else
{
LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint volume!";
}
Expand Down Expand Up @@ -315,7 +298,7 @@ int VolumeControl::getVolume() const
if (endpointVolume->GetMasterVolumeLevelScalar(&floatVolume) == S_OK)
{
volume = (int)Math::round(floatVolume * 100.0f);
LOG(LogInfo) << " getting volume as " << volume << " ( from float " << floatVolume << ")";
LOG(LogDebug) << " getting volume as " << volume << " (from float " << floatVolume << ")";
}
else
{
Expand Down Expand Up @@ -347,8 +330,6 @@ void VolumeControl::setVolume(int volume)
{
volume = 100;
}
//store values in internal variables
internalVolume = volume;
#if defined (__APPLE__)
#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
Expand Down
5 changes: 0 additions & 5 deletions es-app/src/VolumeControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,9 @@ class VolumeControl
IAudioEndpointVolume * endpointVolume;
#endif

int originalVolume;
int internalVolume;

static std::weak_ptr<VolumeControl> sInstance;

VolumeControl();
VolumeControl(const VolumeControl & right);
VolumeControl & operator=(const VolumeControl & right);

public:
static std::shared_ptr<VolumeControl> & getInstance();
Expand Down
6 changes: 6 additions & 0 deletions es-app/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "Settings.h"
#include "SystemData.h"
#include "SystemScreenSaver.h"
#include "AudioManager.h"
#include "VolumeControl.h"
#include <SDL_events.h>
#include <SDL_main.h>
#include <SDL_timer.h>
Expand Down Expand Up @@ -395,6 +397,8 @@ int main(int argc, char* argv[])
window.renderLoadingScreen("Done.");

InputManager::getInstance()->init();
VolumeControl::getInstance()->init();
AudioManager::getInstance()->init();

//choose which GUI to open depending on if an input configuration already exists
if(errorMsg == NULL)
Expand Down Expand Up @@ -467,6 +471,8 @@ int main(int argc, char* argv[])
while(window.peekGui() != ViewController::get())
delete window.peekGui();

AudioManager::getInstance()->deinit();
VolumeControl::getInstance()->deinit();
InputManager::getInstance()->deinit();
window.deinit();

Expand Down
6 changes: 6 additions & 0 deletions es-core/src/AudioManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ std::shared_ptr<AudioManager> & AudioManager::getInstance()

void AudioManager::init()
{
if(sInstance)
return;

if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
{
LOG(LogError) << "Error initializing SDL audio!\n" << SDL_GetError();
Expand Down Expand Up @@ -103,6 +106,9 @@ void AudioManager::init()

void AudioManager::deinit()
{
if(!sInstance)
return;

//stop all playback
stop();
//completely tear down SDL audio. else SDL hogs audio resources and emulators might fail to start...
Expand Down
14 changes: 9 additions & 5 deletions es-core/src/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
int SDL_USER_CECBUTTONDOWN = -1;
int SDL_USER_CECBUTTONUP = -1;

InputManager* InputManager::mInstance = NULL;
InputManager* InputManager::sInstance = NULL;

InputManager::InputManager() : mKeyboardInputConfig(NULL)
{
Expand All @@ -42,16 +42,16 @@ InputManager::~InputManager()

InputManager* InputManager::getInstance()
{
if(!mInstance)
mInstance = new InputManager();
if(!sInstance)
sInstance = new InputManager();

return mInstance;
return sInstance;
}

void InputManager::init()
{
if(initialized())
deinit();
return;

SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
Settings::getInstance()->getBool("BackgroundJoystickInput") ? "1" : "0");
Expand Down Expand Up @@ -93,6 +93,10 @@ void InputManager::addJoystickByDeviceIndex(int id)

// add it to our list so we can close it again later
SDL_JoystickID joyId = SDL_JoystickInstanceID(joy);

if(mJoysticks.count(joyId) > 0)
return; // already added

mJoysticks[joyId] = joy;

char guid[65];
Expand Down
2 changes: 1 addition & 1 deletion es-core/src/InputManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class InputManager
private:
InputManager();

static InputManager* mInstance;
static InputManager* sInstance;

static const int DEADZONE = 23000;

Expand Down