mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-02-16 02:20:53 +00:00
Add 7.1 surround sound support
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
#include <libxml2/libxml/xmlreader.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Limelight.h>
|
||||
|
||||
#define SHORT_TIMEOUT_SEC 2
|
||||
#define NORMAL_TIMEOUT_SEC 5
|
||||
#define LONG_TIMEOUT_SEC 60
|
||||
@@ -214,7 +216,7 @@ static const NSString* HTTPS_PORT = @"47984";
|
||||
[Utils bytesToHex:config.riKey], config.riKeyId,
|
||||
config.enableHdr ? @"&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0": @"",
|
||||
config.playAudioOnPC ? 1 : 0,
|
||||
(config.audioChannelMask << 16) | config.audioChannelCount,
|
||||
SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(config.audioConfiguration),
|
||||
config.gamepadMask, config.gamepadMask];
|
||||
Log(LOG_I, @"Requesting: %@", urlString);
|
||||
// This blocks while the app is launching
|
||||
@@ -225,7 +227,7 @@ static const NSString* HTTPS_PORT = @"47984";
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d&surroundAudioInfo=%d",
|
||||
_baseHTTPSURL, _uniqueId,
|
||||
[Utils bytesToHex:config.riKey], config.riKeyId,
|
||||
(config.audioChannelMask << 16) | config.audioChannelCount];
|
||||
SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(config.audioConfiguration)];
|
||||
Log(LOG_I, @"Requesting: %@", urlString);
|
||||
// This blocks while the app is resuming
|
||||
return [self createRequestFromString:urlString timeout:LONG_TIMEOUT_SEC];
|
||||
|
||||
@@ -100,37 +100,64 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
||||
pts:decodeUnit->presentationTimeMs];
|
||||
}
|
||||
|
||||
int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int flags)
|
||||
int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION originalOpusConfig, void* context, int flags)
|
||||
{
|
||||
int err;
|
||||
AudioChannelLayout channelLayout = {};
|
||||
OPUS_MULTISTREAM_CONFIGURATION opusConfig = *originalOpusConfig;
|
||||
|
||||
// Initialize the circular buffer
|
||||
audioBufferWriteIndex = audioBufferReadIndex = 0;
|
||||
audioSamplesPerFrame = opusConfig->samplesPerFrame;
|
||||
audioBufferStride = opusConfig->channelCount * opusConfig->samplesPerFrame;
|
||||
audioBufferEntries = CIRCULAR_BUFFER_DURATION / (opusConfig->samplesPerFrame / (opusConfig->sampleRate / 1000));
|
||||
audioSamplesPerFrame = opusConfig.samplesPerFrame;
|
||||
audioBufferStride = opusConfig.channelCount * opusConfig.samplesPerFrame;
|
||||
audioBufferEntries = CIRCULAR_BUFFER_DURATION / (opusConfig.samplesPerFrame / (opusConfig.sampleRate / 1000));
|
||||
audioCircularBuffer = malloc(audioBufferEntries * audioBufferStride * sizeof(short));
|
||||
if (audioCircularBuffer == NULL) {
|
||||
Log(LOG_E, @"Error allocating output queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
opusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
||||
opusConfig->channelCount,
|
||||
opusConfig->streams,
|
||||
opusConfig->coupledStreams,
|
||||
opusConfig->mapping,
|
||||
|
||||
switch (opusConfig.channelCount) {
|
||||
case 2:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
|
||||
break;
|
||||
case 4:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Quadraphonic;
|
||||
break;
|
||||
case 6:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
|
||||
break;
|
||||
case 8:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_7_1;
|
||||
|
||||
// Swap SL/SR and RL/RR to match the selected channel layout
|
||||
opusConfig.mapping[4] = originalOpusConfig->mapping[6];
|
||||
opusConfig.mapping[5] = originalOpusConfig->mapping[7];
|
||||
opusConfig.mapping[6] = originalOpusConfig->mapping[4];
|
||||
opusConfig.mapping[7] = originalOpusConfig->mapping[5];
|
||||
break;
|
||||
default:
|
||||
// Unsupported channel layout
|
||||
Log(LOG_E, @"Unsupported channel layout: %d\n", opusConfig.channelCount);
|
||||
abort();
|
||||
}
|
||||
|
||||
opusDecoder = opus_multistream_decoder_create(opusConfig.sampleRate,
|
||||
opusConfig.channelCount,
|
||||
opusConfig.streams,
|
||||
opusConfig.coupledStreams,
|
||||
opusConfig.mapping,
|
||||
&err);
|
||||
|
||||
// Configure the audio session for our app
|
||||
NSError *audioSessionError = nil;
|
||||
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
||||
|
||||
[audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
|
||||
[audioSession setPreferredSampleRate:opusConfig.sampleRate error:&audioSessionError];
|
||||
[audioSession setCategory:AVAudioSessionCategoryPlayback
|
||||
withOptions:AVAudioSessionCategoryOptionMixWithOthers
|
||||
error:&audioSessionError];
|
||||
[audioSession setPreferredIOBufferDuration:(opusConfig->samplesPerFrame / (opusConfig->sampleRate / 1000)) / 1000.0
|
||||
[audioSession setPreferredIOBufferDuration:(opusConfig.samplesPerFrame / (opusConfig.sampleRate / 1000)) / 1000.0
|
||||
error:&audioSessionError];
|
||||
[audioSession setActive: YES error: &audioSessionError];
|
||||
|
||||
@@ -140,11 +167,11 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
OSStatus status;
|
||||
|
||||
AudioStreamBasicDescription audioFormat = {0};
|
||||
audioFormat.mSampleRate = opusConfig->sampleRate;
|
||||
audioFormat.mSampleRate = opusConfig.sampleRate;
|
||||
audioFormat.mBitsPerChannel = 16;
|
||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
||||
audioFormat.mChannelsPerFrame = opusConfig->channelCount;
|
||||
audioFormat.mChannelsPerFrame = opusConfig.channelCount;
|
||||
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
|
||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
|
||||
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
|
||||
@@ -157,28 +184,14 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
}
|
||||
|
||||
// We need to specify a channel layout for surround sound configurations
|
||||
if (opusConfig->channelCount > 2) {
|
||||
AudioChannelLayout channelLayout = {};
|
||||
|
||||
switch (opusConfig->channelCount) {
|
||||
case 6:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A;
|
||||
break;
|
||||
default:
|
||||
// Unsupported channel layout
|
||||
Log(LOG_E, @"Unsupported channel layout: %d\n", opusConfig->channelCount);
|
||||
abort();
|
||||
}
|
||||
|
||||
status = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_ChannelLayout, &channelLayout, sizeof(channelLayout));
|
||||
if (status != noErr) {
|
||||
Log(LOG_E, @"Error configuring surround channel layout: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_ChannelLayout, &channelLayout, sizeof(channelLayout));
|
||||
if (status != noErr) {
|
||||
Log(LOG_E, @"Error configuring surround channel layout: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
for (int i = 0; i < AUDIO_QUEUE_BUFFERS; i++) {
|
||||
status = AudioQueueAllocateBuffer(audioQueue, audioFormat.mBytesPerFrame * opusConfig->samplesPerFrame, &audioBuffers[i]);
|
||||
status = AudioQueueAllocateBuffer(audioQueue, audioFormat.mBytesPerFrame * opusConfig.samplesPerFrame, &audioBuffers[i]);
|
||||
if (status != noErr) {
|
||||
Log(LOG_E, @"Error allocating output buffer: %d\n", status);
|
||||
return status;
|
||||
@@ -342,6 +355,7 @@ void ClConnectionStatusUpdate(int status)
|
||||
_streamConfig.fps = config.frameRate;
|
||||
_streamConfig.bitrate = config.bitRate;
|
||||
_streamConfig.enableHdr = config.enableHdr;
|
||||
_streamConfig.audioConfiguration = config.audioConfiguration;
|
||||
|
||||
// Use some of the HEVC encoding efficiency improvements to
|
||||
// reduce bandwidth usage while still gaining some image
|
||||
@@ -359,18 +373,6 @@ void ClConnectionStatusUpdate(int status)
|
||||
_streamConfig.packetSize = 1392;
|
||||
}
|
||||
|
||||
switch (config.audioChannelCount) {
|
||||
case 2:
|
||||
_streamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
|
||||
break;
|
||||
case 6:
|
||||
_streamConfig.audioConfiguration = AUDIO_CONFIGURATION_51_SURROUND;
|
||||
break;
|
||||
default:
|
||||
Log(LOG_E, @"Unknown audio channel count: %d", config.audioChannelCount);
|
||||
abort();
|
||||
}
|
||||
|
||||
// HDR implies HEVC allowed
|
||||
if (config.enableHdr) {
|
||||
config.allowHevc = YES;
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
@property int gamepadMask;
|
||||
@property BOOL optimizeGameSettings;
|
||||
@property BOOL playAudioOnPC;
|
||||
@property int audioChannelCount;
|
||||
@property int audioChannelMask;
|
||||
@property int audioConfiguration;
|
||||
@property BOOL enableHdr;
|
||||
@property BOOL multiController;
|
||||
@property BOOL allowHevc;
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
#import "StreamConfiguration.h"
|
||||
|
||||
@implementation StreamConfiguration
|
||||
@synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, streamingRemotely, appName, optimizeGameSettings, playAudioOnPC, audioChannelMask, audioChannelCount, enableHdr, multiController, allowHevc, serverCert;
|
||||
@synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey, gamepadMask, streamingRemotely, appName, optimizeGameSettings, playAudioOnPC, audioConfiguration, enableHdr, multiController, allowHevc, serverCert;
|
||||
@end
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
#import <VideoToolbox/VideoToolbox.h>
|
||||
|
||||
#include <Limelight.h>
|
||||
|
||||
@implementation MainFrameViewController {
|
||||
NSOperationQueue* _opQueue;
|
||||
TemporaryHost* _selectedHost;
|
||||
@@ -548,14 +550,16 @@ static NSMutableSet* hostList;
|
||||
|
||||
|
||||
// Probe for supported channel configurations
|
||||
Log(LOG_I, @"Audio device supports %d channels", [AVAudioSession sharedInstance].maximumOutputNumberOfChannels);
|
||||
if ([AVAudioSession sharedInstance].maximumOutputNumberOfChannels >= 6) {
|
||||
_streamConfig.audioChannelCount = 6;
|
||||
_streamConfig.audioChannelMask = 0xFC;
|
||||
long outputChannels = [AVAudioSession sharedInstance].maximumOutputNumberOfChannels;
|
||||
Log(LOG_I, @"Audio device supports %d channels", outputChannels);
|
||||
if (outputChannels >= 8) {
|
||||
_streamConfig.audioConfiguration = AUDIO_CONFIGURATION_71_SURROUND;
|
||||
}
|
||||
else if (outputChannels >= 6) {
|
||||
_streamConfig.audioConfiguration = AUDIO_CONFIGURATION_51_SURROUND;
|
||||
}
|
||||
else {
|
||||
_streamConfig.audioChannelCount = 2;
|
||||
_streamConfig.audioChannelMask = 0x3;
|
||||
_streamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
|
||||
}
|
||||
|
||||
// HDR requires HDR10 game, HDR10 display, and HEVC Main10 decoder on the client.
|
||||
|
||||
Reference in New Issue
Block a user