diff --git a/src/audio/alsa.c b/src/audio/alsa.c index 036cf71..3999b2c 100644 --- a/src/audio/alsa.c +++ b/src/audio/alsa.c @@ -20,30 +20,49 @@ #include "../audio.h" #include -#include +#include #include #define CHECK_RETURN(f) if ((rc = f) < 0) { printf("Alsa error code %d\n", rc); exit(-1); } -#define SAMPLE_RATE 48000 -#define CHANNEL_COUNT 2 +#define MAX_CHANNEL_COUNT 6 #define FRAME_SIZE 240 const char* audio_device = "sysdefault"; static snd_pcm_t *handle; -static OpusDecoder* decoder; -static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT]; +static OpusMSDecoder* decoder; +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; - 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_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; - unsigned int sampleRate = SAMPLE_RATE; + unsigned int sampleRate = opusConfig->sampleRate; /* Open PCM device for playback. */ 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_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_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_period_size_near(handle, hw_params, &period_size, NULL)); CHECK_RETURN(snd_pcm_hw_params(handle, hw_params)); @@ -73,7 +92,7 @@ static void alsa_renderer_init() { static void alsa_renderer_cleanup() { if (decoder != NULL) - opus_decoder_destroy(decoder); + opus_multistream_decoder_destroy(decoder); if (handle != NULL) { 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) { - 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) { int rc = snd_pcm_writei(handle, pcmBuffer, decodeLen); if (rc == -EPIPE) diff --git a/src/audio/sdl.c b/src/audio/sdl.c index f7ebc9b..8da514a 100644 --- a/src/audio/sdl.c +++ b/src/audio/sdl.c @@ -23,27 +23,34 @@ #include #include -#include +#include -#define SAMPLE_RATE 48000 -#define CHANNEL_COUNT 2 +#define MAX_CHANNEL_COUNT 6 #define FRAME_SIZE 240 -static OpusDecoder* decoder; -static short pcmBuffer[FRAME_SIZE * CHANNEL_COUNT]; +static OpusMSDecoder* decoder; +static short pcmBuffer[FRAME_SIZE * MAX_CHANNEL_COUNT]; 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; - 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_AudioSpec want, have; SDL_zero(want); - want.freq = SAMPLE_RATE; + want.freq = opusConfig->sampleRate; want.format = AUDIO_S16LSB; - want.channels = CHANNEL_COUNT; + want.channels = opusConfig->channelCount; want.samples = 4096; 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() { if (decoder != NULL) - opus_decoder_destroy(decoder); + opus_multistream_decoder_destroy(decoder); SDL_CloseAudioDevice(dev); } 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) { - SDL_QueueAudio(dev, pcmBuffer, decodeLen * CHANNEL_COUNT * sizeof(short)); + SDL_QueueAudio(dev, pcmBuffer, decodeLen * channelCount * sizeof(short)); } else { printf("Opus error from decode: %d\n", decodeLen); } diff --git a/src/config.c b/src/config.c index 225bbe4..dfde033 100644 --- a/src/config.c +++ b/src/config.c @@ -60,6 +60,7 @@ static struct option long_options[] = { {"keydir", required_argument, NULL, 'r'}, {"remote", no_argument, NULL, 's'}, {"fullscreen", no_argument, NULL, 't'}, + {"surround", no_argument, NULL, 'u'}, {0, 0, 0, 0}, }; @@ -187,6 +188,10 @@ static void parse_argument(int c, char* value, PCONFIGURATION config) { break; case 't': config->fullscreen = true; + break; + case 'u': + config->stream.audioConfiguration = AUDIO_CONFIGURATION_51_SURROUND; + break; case 1: if (config->action == NULL) config->action = value; @@ -259,12 +264,15 @@ void config_save(char* filename, PCONFIGURATION config) { } void config_parse(int argc, char* argv[], PCONFIGURATION config) { + LiInitializeStreamConfiguration(&config->stream); + config->stream.width = 1280; config->stream.height = 720; config->stream.fps = 60; config->stream.bitrate = -1; config->stream.packetSize = 1024; config->stream.streamingRemotely = 0; + config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO; config->platform = "default"; config->app = "Steam"; diff --git a/src/main.c b/src/main.c index c0b8def..53335ad 100644 --- a/src/main.c +++ b/src/main.c @@ -135,6 +135,7 @@ static void help() { printf("\t-app \t\tName of app to stream\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-surround\t\tStream 5.1 surround sound (requires GFE 2.7)\n"); printf("\t-keydir \tLoad encryption keys from directory\n"); #ifdef HAVE_SDL printf("\n Video options (SDL Only)\n\n"); diff --git a/third_party/moonlight-common-c b/third_party/moonlight-common-c index 2d35d72..81ecd32 160000 --- a/third_party/moonlight-common-c +++ b/third_party/moonlight-common-c @@ -1 +1 @@ -Subproject commit 2d35d7262ffe79925114d4b5e331e52c6a436d9f +Subproject commit 81ecd32e833035d89538a5a5c78b4ad61ecdceb5