ALSA Audio Renderer (Linux)

This commit is contained in:
Nekotekina 2017-04-09 15:59:19 +03:00
parent dc3d38c255
commit 4c741e93c3
6 changed files with 164 additions and 2 deletions

View File

@ -66,6 +66,7 @@ addons:
- llvm-toolchain-trusty-4.0
packages:
- cmake
- libasound2-dev
- libopenal-dev
- freeglut3-dev
- libglew-dev

View File

@ -28,7 +28,7 @@ __Windows__
__Linux__
* GCC 5.1+ or Clang 3.5.0+ ([not GCC 6.1](https://github.com/RPCS3/rpcs3/issues/1691))
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libopenal-dev libwxgtk3.0-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev git`
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libasound2-dev libopenal-dev libwxgtk3.0-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev git`
* Arch: `sudo pacman -S glew openal wxgtk cmake llvm`
__Mac OSX__

View File

@ -49,7 +49,7 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
#on some Linux distros shm_unlink and similar functions are in librt only
set(ADDITIONAL_LIBS "rt" "X11")
set(ADDITIONAL_LIBS "rt" "X11" "asound")
elseif(UNIX OR NOT MSVC)
#it seems like glibc includes the iconv functions we use but other libc
#implementations like the one on OSX don't seem implement them

View File

@ -0,0 +1,136 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Utilities/GSL.h"
#include "Emu/System.h"
#include "ALSAThread.h"
#ifdef __linux__
#include <alsa/asoundlib.h>
extern cfg::bool_entry g_cfg_audio_convert_to_u16;
thread_local static snd_pcm_t* s_tls_handle{nullptr};
static void error(int err, const char* reason)
{
fprintf(stderr, "ALSA: %s failed: %s\n", reason, snd_strerror(err));
}
static bool check(int err, const char* reason)
{
if (err < 0)
{
error(err, reason);
return false;
}
return true;
}
ALSAThread::ALSAThread()
{
snd_pcm_hw_params_t* hw_params{nullptr};
auto at_ret = gsl::finally([&]()
{
if (hw_params)
{
snd_pcm_hw_params_free(hw_params);
}
});
if (!check(snd_pcm_open(&s_tls_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), "snd_pcm_open"))
return;
if (!check(snd_pcm_hw_params_malloc(&hw_params), "snd_pcm_hw_params_malloc"))
return;
if (!check(snd_pcm_hw_params_any(s_tls_handle, hw_params), "snd_pcm_hw_params_any"))
return;
if (!check(snd_pcm_hw_params_set_access(s_tls_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "snd_pcm_hw_params_set_access"))
return;
if (!check(snd_pcm_hw_params_set_format(s_tls_handle, hw_params, g_cfg_audio_convert_to_u16 ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_FLOAT_LE), "snd_pcm_hw_params_set_format"))
return;
if (!check(snd_pcm_hw_params_set_rate(s_tls_handle, hw_params, 48000, 0), "snd_pcm_hw_params_set_rate_near"))
return;
if (!check(snd_pcm_hw_params_set_channels(s_tls_handle, hw_params, 8), "snd_pcm_hw_params_set_channels"))
return;
if (!check(snd_pcm_hw_params_set_buffer_size(s_tls_handle, hw_params, 64 * 256), "snd_pcm_hw_params_set_buffer_size"))
return;
if (!check(snd_pcm_hw_params_set_period_size(s_tls_handle, hw_params, 256, 0), "snd_pcm_hw_params_set_period_size"))
return;
//if (!check(snd_pcm_hw_params_set_periods(s_tls_handle, hw_params, 2, 0), "snd_pcm_hw_params_set_periods"))
// return;
if (!check(snd_pcm_hw_params(s_tls_handle, hw_params), "snd_pcm_hw_params"))
return;
if (!check(snd_pcm_prepare(s_tls_handle), "snd_pcm_prepare"))
return;
}
ALSAThread::~ALSAThread()
{
if (s_tls_handle)
{
snd_pcm_close(s_tls_handle);
}
}
void ALSAThread::Play()
{
}
void ALSAThread::Close()
{
}
void ALSAThread::Stop()
{
}
void ALSAThread::Open(const void* src, int size)
{
AddData(src, size);
}
void ALSAThread::AddData(const void* src, int size)
{
size /= g_cfg_audio_convert_to_u16 ? 2 * 8 : 4 * 8;
int res;
while (true)
{
res = snd_pcm_writei(s_tls_handle, src, size);
if (res == -EAGAIN)
{
continue;
}
else if (res == -EPIPE)
{
snd_pcm_prepare(s_tls_handle);
}
else
{
break;
}
}
if (res != size)
{
error(res, "snd_pcm_writei");
}
}
#endif

View File

@ -0,0 +1,20 @@
#pragma once
#ifdef __linux__
#include "Emu/Audio/AudioThread.h"
class ALSAThread : public AudioThread
{
public:
ALSAThread();
virtual ~ALSAThread() override;
virtual void Play() override;
virtual void Open(const void* src, int size) override;
virtual void Close() override;
virtual void Stop() override;
virtual void AddData(const void* src, int size) override;
};
#endif

View File

@ -42,6 +42,9 @@
#include "Emu/Audio/XAudio2/XAudio2Thread.h"
#include <wx/msw/wrapwin.h>
#endif
#ifdef __linux__
#include "Emu/Audio/ALSA/ALSAThread.h"
#endif
#ifdef __unix__
#include <X11/Xlib.h>
@ -107,6 +110,8 @@ cfg::map_entry<std::function<std::shared_ptr<AudioThread>()>> g_cfg_audio_render
{ "Null", &std::make_shared<NullAudioThread> },
#ifdef _WIN32
{ "XAudio2", &std::make_shared<XAudio2Thread> },
#elif __linux__
{ "ALSA", &std::make_shared<ALSAThread> },
#endif
{ "OpenAL", &std::make_shared<OpenALThread> },
});