mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-04-18 22:39:53 +00:00
Add 5.1 surround sound support
This commit is contained in:
@@ -20,30 +20,49 @@
|
|||||||
#include "../audio.h"
|
#include "../audio.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <opus.h>
|
#include <opus_multistream.h>
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
#define CHECK_RETURN(f) if ((rc = f) < 0) { printf("Alsa error code %d\n", rc); exit(-1); }
|
#define CHECK_RETURN(f) if ((rc = f) < 0) { printf("Alsa error code %d\n", rc); exit(-1); }
|
||||||
|
|
||||||
#define SAMPLE_RATE 48000
|
#define MAX_CHANNEL_COUNT 6
|
||||||
#define CHANNEL_COUNT 2
|
|
||||||
#define FRAME_SIZE 240
|
#define FRAME_SIZE 240
|
||||||
|
|
||||||
const char* audio_device = "sysdefault";
|
const char* audio_device = "sysdefault";
|
||||||
|
|
||||||
static snd_pcm_t *handle;
|
static snd_pcm_t *handle;
|
||||||
static OpusDecoder* decoder;
|
static OpusMSDecoder* decoder;
|
||||||
static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT];
|
static short pcmBuffer[FRAME_SIZE * MAX_CHANNEL_COUNT];
|
||||||
|
|
||||||
static void alsa_renderer_init() {
|
static void alsa_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) {
|
||||||
int rc;
|
int rc;
|
||||||
decoder = opus_decoder_create(SAMPLE_RATE, CHANNEL_COUNT, &rc);
|
unsigned char alsaMapping[6];
|
||||||
|
|
||||||
|
/* The supplied mapping array has order: FL-FR-C-LFE-RL-RR
|
||||||
|
* ALSA expects the order: FL-FR-RL-RR-C-LFE
|
||||||
|
* We need copy the mapping locally and swap the channels around.
|
||||||
|
*/
|
||||||
|
alsaMapping[0] = opusConfig->mapping[0];
|
||||||
|
alsaMapping[1] = opusConfig->mapping[1];
|
||||||
|
if (opusConfig->channelCount == 6) {
|
||||||
|
alsaMapping[2] = opusConfig->mapping[4];
|
||||||
|
alsaMapping[3] = opusConfig->mapping[5];
|
||||||
|
alsaMapping[4] = opusConfig->mapping[2];
|
||||||
|
alsaMapping[5] = opusConfig->mapping[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
||||||
|
opusConfig->channelCount,
|
||||||
|
opusConfig->streams,
|
||||||
|
opusConfig->coupledStreams,
|
||||||
|
alsaMapping,
|
||||||
|
&rc);
|
||||||
|
|
||||||
snd_pcm_hw_params_t *hw_params;
|
snd_pcm_hw_params_t *hw_params;
|
||||||
snd_pcm_sw_params_t *sw_params;
|
snd_pcm_sw_params_t *sw_params;
|
||||||
snd_pcm_uframes_t period_size = FRAME_SIZE * CHANNEL_COUNT * 2;
|
snd_pcm_uframes_t period_size = FRAME_SIZE * opusConfig->channelCount * 2;
|
||||||
snd_pcm_uframes_t buffer_size = 12 * period_size;
|
snd_pcm_uframes_t buffer_size = 12 * period_size;
|
||||||
unsigned int sampleRate = SAMPLE_RATE;
|
unsigned int sampleRate = opusConfig->sampleRate;
|
||||||
|
|
||||||
/* Open PCM device for playback. */
|
/* Open PCM device for playback. */
|
||||||
CHECK_RETURN(snd_pcm_open(&handle, audio_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
|
CHECK_RETURN(snd_pcm_open(&handle, audio_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))
|
||||||
@@ -54,7 +73,7 @@ static void alsa_renderer_init() {
|
|||||||
CHECK_RETURN(snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
|
CHECK_RETURN(snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
|
||||||
CHECK_RETURN(snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE));
|
CHECK_RETURN(snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16_LE));
|
||||||
CHECK_RETURN(snd_pcm_hw_params_set_rate_near(handle, hw_params, &sampleRate, NULL));
|
CHECK_RETURN(snd_pcm_hw_params_set_rate_near(handle, hw_params, &sampleRate, NULL));
|
||||||
CHECK_RETURN(snd_pcm_hw_params_set_channels(handle, hw_params, CHANNEL_COUNT));
|
CHECK_RETURN(snd_pcm_hw_params_set_channels(handle, hw_params, opusConfig->channelCount));
|
||||||
CHECK_RETURN(snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffer_size));
|
CHECK_RETURN(snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &buffer_size));
|
||||||
CHECK_RETURN(snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, NULL));
|
CHECK_RETURN(snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, NULL));
|
||||||
CHECK_RETURN(snd_pcm_hw_params(handle, hw_params));
|
CHECK_RETURN(snd_pcm_hw_params(handle, hw_params));
|
||||||
@@ -73,7 +92,7 @@ static void alsa_renderer_init() {
|
|||||||
|
|
||||||
static void alsa_renderer_cleanup() {
|
static void alsa_renderer_cleanup() {
|
||||||
if (decoder != NULL)
|
if (decoder != NULL)
|
||||||
opus_decoder_destroy(decoder);
|
opus_multistream_decoder_destroy(decoder);
|
||||||
|
|
||||||
if (handle != NULL) {
|
if (handle != NULL) {
|
||||||
snd_pcm_drain(handle);
|
snd_pcm_drain(handle);
|
||||||
@@ -82,7 +101,7 @@ static void alsa_renderer_cleanup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void alsa_renderer_decode_and_play_sample(char* data, int length) {
|
static void alsa_renderer_decode_and_play_sample(char* data, int length) {
|
||||||
int decodeLen = opus_decode(decoder, data, length, pcmBuffer, FRAME_SIZE, 0);
|
int decodeLen = opus_multistream_decode(decoder, data, length, pcmBuffer, FRAME_SIZE, 0);
|
||||||
if (decodeLen > 0) {
|
if (decodeLen > 0) {
|
||||||
int rc = snd_pcm_writei(handle, pcmBuffer, decodeLen);
|
int rc = snd_pcm_writei(handle, pcmBuffer, decodeLen);
|
||||||
if (rc == -EPIPE)
|
if (rc == -EPIPE)
|
||||||
|
|||||||
@@ -23,27 +23,34 @@
|
|||||||
#include <SDL_audio.h>
|
#include <SDL_audio.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <opus.h>
|
#include <opus_multistream.h>
|
||||||
|
|
||||||
#define SAMPLE_RATE 48000
|
#define MAX_CHANNEL_COUNT 6
|
||||||
#define CHANNEL_COUNT 2
|
|
||||||
#define FRAME_SIZE 240
|
#define FRAME_SIZE 240
|
||||||
|
|
||||||
static OpusDecoder* decoder;
|
static OpusMSDecoder* decoder;
|
||||||
static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT];
|
static short pcmBuffer[FRAME_SIZE * MAX_CHANNEL_COUNT];
|
||||||
static SDL_AudioDeviceID dev;
|
static SDL_AudioDeviceID dev;
|
||||||
|
static int channelCount;
|
||||||
|
|
||||||
static void sdl_renderer_init() {
|
static void sdl_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) {
|
||||||
int rc;
|
int rc;
|
||||||
decoder = opus_decoder_create(SAMPLE_RATE, CHANNEL_COUNT, &rc);
|
decoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
||||||
|
opusConfig->channelCount,
|
||||||
|
opusConfig->streams,
|
||||||
|
opusConfig->coupledStreams,
|
||||||
|
opusConfig->mapping,
|
||||||
|
&rc);
|
||||||
|
|
||||||
|
channelCount = opusConfig->channelCount;
|
||||||
|
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
|
|
||||||
SDL_AudioSpec want, have;
|
SDL_AudioSpec want, have;
|
||||||
SDL_zero(want);
|
SDL_zero(want);
|
||||||
want.freq = SAMPLE_RATE;
|
want.freq = opusConfig->sampleRate;
|
||||||
want.format = AUDIO_S16LSB;
|
want.format = AUDIO_S16LSB;
|
||||||
want.channels = CHANNEL_COUNT;
|
want.channels = opusConfig->channelCount;
|
||||||
want.samples = 4096;
|
want.samples = 4096;
|
||||||
|
|
||||||
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
|
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
|
||||||
@@ -58,15 +65,15 @@ static void sdl_renderer_init() {
|
|||||||
|
|
||||||
static void sdl_renderer_cleanup() {
|
static void sdl_renderer_cleanup() {
|
||||||
if (decoder != NULL)
|
if (decoder != NULL)
|
||||||
opus_decoder_destroy(decoder);
|
opus_multistream_decoder_destroy(decoder);
|
||||||
|
|
||||||
SDL_CloseAudioDevice(dev);
|
SDL_CloseAudioDevice(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdl_renderer_decode_and_play_sample(char* data, int length) {
|
static void sdl_renderer_decode_and_play_sample(char* data, int length) {
|
||||||
int decodeLen = opus_decode(decoder, data, length, pcmBuffer, FRAME_SIZE, 0);
|
int decodeLen = opus_multistream_decode(decoder, data, length, pcmBuffer, FRAME_SIZE, 0);
|
||||||
if (decodeLen > 0) {
|
if (decodeLen > 0) {
|
||||||
SDL_QueueAudio(dev, pcmBuffer, decodeLen * CHANNEL_COUNT * sizeof(short));
|
SDL_QueueAudio(dev, pcmBuffer, decodeLen * channelCount * sizeof(short));
|
||||||
} else {
|
} else {
|
||||||
printf("Opus error from decode: %d\n", decodeLen);
|
printf("Opus error from decode: %d\n", decodeLen);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ static struct option long_options[] = {
|
|||||||
{"keydir", required_argument, NULL, 'r'},
|
{"keydir", required_argument, NULL, 'r'},
|
||||||
{"remote", no_argument, NULL, 's'},
|
{"remote", no_argument, NULL, 's'},
|
||||||
{"fullscreen", no_argument, NULL, 't'},
|
{"fullscreen", no_argument, NULL, 't'},
|
||||||
|
{"surround", no_argument, NULL, 'u'},
|
||||||
{0, 0, 0, 0},
|
{0, 0, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,6 +188,10 @@ static void parse_argument(int c, char* value, PCONFIGURATION config) {
|
|||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
config->fullscreen = true;
|
config->fullscreen = true;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
config->stream.audioConfiguration = AUDIO_CONFIGURATION_51_SURROUND;
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (config->action == NULL)
|
if (config->action == NULL)
|
||||||
config->action = value;
|
config->action = value;
|
||||||
@@ -259,12 +264,15 @@ void config_save(char* filename, PCONFIGURATION config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void config_parse(int argc, char* argv[], PCONFIGURATION config) {
|
void config_parse(int argc, char* argv[], PCONFIGURATION config) {
|
||||||
|
LiInitializeStreamConfiguration(&config->stream);
|
||||||
|
|
||||||
config->stream.width = 1280;
|
config->stream.width = 1280;
|
||||||
config->stream.height = 720;
|
config->stream.height = 720;
|
||||||
config->stream.fps = 60;
|
config->stream.fps = 60;
|
||||||
config->stream.bitrate = -1;
|
config->stream.bitrate = -1;
|
||||||
config->stream.packetSize = 1024;
|
config->stream.packetSize = 1024;
|
||||||
config->stream.streamingRemotely = 0;
|
config->stream.streamingRemotely = 0;
|
||||||
|
config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
|
||||||
|
|
||||||
config->platform = "default";
|
config->platform = "default";
|
||||||
config->app = "Steam";
|
config->app = "Steam";
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ static void help() {
|
|||||||
printf("\t-app <app>\t\tName of app to stream\n");
|
printf("\t-app <app>\t\tName of app to stream\n");
|
||||||
printf("\t-nosops\t\t\tDon't allow GFE to modify game settings\n");
|
printf("\t-nosops\t\t\tDon't allow GFE to modify game settings\n");
|
||||||
printf("\t-localaudio\t\tPlay audio locally\n");
|
printf("\t-localaudio\t\tPlay audio locally\n");
|
||||||
|
printf("\t-surround\t\tStream 5.1 surround sound (requires GFE 2.7)\n");
|
||||||
printf("\t-keydir <directory>\tLoad encryption keys from directory\n");
|
printf("\t-keydir <directory>\tLoad encryption keys from directory\n");
|
||||||
#ifdef HAVE_SDL
|
#ifdef HAVE_SDL
|
||||||
printf("\n Video options (SDL Only)\n\n");
|
printf("\n Video options (SDL Only)\n\n");
|
||||||
|
|||||||
2
third_party/moonlight-common-c
vendored
2
third_party/moonlight-common-c
vendored
Submodule third_party/moonlight-common-c updated: 2d35d7262f...81ecd32e83
Reference in New Issue
Block a user