1
0
Fork 0
mirror of https://github.com/bjornbytes/lovr.git synced 2024-07-02 20:43:35 +00:00

Sink attempt;

This commit is contained in:
bjorn 2021-03-03 20:01:56 -07:00
parent f806c07bfa
commit 0c3351331e
6 changed files with 92 additions and 48 deletions

View file

@ -76,6 +76,7 @@ typedef struct {
extern StringEntry lovrArcMode[]; extern StringEntry lovrArcMode[];
extern StringEntry lovrAttributeType[]; extern StringEntry lovrAttributeType[];
extern StringEntry lovrAudioMaterial[]; extern StringEntry lovrAudioMaterial[];
extern StringEntry lovrAudioShareMode[];
extern StringEntry lovrAudioType[]; extern StringEntry lovrAudioType[];
extern StringEntry lovrBlendAlphaMode[]; extern StringEntry lovrBlendAlphaMode[];
extern StringEntry lovrBlendMode[]; extern StringEntry lovrBlendMode[];

View file

@ -31,6 +31,12 @@ StringEntry lovrAudioMaterial[] = {
{ 0 } { 0 }
}; };
StringEntry lovrAudioShareMode[] = {
[AUDIO_SHARED] = ENTRY("shared"),
[AUDIO_EXCLUSIVE] = ENTRY("exclusive"),
{ 0 }
};
StringEntry lovrAudioType[] = { StringEntry lovrAudioType[] = {
[AUDIO_PLAYBACK] = ENTRY("playback"), [AUDIO_PLAYBACK] = ENTRY("playback"),
[AUDIO_CAPTURE] = ENTRY("capture"), [AUDIO_CAPTURE] = ENTRY("capture"),
@ -74,10 +80,9 @@ static int l_lovrAudioSetDevice(lua_State *L) {
luaL_checkany(L, 2); luaL_checkany(L, 2);
void* id = lua_touserdata(L, 2); void* id = lua_touserdata(L, 2);
size_t size = luax_len(L, 2); size_t size = luax_len(L, 2);
uint32_t sampleRate = lua_tointeger(L, 3); Sound* sink = lua_isnoneornil(L, 3) ? NULL : luax_checktype(L, 3, Sound);
SampleFormat format = luax_checkenum(L, 4, SampleFormat, "f32"); AudioShareMode shareMode = luax_checkenum(L, 4, AudioShareMode, "shared");
bool exclusive = lua_toboolean(L, 5); bool success = lovrAudioSetDevice(type, id, size, sink, shareMode);
bool success = lovrAudioSetDevice(type, id, size, sampleRate, format, exclusive);
lua_pushboolean(L, success); lua_pushboolean(L, success);
return 1; return 1;
} }
@ -193,12 +198,6 @@ static int l_lovrAudioGetSpatializer(lua_State *L) {
return 1; return 1;
} }
static int l_lovrAudioGetCaptureStream(lua_State* L) {
Sound* sound = lovrAudioGetCaptureStream();
luax_pushtype(L, Sound, sound);
return 1;
}
static int l_lovrAudioGetAbsorption(lua_State* L) { static int l_lovrAudioGetAbsorption(lua_State* L) {
float absorption[3]; float absorption[3];
lovrAudioGetAbsorption(absorption); lovrAudioGetAbsorption(absorption);
@ -263,7 +262,6 @@ static const luaL_Reg lovrAudio[] = {
{ "setPose", l_lovrAudioSetPose }, { "setPose", l_lovrAudioSetPose },
{ "setGeometry", l_lovrAudioSetGeometry }, { "setGeometry", l_lovrAudioSetGeometry },
{ "getSpatializer", l_lovrAudioGetSpatializer }, { "getSpatializer", l_lovrAudioGetSpatializer },
{ "getCaptureStream", l_lovrAudioGetCaptureStream },
{ "getAbsorption", l_lovrAudioGetAbsorption }, { "getAbsorption", l_lovrAudioGetAbsorption },
{ "setAbsorption", l_lovrAudioSetAbsorption }, { "setAbsorption", l_lovrAudioSetAbsorption },
{ "newSource", l_lovrAudioNewSource }, { "newSource", l_lovrAudioNewSource },
@ -293,7 +291,7 @@ int luaopen_lovr_audio(lua_State* L) {
if (lovrAudioInit(spatializer)) { if (lovrAudioInit(spatializer)) {
luax_atexit(L, lovrAudioDestroy); luax_atexit(L, lovrAudioDestroy);
if (start) { if (start) {
lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, PLAYBACK_SAMPLE_RATE, SAMPLE_F32, false); lovrAudioSetDevice(AUDIO_PLAYBACK, NULL, 0, NULL, AUDIO_SHARED);
lovrAudioStart(AUDIO_PLAYBACK); lovrAudioStart(AUDIO_PLAYBACK);
} }
} }

View file

@ -20,7 +20,6 @@ static const ma_format miniaudioFormats[] = {
#define FOREACH_SOURCE(s) for (uint64_t m = state.sourceMask; s = m ? state.sources[CTZL(m)] : NULL, m; m ^= (m & -m)) #define FOREACH_SOURCE(s) for (uint64_t m = state.sourceMask; s = m ? state.sources[CTZL(m)] : NULL, m; m ^= (m & -m))
#define OUTPUT_FORMAT SAMPLE_F32 #define OUTPUT_FORMAT SAMPLE_F32
#define OUTPUT_CHANNELS 2 #define OUTPUT_CHANNELS 2
#define CAPTURE_CHANNELS 1
struct Source { struct Source {
uint32_t ref; uint32_t ref;
@ -44,13 +43,12 @@ struct Source {
static struct { static struct {
bool initialized; bool initialized;
ma_mutex lock;
ma_context context; ma_context context;
ma_device devices[2]; ma_device devices[2];
ma_mutex lock; Sound* sinks[2];
Source* sources[MAX_SOURCES]; Source* sources[MAX_SOURCES];
uint64_t sourceMask; uint64_t sourceMask;
Sound* captureStream;
arr_t(ma_data_converter) converters;
float position[4]; float position[4];
float orientation[4]; float orientation[4];
Spatializer* spatializer; Spatializer* spatializer;
@ -58,11 +56,17 @@ static struct {
uint32_t leftoverFrames; uint32_t leftoverFrames;
float leftovers[BUFFER_SIZE * 2]; float leftovers[BUFFER_SIZE * 2];
float absorption[3]; float absorption[3];
arr_t(ma_data_converter) converters;
ma_data_converter playbackConverter;
} state; } state;
// Device callbacks // Device callbacks
static void onPlayback(ma_device* device, void* out, const void* in, uint32_t count) { static void onPlayback(ma_device* device, void* out, const void* in, uint32_t count) {
float raw[BUFFER_SIZE * 2];
float aux[BUFFER_SIZE * 2];
float mix[BUFFER_SIZE * 2];
uint32_t total = count;
float* output = out; float* output = out;
// Consume any leftovers from the previous callback // Consume any leftovers from the previous callback
@ -74,17 +78,13 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
output += leftoverFrames * OUTPUT_CHANNELS; output += leftoverFrames * OUTPUT_CHANNELS;
count -= leftoverFrames; count -= leftoverFrames;
if (count == 0) { if (count == 0) {
return; goto sink;
} }
} }
ma_mutex_lock(&state.lock); ma_mutex_lock(&state.lock);
do { do {
float raw[BUFFER_SIZE * 2];
float aux[BUFFER_SIZE * 2];
float mix[BUFFER_SIZE * 2];
float* dst = count >= BUFFER_SIZE ? output : state.leftovers; float* dst = count >= BUFFER_SIZE ? output : state.leftovers;
float* src = NULL; // The "current" buffer (used for fast paths) float* src = NULL; // The "current" buffer (used for fast paths)
@ -169,10 +169,26 @@ static void onPlayback(ma_device* device, void* out, const void* in, uint32_t co
} while (count > 0); } while (count > 0);
ma_mutex_unlock(&state.lock); ma_mutex_unlock(&state.lock);
sink:
if (state.sinks[AUDIO_PLAYBACK]) {
uint64_t remaining = total;
uint64_t capacity = sizeof(aux) / lovrSoundGetChannelCount(state.sinks[AUDIO_PLAYBACK]) / sizeof(float);
output = out;
while (remaining > 0) {
ma_uint64 framesConsumed = remaining;
ma_uint64 framesWritten = capacity;
ma_data_converter_process_pcm_frames(&state.playbackConverter, output, &framesConsumed, aux, &framesWritten);
lovrSoundWrite(state.sinks[AUDIO_PLAYBACK], 0, framesWritten, aux);
output += framesConsumed * OUTPUT_CHANNELS;
remaining -= framesConsumed;
}
}
} }
static void onCapture(ma_device* device, void* output, const void* input, uint32_t count) { static void onCapture(ma_device* device, void* output, const void* input, uint32_t count) {
lovrSoundWrite(state.captureStream, 0, count, input); lovrSoundWrite(state.sinks[AUDIO_CAPTURE], 0, count, input);
} }
static const ma_device_callback_proc callbacks[] = { onPlayback, onCapture }; static const ma_device_callback_proc callbacks[] = { onPlayback, onCapture };
@ -229,11 +245,13 @@ void lovrAudioDestroy() {
FOREACH_SOURCE(source) lovrRelease(source, lovrSourceDestroy); FOREACH_SOURCE(source) lovrRelease(source, lovrSourceDestroy);
ma_mutex_uninit(&state.lock); ma_mutex_uninit(&state.lock);
ma_context_uninit(&state.context); ma_context_uninit(&state.context);
lovrRelease(state.captureStream, lovrSoundDestroy); lovrRelease(state.sinks[AUDIO_PLAYBACK], lovrSoundDestroy);
lovrRelease(state.sinks[AUDIO_CAPTURE], lovrSoundDestroy);
if (state.spatializer) state.spatializer->destroy(); if (state.spatializer) state.spatializer->destroy();
for (size_t i = 0; i < state.converters.length; i++) { for (size_t i = 0; i < state.converters.length; i++) {
ma_data_converter_uninit(&state.converters.data[i]); ma_data_converter_uninit(&state.converters.data[i]);
} }
ma_data_converter_uninit(&state.playbackConverter);
arr_free(&state.converters); arr_free(&state.converters);
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
} }
@ -255,43 +273,70 @@ void lovrAudioEnumerateDevices(AudioType type, AudioDeviceCallback* callback, vo
ma_context_enumerate_devices(&state.context, type == AUDIO_PLAYBACK ? enumPlayback : enumCapture, userdata); ma_context_enumerate_devices(&state.context, type == AUDIO_PLAYBACK ? enumPlayback : enumCapture, userdata);
} }
bool lovrAudioSetDevice(AudioType type, void* id, size_t size, uint32_t sampleRate, uint32_t format, bool exclusive) { bool lovrAudioSetDevice(AudioType type, void* id, size_t size, Sound* sink, AudioShareMode shareMode) {
if (id && size != sizeof(ma_device_id)) return false; if (id && size != sizeof(ma_device_id)) return false;
// If no sink is provided for a capture device, one is created internally
if (type == AUDIO_CAPTURE && !sink) {
sink = lovrSoundCreateStream(SAMPLE_RATE * 1., SAMPLE_F32, CHANNEL_MONO, SAMPLE_RATE);
} else {
lovrRetain(sink);
}
lovrAssert(!sink || lovrSoundGetChannelLayout(sink) != CHANNEL_AMBISONIC, "Ambisonic Sounds cannot be used as sinks");
lovrAssert(!sink || lovrSoundIsStream(sink), "Sinks must be streams");
ma_device_uninit(&state.devices[type]);
lovrRelease(state.sinks[type], lovrSoundDestroy);
state.sinks[type] = sink;
#ifdef ANDROID #ifdef ANDROID
// XX<nevyn> miniaudio doesn't seem to be happy to set a specific device an android (fails with // XXX<nevyn> miniaudio doesn't seem to be happy to set a specific device an android (fails with
// error -2 on device init). Since there is only one playback and one capture device in OpenSL, // error -2 on device init). Since there is only one playback and one capture device in OpenSL,
// we can just set this to NULL and make this call a no-op. // we can just set this to NULL and make this call a no-op.
id = NULL; id = NULL;
#endif #endif
static const ma_share_mode shareModes[] = {
[AUDIO_SHARED] = ma_share_mode_shared,
[AUDIO_EXCLUSIVE] = ma_share_mode_exclusive
};
ma_device_config config; ma_device_config config;
if (type == AUDIO_PLAYBACK) { if (type == AUDIO_PLAYBACK) {
sampleRate = sampleRate ? sampleRate : PLAYBACK_SAMPLE_RATE;
lovrAssert(sampleRate == PLAYBACK_SAMPLE_RATE, "Playback sample rate must be %d", PLAYBACK_SAMPLE_RATE);
lovrAssert(format == SAMPLE_F32, "Playback format must be f32");
config = ma_device_config_init(ma_device_type_playback); config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = (ma_device_id*) id; config.playback.pDeviceID = (ma_device_id*) id;
config.playback.format = miniaudioFormats[format]; config.playback.shareMode = shareModes[shareMode];
config.playback.format = ma_format_f32;
config.playback.channels = OUTPUT_CHANNELS; config.playback.channels = OUTPUT_CHANNELS;
config.playback.shareMode = exclusive ? ma_share_mode_exclusive : ma_share_mode_shared; config.sampleRate = SAMPLE_RATE;
if (sink) {
ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
converterConfig.formatIn = config.playback.format;
converterConfig.formatOut = miniaudioFormats[lovrSoundGetFormat(sink)];
converterConfig.channelsIn = config.playback.channels;
converterConfig.channelsOut = lovrSoundGetChannelCount(sink);
converterConfig.sampleRateIn = config.sampleRate;
converterConfig.sampleRateOut = lovrSoundGetSampleRate(sink);
if (memcmp(&converterConfig, &state.playbackConverter.config, sizeof(ma_data_converter_config))) {
ma_data_converter_uninit(&state.playbackConverter);
ma_result status = ma_data_converter_init(&converterConfig, &state.playbackConverter);
lovrAssert(status == MA_SUCCESS, "Failed to create sink data converter");
}
}
} else { } else {
sampleRate = sampleRate ? sampleRate : 16000;
config = ma_device_config_init(ma_device_type_capture); config = ma_device_config_init(ma_device_type_capture);
config.capture.pDeviceID = (ma_device_id*) id; config.capture.pDeviceID = (ma_device_id*) id;
config.capture.format = miniaudioFormats[format]; config.capture.shareMode = shareModes[shareMode];
config.capture.channels = CAPTURE_CHANNELS; config.capture.format = miniaudioFormats[lovrSoundGetFormat(sink)];
config.capture.shareMode = exclusive ? ma_share_mode_exclusive : ma_share_mode_shared; config.capture.channels = lovrSoundGetChannelCount(sink);
lovrRelease(state.captureStream, lovrSoundDestroy); config.sampleRate = lovrSoundGetSampleRate(sink);
state.captureStream = lovrSoundCreateStream(sampleRate * 1., format, CAPTURE_CHANNELS, sampleRate);
} }
config.sampleRate = sampleRate;
config.periodSizeInFrames = BUFFER_SIZE; config.periodSizeInFrames = BUFFER_SIZE;
config.dataCallback = callbacks[type]; config.dataCallback = callbacks[type];
ma_device_uninit(&state.devices[type]);
ma_result result = ma_device_init(&state.context, &config, &state.devices[type]); ma_result result = ma_device_init(&state.context, &config, &state.devices[type]);
return result == MA_SUCCESS; return result == MA_SUCCESS;
} }
@ -335,10 +380,6 @@ const char* lovrAudioGetSpatializer() {
return state.spatializer->name; return state.spatializer->name;
} }
Sound* lovrAudioGetCaptureStream() {
return state.captureStream;
}
void lovrAudioGetAbsorption(float absorption[3]) { void lovrAudioGetAbsorption(float absorption[3]) {
memcpy(absorption, state.absorption, 3 * sizeof(float)); memcpy(absorption, state.absorption, 3 * sizeof(float));
} }
@ -370,7 +411,7 @@ Source* lovrSourceCreate(Sound* sound, bool spatial) {
config.channelsIn = lovrSoundGetChannelCount(sound); config.channelsIn = lovrSoundGetChannelCount(sound);
config.channelsOut = spatial ? 1 : 2; config.channelsOut = spatial ? 1 : 2;
config.sampleRateIn = lovrSoundGetSampleRate(sound); config.sampleRateIn = lovrSoundGetSampleRate(sound);
config.sampleRateOut = PLAYBACK_SAMPLE_RATE; config.sampleRateOut = SAMPLE_RATE;
if (config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) { if (config.formatIn != config.formatOut || config.channelsIn != config.channelsOut || config.sampleRateIn != config.sampleRateOut) {
for (size_t i = 0; i < state.converters.length; i++) { for (size_t i = 0; i < state.converters.length; i++) {

View file

@ -4,7 +4,7 @@
#pragma once #pragma once
#define PLAYBACK_SAMPLE_RATE 48000 #define SAMPLE_RATE 48000
#define BUFFER_SIZE 256 #define BUFFER_SIZE 256
#define MAX_SOURCES 64 #define MAX_SOURCES 64
@ -35,6 +35,11 @@ typedef enum {
MATERIAL_WOOD MATERIAL_WOOD
} AudioMaterial; } AudioMaterial;
typedef enum {
AUDIO_SHARED,
AUDIO_EXCLUSIVE
} AudioShareMode;
typedef enum { typedef enum {
AUDIO_PLAYBACK, AUDIO_PLAYBACK,
AUDIO_CAPTURE AUDIO_CAPTURE
@ -55,7 +60,7 @@ typedef void AudioDeviceCallback(const void* id, size_t size, const char* name,
bool lovrAudioInit(const char* spatializer); bool lovrAudioInit(const char* spatializer);
void lovrAudioDestroy(void); void lovrAudioDestroy(void);
void lovrAudioEnumerateDevices(AudioType type, AudioDeviceCallback* callback, void* userdata); void lovrAudioEnumerateDevices(AudioType type, AudioDeviceCallback* callback, void* userdata);
bool lovrAudioSetDevice(AudioType type, void* id, size_t size, uint32_t sampleRate, uint32_t format, bool exclusive); bool lovrAudioSetDevice(AudioType type, void* id, size_t size, struct Sound* sink, AudioShareMode shareMode);
bool lovrAudioStart(AudioType type); bool lovrAudioStart(AudioType type);
bool lovrAudioStop(AudioType type); bool lovrAudioStop(AudioType type);
bool lovrAudioIsStarted(AudioType type); bool lovrAudioIsStarted(AudioType type);
@ -65,7 +70,6 @@ void lovrAudioGetPose(float position[4], float orientation[4]);
void lovrAudioSetPose(float position[4], float orientation[4]); void lovrAudioSetPose(float position[4], float orientation[4]);
bool lovrAudioSetGeometry(float* vertices, uint32_t* indices, uint32_t vertexCount, uint32_t indexCount, AudioMaterial material); bool lovrAudioSetGeometry(float* vertices, uint32_t* indices, uint32_t vertexCount, uint32_t indexCount, AudioMaterial material);
const char* lovrAudioGetSpatializer(void); const char* lovrAudioGetSpatializer(void);
struct Sound* lovrAudioGetCaptureStream(void);
void lovrAudioGetAbsorption(float absorption[3]); void lovrAudioGetAbsorption(float absorption[3]);
void lovrAudioSetAbsorption(float absorption[3]); void lovrAudioSetAbsorption(float absorption[3]);

View file

@ -104,7 +104,7 @@ static bool oculus_init() {
contextConfig.acc_Size = sizeof(contextConfig); contextConfig.acc_Size = sizeof(contextConfig);
contextConfig.acc_MaxNumSources = MAX_SOURCES; contextConfig.acc_MaxNumSources = MAX_SOURCES;
contextConfig.acc_SampleRate = PLAYBACK_SAMPLE_RATE; contextConfig.acc_SampleRate = SAMPLE_RATE;
contextConfig.acc_BufferLength = BUFFER_SIZE; // Stereo contextConfig.acc_BufferLength = BUFFER_SIZE; // Stereo
if (ovrAudio_CreateContext(&state.context, &contextConfig) != ovrSuccess) { if (ovrAudio_CreateContext(&state.context, &contextConfig) != ovrSuccess) {

View file

@ -146,7 +146,7 @@ bool phonon_init() {
status = phonon_iplCreateEnvironment(state.context, NULL, simulationSettings, NULL, NULL, &state.environment); status = phonon_iplCreateEnvironment(state.context, NULL, simulationSettings, NULL, NULL, &state.environment);
if (status != IPL_STATUS_SUCCESS) return phonon_destroy(), false; if (status != IPL_STATUS_SUCCESS) return phonon_destroy(), false;
state.renderingSettings.samplingRate = PLAYBACK_SAMPLE_RATE; state.renderingSettings.samplingRate = SAMPLE_RATE;
state.renderingSettings.frameSize = BUFFER_SIZE; state.renderingSettings.frameSize = BUFFER_SIZE;
state.renderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON; state.renderingSettings.convolutionType = IPL_CONVOLUTIONTYPE_PHONON;