Add 7.1 surround sound support

This commit is contained in:
Cameron Gutman
2020-04-03 17:46:04 -07:00
parent f32d4f2886
commit c7a7fc3fbc
6 changed files with 64 additions and 57 deletions

View File

@@ -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];

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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.