From 3840b1409ee120d6c1c94914791a6a9fa3bb4e9f Mon Sep 17 00:00:00 2001 From: armin-25689 <83564821+armin-25689@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:14:22 +0800 Subject: [PATCH] feat: add oss audio callback for FreeBSD OSS is the native sound system of the FreeBSD.It will be used on the x11_vaapi platform.It was added to reduce moonlight's dependency on FreeBSD. --- CMakeLists.txt | 7 ++++ src/audio/audio.h | 3 ++ src/audio/oss.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ src/platform.c | 3 ++ 4 files changed, 118 insertions(+) create mode 100644 src/audio/oss.c diff --git a/CMakeLists.txt b/CMakeLists.txt index caa71cf..892b217 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,13 @@ add_executable(moonlight ${SRC_LIST}) target_link_libraries(moonlight m) target_link_libraries(moonlight gamestream) +if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + set(ALSA_FOUND FALSE) + set(PULSE_FOUND FALSE) + set(CEC_FOUND FALSE) + target_sources(moonlight PRIVATE ./src/audio/oss.c) +endif() + if (CEC_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC) list(APPEND MOONLIGHT_OPTIONS CEC) diff --git a/src/audio/audio.h b/src/audio/audio.h index 260e78d..efc9f2d 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -31,3 +31,6 @@ extern AUDIO_RENDERER_CALLBACKS audio_callbacks_sdl; extern AUDIO_RENDERER_CALLBACKS audio_callbacks_pulse; bool audio_pulse_init(char* audio_device); #endif +#ifdef __FreeBSD__ +extern AUDIO_RENDERER_CALLBACKS audio_callbacks_oss; +#endif diff --git a/src/audio/oss.c b/src/audio/oss.c new file mode 100644 index 0000000..a38465f --- /dev/null +++ b/src/audio/oss.c @@ -0,0 +1,105 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015-2017 Iwan Timmer + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#ifdef __FreeBSD__ +#include +#include "audio.h" + +#include +#include +#include + +#include +#include +#include + +static OpusMSDecoder* decoder; +static short* pcmBuffer; +static int samplesPerFrame; +static int channelCount; +static int fd; + +static int oss_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int arFlags) { + int rc; + decoder = opus_multistream_decoder_create(opusConfig->sampleRate, opusConfig->channelCount, opusConfig->streams, opusConfig->coupledStreams, opusConfig->mapping, &rc); + + channelCount = opusConfig->channelCount; + samplesPerFrame = opusConfig->samplesPerFrame; + pcmBuffer = malloc(sizeof(short) * channelCount * samplesPerFrame); + if (pcmBuffer == NULL) + return -1; + + const char* oss_name = "/dev/dsp"; + fd = open(oss_name, O_WRONLY); + // buffer size for fragment ,selector 12 is 4096;11 is 2048;10 is 1024; 13is 8192 + if (fd == -1) { + close(fd); + printf("Open audio device /dev/dsp faild!!!"); + return -1; + } + int frag = 12; + if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag) == -1) + printf("Set framgment for /dev/dsp faild."); + + int format = AFMT_S16_LE; + int channels = opusConfig->channelCount; + int rate = opusConfig->sampleRate; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1) + printf("Set framgment for /dev/dsp faild."); + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) + printf("Set channels for /dev/dsp faild."); + if (ioctl(fd, SNDCTL_DSP_SPEED, &rate) == -1) + printf("Set sameple rate for /dev/dsp faild."); + + return 0; +} + +static void oss_renderer_cleanup() { + if (decoder != NULL) { + opus_multistream_decoder_destroy(decoder); + decoder = NULL; + } + + if (pcmBuffer != NULL) { + free(pcmBuffer); + pcmBuffer = NULL; + } + + if (fd != 0) { + close(fd); + fd = 0; + } +} + +static void oss_renderer_decode_and_play_sample(char* data, int length) { + int decodeLen = opus_multistream_decode(decoder, data, length, pcmBuffer, samplesPerFrame, 0); + if (decodeLen > 0) { + write(fd, pcmBuffer, decodeLen * channelCount * sizeof(short)); + } else { + printf("Opus error from decode: %d\n", decodeLen); + } +} + +AUDIO_RENDERER_CALLBACKS audio_callbacks_oss = { + .init = oss_renderer_init, + .cleanup = oss_renderer_cleanup, + .decodeAndPlaySample = oss_renderer_decode_and_play_sample, + .capabilities = CAPABILITY_DIRECT_SUBMIT | CAPABILITY_SUPPORTS_ARBITRARY_AUDIO_DURATION, +}; +#endif diff --git a/src/platform.c b/src/platform.c index 0e873de..fab3057 100644 --- a/src/platform.c +++ b/src/platform.c @@ -202,6 +202,9 @@ AUDIO_RENDERER_CALLBACKS* platform_get_audio(enum platform system, char* audio_d #ifdef HAVE_ALSA return &audio_callbacks_alsa; #endif + #ifdef __FreeBSD__ + return &audio_callbacks_oss; + #endif } return NULL; }