mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-15 01:24:35 +02:00
#15 Raspberry Pi sound (ALSA) and command line support
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
set -e
|
set -e
|
||||||
clang++ -std=c++11 -Os -s -g -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -Wl,--gc-sections -DNDEBUG -D__RPI__ main.cpp ../../libs/stb_vorbis/stb_vorbis.c -I/opt/vc/include -I../../ -o../../../bin/OpenLara.bin -L/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lX11 -lm -lrt -lpthread -lpulse-simple -lpulse -lbcm_host -ludev
|
clang++ -std=c++11 -Os -s -g -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -Wl,--gc-sections -DNDEBUG -D__RPI__ main.cpp ../../libs/stb_vorbis/stb_vorbis.c -I/opt/vc/include -I../../ -o../../../bin/OpenLara -L/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lX11 -lm -lrt -lpthread -lasound -lbcm_host -ludev
|
||||||
strip ../../../bin/OpenLara --strip-all --remove-section=.comment --remove-section=.note
|
strip ../../../bin/OpenLara --strip-all --remove-section=.comment --remove-section=.note
|
||||||
|
@@ -9,72 +9,13 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
#include <pulse/pulseaudio.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <pulse/simple.h>
|
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
#define WND_TITLE "OpenLara"
|
#define WND_TITLE "OpenLara"
|
||||||
|
|
||||||
#define SND_FRAME_SIZE 4
|
// Time
|
||||||
#define SND_DATA_SIZE (1024 * SND_FRAME_SIZE)
|
|
||||||
|
|
||||||
pa_simple *sndOut;
|
|
||||||
pthread_t sndThread;
|
|
||||||
pthread_mutex_t sndMutex;
|
|
||||||
|
|
||||||
Sound::Frame *sndData;
|
|
||||||
|
|
||||||
void* sndFill(void *arg) {
|
|
||||||
while (1) {
|
|
||||||
pthread_mutex_lock(&sndMutex);
|
|
||||||
Sound::fill(sndData, SND_DATA_SIZE / SND_FRAME_SIZE);
|
|
||||||
pthread_mutex_unlock(&sndMutex);
|
|
||||||
pa_simple_write(sndOut, sndData, SND_DATA_SIZE, NULL);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sndInit() {
|
|
||||||
static const pa_sample_spec spec = {
|
|
||||||
.format = PA_SAMPLE_S16LE,
|
|
||||||
.rate = 44100,
|
|
||||||
.channels = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
static const pa_buffer_attr attr = {
|
|
||||||
.maxlength = SND_DATA_SIZE * 2,
|
|
||||||
.tlength = 0xFFFFFFFF,
|
|
||||||
.prebuf = 0xFFFFFFFF,
|
|
||||||
.minreq = SND_DATA_SIZE,
|
|
||||||
.fragsize = 0xFFFFFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
pthread_mutex_init(&sndMutex, NULL);
|
|
||||||
|
|
||||||
int error;
|
|
||||||
if (!(sndOut = pa_simple_new(NULL, WND_TITLE, PA_STREAM_PLAYBACK, NULL, "game", &spec, NULL, &attr, &error))) {
|
|
||||||
LOG("! sound: pa_simple_new() %s\n", pa_strerror(error));
|
|
||||||
sndData = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sndData = new Sound::Frame[SND_DATA_SIZE / SND_FRAME_SIZE];
|
|
||||||
pthread_create(&sndThread, NULL, sndFill, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sndFree() {
|
|
||||||
if (sndOut) {
|
|
||||||
pthread_cancel(sndThread);
|
|
||||||
pthread_mutex_lock(&sndMutex);
|
|
||||||
// pa_simple_flush(sndOut, NULL);
|
|
||||||
// pa_simple_free(sndOut);
|
|
||||||
pthread_mutex_unlock(&sndMutex);
|
|
||||||
delete[] sndData;
|
|
||||||
}
|
|
||||||
pthread_mutex_destroy(&sndMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int startTime;
|
unsigned int startTime;
|
||||||
|
|
||||||
int getTime() {
|
int getTime() {
|
||||||
@@ -83,6 +24,90 @@ int getTime() {
|
|||||||
return int((t.tv_sec - startTime) * 1000 + t.tv_usec / 1000);
|
return int((t.tv_sec - startTime) * 1000 + t.tv_usec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sound
|
||||||
|
snd_pcm_uframes_t SND_FRAMES = 512;
|
||||||
|
snd_pcm_t *sndOut;
|
||||||
|
Sound::Frame *sndData;
|
||||||
|
pthread_t sndThread;
|
||||||
|
pthread_mutex_t sndMutex;
|
||||||
|
|
||||||
|
void* sndFill(void *arg) {
|
||||||
|
while (sndOut) {
|
||||||
|
pthread_mutex_lock(&sndMutex);
|
||||||
|
Sound::fill(sndData, SND_FRAMES);
|
||||||
|
pthread_mutex_unlock(&sndMutex);
|
||||||
|
|
||||||
|
int err = snd_pcm_writei(sndOut, sndData, SND_FRAMES);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG("! sound: write %s\n", snd_strerror(err));;
|
||||||
|
if (err != -EPIPE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
err = snd_pcm_recover(sndOut, err, 0);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG("! sound: failed to recover\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
snd_pcm_prepare(sndOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sndInit() {
|
||||||
|
unsigned int freq = 44100;
|
||||||
|
|
||||||
|
pthread_mutex_init(&sndMutex, NULL);
|
||||||
|
|
||||||
|
int err;
|
||||||
|
if ((err = snd_pcm_open(&sndOut, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||||
|
LOG("! sound: open %s\n", snd_strerror(err));\
|
||||||
|
sndOut = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
snd_pcm_hw_params_any(sndOut, params);
|
||||||
|
snd_pcm_hw_params_set_access(sndOut, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
|
|
||||||
|
snd_pcm_hw_params_set_channels(sndOut, params, 2);
|
||||||
|
snd_pcm_hw_params_set_format(sndOut, params, SND_PCM_FORMAT_S16_LE);
|
||||||
|
snd_pcm_hw_params_set_rate_near(sndOut, params, &freq, NULL);
|
||||||
|
|
||||||
|
snd_pcm_hw_params_set_periods(sndOut, params, 4, 0);
|
||||||
|
snd_pcm_hw_params_set_period_size_near(sndOut, params, &SND_FRAMES, NULL);
|
||||||
|
snd_pcm_hw_params_get_period_size(params, &SND_FRAMES, 0);
|
||||||
|
|
||||||
|
snd_pcm_hw_params(sndOut, params);
|
||||||
|
snd_pcm_prepare(sndOut);
|
||||||
|
|
||||||
|
sndData = new Sound::Frame[SND_FRAMES];
|
||||||
|
memset(sndData, 0, SND_FRAMES * sizeof(Sound::Frame));
|
||||||
|
if ((err = snd_pcm_writei(sndOut, sndData, SND_FRAMES)) < 0) {
|
||||||
|
LOG("! sound: write %s\n", snd_strerror(err));\
|
||||||
|
sndOut = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_pcm_start(sndOut);
|
||||||
|
pthread_create(&sndThread, NULL, sndFill, NULL);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sndFree() {
|
||||||
|
pthread_cancel(sndThread);
|
||||||
|
pthread_mutex_lock(&sndMutex);
|
||||||
|
snd_pcm_drop(sndOut);
|
||||||
|
snd_pcm_drain(sndOut);
|
||||||
|
snd_pcm_close(sndOut);
|
||||||
|
pthread_mutex_unlock(&sndMutex);
|
||||||
|
pthread_mutex_destroy(&sndMutex);
|
||||||
|
delete[] sndData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window
|
||||||
bool wndInit(DISPMANX_DISPLAY_HANDLE_T &display, EGL_DISPMANX_WINDOW_T &window) {
|
bool wndInit(DISPMANX_DISPLAY_HANDLE_T &display, EGL_DISPMANX_WINDOW_T &window) {
|
||||||
if (graphics_get_display_size(0, (uint32_t*)&window.width, (uint32_t*)&window.height) < 0) {
|
if (graphics_get_display_size(0, (uint32_t*)&window.width, (uint32_t*)&window.height) < 0) {
|
||||||
LOG("! can't get display size\n");
|
LOG("! can't get display size\n");
|
||||||
@@ -270,8 +295,8 @@ void inputDevAdd(const char *node) {
|
|||||||
int index = inputDevIndex(node);
|
int index = inputDevIndex(node);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
inputDevices[index] = open(node, O_RDONLY | O_NONBLOCK);
|
inputDevices[index] = open(node, O_RDONLY | O_NONBLOCK);
|
||||||
//ioctl(inputDevices[index], EVIOCGRAB, (void*)1);
|
ioctl(inputDevices[index], EVIOCGRAB, 1);
|
||||||
LOG("input: add %s\n", node);
|
//LOG("input: add %s\n", node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +304,7 @@ void inputDevRemove(const char *node) {
|
|||||||
int index = inputDevIndex(node);
|
int index = inputDevIndex(node);
|
||||||
if (index != -1 && inputDevices[index] != -1) {
|
if (index != -1 && inputDevices[index] != -1) {
|
||||||
close(inputDevices[index]);
|
close(inputDevices[index]);
|
||||||
LOG("input: remove %s\n", node);
|
//LOG("input: remove %s\n", node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +423,7 @@ void inputUpdate() {
|
|||||||
char Stream::cacheDir[255];
|
char Stream::cacheDir[255];
|
||||||
char Stream::contentDir[255];
|
char Stream::contentDir[255];
|
||||||
|
|
||||||
int main() {
|
int main(int argc, char **argv) {
|
||||||
bcm_host_init();
|
bcm_host_init();
|
||||||
|
|
||||||
DISPMANX_DISPLAY_HANDLE_T dmDisplay;
|
DISPMANX_DISPLAY_HANDLE_T dmDisplay;
|
||||||
@@ -416,8 +441,6 @@ int main() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputInit();
|
|
||||||
|
|
||||||
Stream::contentDir[0] = Stream::cacheDir[0] = 0;
|
Stream::contentDir[0] = Stream::cacheDir[0] = 0;
|
||||||
|
|
||||||
const char *home;
|
const char *home;
|
||||||
@@ -435,7 +458,13 @@ int main() {
|
|||||||
startTime = t.tv_sec;
|
startTime = t.tv_sec;
|
||||||
|
|
||||||
sndInit();
|
sndInit();
|
||||||
Game::init();
|
|
||||||
|
char *lvlName = argc > 1 ? argv[1] : NULL;
|
||||||
|
char *sndName = argc > 2 ? argv[2] : NULL;
|
||||||
|
|
||||||
|
Game::init(lvlName, sndName);
|
||||||
|
|
||||||
|
inputInit(); // initialize and grab input devices
|
||||||
|
|
||||||
int lastTime = getTime();
|
int lastTime = getTime();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user