mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Merge pull request #22037 from hrydgard/hide-status-bar-ios
Add setting to hide/show the status bar on iOS
This commit is contained in:
20 files changed
+84
-255
No files matched your search
@@ -976,7 +976,6 @@ elseif(IOS AND NOT LIBRETRO)
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/main.mm
|
||||
ios/CameraHelper.mm
|
||||
ios/AudioEngine.mm
|
||||
ios/LocationHelper.mm
|
||||
ios/Controls.mm
|
||||
Core/Util/DarwinFileSystemServices.mm
|
||||
|
||||
@@ -2539,7 +2539,7 @@ static u32 sceKernelLoadModuleDNAS(const char *name, u32 flags)
|
||||
}
|
||||
|
||||
// Pretty sure this is a badly brute-forced function name...
|
||||
static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, u32 lmoptionPtr)
|
||||
SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, u32 lmoptionPtr)
|
||||
{
|
||||
if (flags != 0) {
|
||||
WARN_LOG_REPORT(Log::Loader, "sceKernelLoadModuleBufferUsbWlan: unsupported flags: %08x", flags);
|
||||
|
||||
@@ -1165,6 +1165,14 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) {
|
||||
switchMode->OnChoice.Add([](EventParams &e) {
|
||||
System_Notify(SystemNotification::APP_SWITCH_MODE_CHANGED);
|
||||
});
|
||||
|
||||
{
|
||||
// Note: On iPhone, iOS hides the status bar in landscape no matter what this is set to.
|
||||
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
|
||||
systemSettings->Add(new CheckBox(&config.bImmersiveMode, sy->T("Hide status bar")))->OnClick.Add([](EventParams &e) {
|
||||
System_Notify(SystemNotification::IMMERSIVE_MODE_CHANGE);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
|
||||
@@ -1424,6 +1424,7 @@ Default tab = Default tab
|
||||
Dynarec/JIT (recommended) = Dynarec/JIT (recommended)
|
||||
Final processed image = Final processed image
|
||||
Hide navigation bar = Hide navigation bar
|
||||
Hide status bar = Hide status bar
|
||||
I/O timing method = I/O timing method
|
||||
JIT using IR = JIT using IR
|
||||
Loaded plugin: %1 = Loaded plugin: %1
|
||||
|
||||
@@ -4,15 +4,11 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
@protocol PPSSPPViewController;
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
@property (strong, nonatomic) UIScreen *screen;
|
||||
@property (nonatomic, strong) NSDictionary *launchOptions;
|
||||
|
||||
- (BOOL)launchPPSSPP:(int)argc argv:(char**)argv;
|
||||
- (void)processFilePath:(NSString *)path;
|
||||
|
||||
// Exports the game library to a caller app via a URL scheme callback.
|
||||
|
||||
@@ -248,8 +248,6 @@ static std::vector<std::string> GatherGameLibrary() {
|
||||
default:
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
return UIInterfaceOrientationMaskAll; // or at least include Portrait
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//
|
||||
// AudioEngine.h
|
||||
// PPSSPP
|
||||
//
|
||||
// Created by rock88 on 15/03/2013.
|
||||
// Copyright (c) 2013 Homebrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface AudioEngine : NSObject
|
||||
|
||||
@end
|
||||
@@ -1,149 +0,0 @@
|
||||
//
|
||||
// AudioEngine.mm
|
||||
// PPSSPP
|
||||
//
|
||||
// Created by rock88 on 15/03/2013.
|
||||
// Copyright (c) 2013 Homebrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AudioEngine.h"
|
||||
#import <OpenAL/al.h>
|
||||
#import <OpenAL/alc.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import <string>
|
||||
|
||||
static volatile BOOL done = 0;
|
||||
|
||||
#define SAMPLE_SIZE 44100
|
||||
static short stream[SAMPLE_SIZE];
|
||||
|
||||
void NativeMix(short *audio, int numSamples, int sampleRateHz, void *userdata);
|
||||
|
||||
@interface AudioEngine ()
|
||||
|
||||
@property (nonatomic,assign) ALCdevice *alcDevice;
|
||||
@property (nonatomic,assign) ALCcontext *alContext;
|
||||
@property (nonatomic,assign) ALuint buffer;
|
||||
@property (nonatomic,assign) ALuint source;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AudioEngine
|
||||
@synthesize alcDevice,alContext,buffer,source;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[self audioInit];
|
||||
[self audioLoop];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self audioShutdown];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)checkALError
|
||||
{
|
||||
ALenum ErrCode;
|
||||
std::string Err = "OpenAL error: ";
|
||||
if ((ErrCode = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
Err += (char *)alGetString(ErrCode);
|
||||
printf("%s\n",Err.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
- (void)audioInit
|
||||
{
|
||||
done = 0;
|
||||
alcDevice = alcOpenDevice(NULL);
|
||||
|
||||
if (alcDevice)
|
||||
{
|
||||
NSLog(@"OpenAL device opened: %s",alcGetString(alcDevice, ALC_DEVICE_SPECIFIER));
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"WARNING: could not open OpenAL device");
|
||||
return;
|
||||
}
|
||||
|
||||
alContext = alcCreateContext(alcDevice, NULL);
|
||||
|
||||
if (alContext)
|
||||
{
|
||||
alcMakeContextCurrent(alContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"ERROR: no OpenAL context");
|
||||
return;
|
||||
}
|
||||
|
||||
alGenSources(1, &source);
|
||||
alGenBuffers(1, &buffer);
|
||||
}
|
||||
|
||||
- (void)audioShutdown
|
||||
{
|
||||
done = 1;
|
||||
alcMakeContextCurrent(NULL);
|
||||
|
||||
if (alContext)
|
||||
{
|
||||
alcDestroyContext(alContext);
|
||||
alContext = NULL;
|
||||
}
|
||||
|
||||
if (alcDevice)
|
||||
{
|
||||
alcCloseDevice(alcDevice);
|
||||
alcDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)playing
|
||||
{
|
||||
ALenum state;
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||||
return (state == AL_PLAYING);
|
||||
}
|
||||
|
||||
- (void)audioLoop
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
|
||||
const int sampleRateHz = 44100;
|
||||
while (!done) {
|
||||
if (![self playing]) {
|
||||
NativeMix(stream, SAMPLE_SIZE / 2, sampleRateHz, 0);
|
||||
frames_ready = SAMPLE_SIZE / 2;
|
||||
} else {
|
||||
frames_ready = 0;
|
||||
}
|
||||
|
||||
if (frames_ready > 0) {
|
||||
const size_t bytes_ready = frames_ready * sizeof(short) * 2;
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
alBufferData(buffer, AL_FORMAT_STEREO16, stream, bytes_ready, sampleRateHz);
|
||||
alSourcei(source, AL_BUFFER, buffer);
|
||||
alSourcePlay(source);
|
||||
|
||||
// TODO: Maybe this could get behind?
|
||||
usleep((1000000 * frames_ready) / sampleRateHz);
|
||||
} else {
|
||||
usleep(100);
|
||||
}
|
||||
pthread_yield_np();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -53,6 +53,10 @@ NSString *getSelectedCamera() {
|
||||
case AVAuthorizationStatusAuthorized: {
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
NSLog(@"unknown camera authorization status %ld, treating as denied", (long)status);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +149,7 @@ NSString *getSelectedCamera() {
|
||||
CGContextDrawImage(outContext, outRect, inImage);
|
||||
CGImageRelease(inImage);
|
||||
CGImageRef outImage = CGBitmapContextCreateImage(outContext);
|
||||
CGContextRelease(outContext);
|
||||
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
|
||||
|
||||
Whitespace-only changes.
+10
-5
@@ -130,19 +130,24 @@
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
case SKPaymentTransactionStateRestored:
|
||||
NSLog(transaction.transactionState == SKPaymentTransactionStatePurchased ? @"IAP Purchase" : @"IAP Restore");
|
||||
NSLog(@"%@", transaction.transactionState == SKPaymentTransactionStatePurchased ? @"IAP Purchase" : @"IAP Restore");
|
||||
// Perform the unlock (updaing the variable and switching the icon).
|
||||
[self unlockGold];
|
||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||
g_requestManager.PostSystemSuccess(_pendingRequestID, "", 0);
|
||||
_pendingRequestID = 0;
|
||||
// The queue also delivers transactions we didn't ask for, like unfinished ones at startup.
|
||||
if (_pendingRequestID != 0) {
|
||||
g_requestManager.PostSystemSuccess(_pendingRequestID, "", 0);
|
||||
_pendingRequestID = 0;
|
||||
}
|
||||
break;
|
||||
case SKPaymentTransactionStateFailed:
|
||||
NSLog(@"[IAPManager] Purchase failed (requestID: %d): %@", _pendingRequestID, transaction.error.localizedDescription);
|
||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||
// Optionally post failure callback here
|
||||
g_requestManager.PostSystemFailure(_pendingRequestID);
|
||||
_pendingRequestID = 0;
|
||||
if (_pendingRequestID != 0) {
|
||||
g_requestManager.PostSystemFailure(_pendingRequestID);
|
||||
_pendingRequestID = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
-(id) init {
|
||||
NSLog(@"LocationHelper::init");
|
||||
locationManager = [[CLLocationManager alloc] init];
|
||||
[locationManager setDelegate:self];
|
||||
self = [super init];
|
||||
if (self) {
|
||||
locationManager = [[CLLocationManager alloc] init];
|
||||
[locationManager setDelegate:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
key.keyCode = getSmartKeyboardMap((int)eventScanCode);
|
||||
key.deviceId = DEVICE_ID_KEYBOARD;
|
||||
NativeKey(key);
|
||||
} else if (GSEVENT_TYPE_KEYDOWN) {
|
||||
} else if (eventType == GSEVENT_TYPE_KEYDOWN) {
|
||||
struct KeyInput key;
|
||||
key.flags = KeyInputFlags::DOWN;
|
||||
key.keyCode = getSmartKeyboardMap((int)eventScanCode);
|
||||
|
||||
+2
-24
@@ -5,7 +5,6 @@
|
||||
// Modified by xSacha
|
||||
// Reworked by hrydgard
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "ViewController.h"
|
||||
#import "iOSCoreAudio.h"
|
||||
|
||||
@@ -56,7 +55,6 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
@property (nonatomic, strong) EAGLContext *glContext;
|
||||
@property (nonatomic, strong) GLKView *glView;
|
||||
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||
@property (nonatomic, assign) NSTimeInterval lastTimestamp;
|
||||
|
||||
@property (nonatomic, strong) EAGLContext* context;
|
||||
|
||||
@@ -134,10 +132,6 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
}
|
||||
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
|
||||
self.lastTimestamp = 0;
|
||||
|
||||
UIScreen* screen = [(AppDelegate*)[UIApplication sharedApplication].delegate screen];
|
||||
self.view.frame = [screen bounds];
|
||||
self.view.multipleTouchEnabled = YES;
|
||||
|
||||
graphicsContext = new OpenGLGraphicsContext();
|
||||
@@ -173,14 +167,12 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
// Resume display link unless explicitly paused
|
||||
INFO_LOG(Log::G3D, "viewWillAppear - resuming display link");
|
||||
INFO_LOG(Log::G3D, "viewWillAppear");
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
// stop rendering while not visible
|
||||
INFO_LOG(Log::G3D, "viewWillDisappear - pausing display link");
|
||||
INFO_LOG(Log::G3D, "viewWillDisappear");
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@@ -205,16 +197,6 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
}
|
||||
|
||||
- (void)displayLinkFired:(CADisplayLink *)dl {
|
||||
// compute delta time
|
||||
NSTimeInterval timestamp = dl.timestamp;
|
||||
NSTimeInterval delta = 0;
|
||||
if (self.lastTimestamp > 0) {
|
||||
delta = timestamp - self.lastTimestamp;
|
||||
} else {
|
||||
delta = dl.duration; // fallback
|
||||
}
|
||||
self.lastTimestamp = timestamp;
|
||||
|
||||
// Ensure context is current before drawing
|
||||
[EAGLContext setCurrentContext:self.glContext];
|
||||
|
||||
@@ -286,10 +268,6 @@ PPSSPPBaseViewController *sharedViewController;
|
||||
[(GLKView*)self.glView bindDrawable];
|
||||
}
|
||||
|
||||
- (UIView *)getView {
|
||||
return [self view];
|
||||
}
|
||||
|
||||
// Can't consolidate this yet.
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
- (void)shareText:(NSString *)text;
|
||||
- (void)shutdown;
|
||||
- (void)bindDefaultFBO;
|
||||
- (UIView *)getView;
|
||||
- (void)startLocation;
|
||||
- (void)stopLocation;
|
||||
- (void)startVideo:(int)width height:(int)height;
|
||||
- (void)stopVideo;
|
||||
- (void)appSwitchModeChanged;
|
||||
- (void)immersiveModeChanged;
|
||||
- (void)setupController:(GCController *)controller;
|
||||
|
||||
// Forwarded from the AppDelegate
|
||||
|
||||
+32
-20
@@ -76,14 +76,17 @@ static int GetPickerRequestId(id picker) {
|
||||
selector:@selector(onOrientationChanged)
|
||||
name:UIDeviceOrientationDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
self.accelerometerQueue = [[NSOperationQueue alloc] init];
|
||||
self.accelerometerQueue.name = @"AccelerometerQueue";
|
||||
self.accelerometerQueue.maxConcurrentOperationCount = 1;
|
||||
|
||||
self.accelerometerQueue = [[NSOperationQueue alloc] init];
|
||||
self.accelerometerQueue.name = @"AccelerometerQueue";
|
||||
self.accelerometerQueue.maxConcurrentOperationCount = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Only means anything for the GL backend, which overrides this.
|
||||
- (void)bindDefaultFBO {}
|
||||
|
||||
- (void)shutdown {
|
||||
self.gameController = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
@@ -481,26 +484,24 @@ extern float g_safeInsetBottom;
|
||||
#endif
|
||||
#pragma mark - Status Bar Control
|
||||
|
||||
// iOS calls this to determine whether to hide the status bar
|
||||
- (BOOL)prefersStatusBarHidden {
|
||||
UIInterfaceOrientation orientation;
|
||||
|
||||
// The immersive mode setting is per-orientation, so we need to know which way we're facing.
|
||||
// Can't just use g_display for this, since it lags behind during rotation.
|
||||
// Note: Using viewIfLoaded, since this can get called before the view exists, and we don't want to force it into existence.
|
||||
- (DeviceOrientation)currentDeviceOrientation {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIWindowScene *scene = self.view.window.windowScene;
|
||||
UIWindowScene *scene = self.viewIfLoaded.window.windowScene;
|
||||
if (scene != nil) {
|
||||
orientation = scene.interfaceOrientation;
|
||||
} else {
|
||||
orientation = UIApplication.sharedApplication.statusBarOrientation;
|
||||
return UIInterfaceOrientationIsPortrait(scene.interfaceOrientation) ? DeviceOrientation::Portrait : DeviceOrientation::Landscape;
|
||||
}
|
||||
} else {
|
||||
orientation = UIApplication.sharedApplication.statusBarOrientation;
|
||||
}
|
||||
CGSize size = self.viewIfLoaded.bounds.size;
|
||||
return size.height > size.width ? DeviceOrientation::Portrait : DeviceOrientation::Landscape;
|
||||
}
|
||||
|
||||
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
|
||||
|
||||
bool userWantsStatusBar = true; // g_Config.bShowStatusBar;
|
||||
// return isLandscape || !userWantsStatusBar;
|
||||
return false;
|
||||
// iOS calls this to determine whether to hide the status bar.
|
||||
// Note that on iPhone, iOS hides it in landscape regardless of what we return here.
|
||||
- (BOOL)prefersStatusBarHidden {
|
||||
return g_Config.GetDisplayLayoutConfig([self currentDeviceOrientation]).bImmersiveMode ? YES : NO;
|
||||
}
|
||||
|
||||
// Optional: choose light/dark text for the status bar
|
||||
@@ -508,11 +509,22 @@ extern float g_safeInsetBottom;
|
||||
return UIStatusBarStyleLightContent;
|
||||
}
|
||||
|
||||
// This should also be called when the user preference changes.
|
||||
- (void)onOrientationChanged {
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
// Called from the C++ side when the user toggles the immersive mode setting.
|
||||
- (void)immersiveModeChanged {
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size
|
||||
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
// The immersive mode setting is per-orientation, so the status bar may need to change along with the rotation.
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
- (void)updateResolutionWithView:(UIView *)view {
|
||||
// 1. Get the scale from the window scene (safest for Metal)
|
||||
CGFloat scale = 1.0;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#import "AppDelegate.h"
|
||||
#import "ViewControllerMetal.h"
|
||||
#import "iOSCoreAudio.h"
|
||||
|
||||
@@ -193,8 +192,6 @@ static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *met
|
||||
|
||||
INFO_LOG(Log::System, "Metal viewDidLoad");
|
||||
|
||||
UIScreen* screen = [(AppDelegate*)[UIApplication sharedApplication].delegate screen];
|
||||
self.view.frame = [screen bounds];
|
||||
self.view.multipleTouchEnabled = YES;
|
||||
// self.view.insetsLayoutMarginsFromSafeArea = NO;
|
||||
// self.view.clipsToBounds = YES;
|
||||
@@ -206,7 +203,9 @@ static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *met
|
||||
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
||||
SetGPUBackend(GPUBackend::OPENGL);
|
||||
delete graphicsContext;
|
||||
// TODO: What to do here?
|
||||
graphicsContext = nullptr; // The render loop and shutdown check for this.
|
||||
// TODO: What to do here? We've switched the config over to GL, but we're still the Metal view controller,
|
||||
// so we won't render anything until the app gets restarted.
|
||||
}
|
||||
|
||||
[self updateResolutionWithView:self.view];
|
||||
@@ -218,10 +217,6 @@ static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *met
|
||||
INFO_LOG(Log::G3D, "Detected size: %dx%d", g_display.pixel_xres, g_display.pixel_yres);
|
||||
}
|
||||
|
||||
- (UIView *)getView {
|
||||
return [self view];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
INFO_LOG(Log::G3D, "viewWillAppear");
|
||||
@@ -245,10 +240,6 @@ static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *met
|
||||
INFO_LOG(Log::G3D, "viewDidDisappear");
|
||||
}
|
||||
|
||||
- (void)bindDefaultFBO {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
|
||||
|
||||
+2
-4
@@ -21,7 +21,5 @@
|
||||
void iOSCoreAudioInit();
|
||||
void iOSCoreAudioShutdown();
|
||||
|
||||
// Ignore mute switch when connected to external display.
|
||||
// Also, obey other settings.
|
||||
void iOSCoreAudioUpdateSession();
|
||||
void iOSCoreAudioSetDisplayConnected(bool connected);
|
||||
// Applies the audio settings (mix with others, respect silent mode) to the session.
|
||||
void iOSCoreAudioUpdateSession();
|
||||
@@ -29,18 +29,9 @@
|
||||
#define SAMPLE_RATE 44100
|
||||
|
||||
static AudioComponentInstance audioInstance = nil;
|
||||
static bool g_displayConnected = false;
|
||||
|
||||
void iOSCoreAudioUpdateSession() {
|
||||
NSError *error = nil;
|
||||
if (g_displayConnected) {
|
||||
INFO_LOG(Log::Audio, "Display connected, setting Playback mode");
|
||||
// Special handling when a display is connected. Always exclusive.
|
||||
// Let's revisit this later.
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(Log::Audio, "RespectSilentMode: %d MixWithOthers: %d", g_Config.bAudioRespectSilentMode, g_Config.bAudioMixWithOthers);
|
||||
|
||||
// Hacky hack to force iOS to re-evaluate.
|
||||
@@ -48,7 +39,6 @@ void iOSCoreAudioUpdateSession() {
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAudioProcessing error:&error];
|
||||
|
||||
// Here, we apply the settings.
|
||||
const bool mixWithOthers = g_Config.bAudioMixWithOthers;
|
||||
if (g_Config.bAudioMixWithOthers) {
|
||||
if (g_Config.bAudioRespectSilentMode) {
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
|
||||
@@ -69,11 +59,6 @@ void iOSCoreAudioUpdateSession() {
|
||||
}
|
||||
}
|
||||
|
||||
void iOSCoreAudioSetDisplayConnected(bool connected) {
|
||||
g_displayConnected = connected;
|
||||
iOSCoreAudioUpdateSession();
|
||||
}
|
||||
|
||||
void NativeMix(short *audio, int numSamples, int sampleRateHz, void *userdata);
|
||||
|
||||
OSStatus iOSCoreAudioCallback(void *inRefCon,
|
||||
|
||||
+13
-1
@@ -432,6 +432,13 @@ void System_Notify(SystemNotification notification) {
|
||||
}
|
||||
});
|
||||
break;
|
||||
case SystemNotification::IMMERSIVE_MODE_CHANGE:
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (sharedViewController) {
|
||||
[sharedViewController immersiveModeChanged];
|
||||
}
|
||||
});
|
||||
break;
|
||||
case SystemNotification::UI_STATE_CHANGED:
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (sharedViewController) {
|
||||
@@ -452,6 +459,7 @@ void System_Notify(SystemNotification notification) {
|
||||
[UIViewController attemptRotationToDeviceOrientation];
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -596,7 +604,11 @@ void System_AskForPermission(SystemPermission permission) {}
|
||||
|
||||
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
|
||||
std::string strUrl(url);
|
||||
NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:strUrl.c_str() encoding:NSStringEncodingConversionAllowLossy]];
|
||||
NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithUTF8String:strUrl.c_str()]];
|
||||
if (!nsUrl) {
|
||||
ERROR_LOG(Log::System, "Failed to parse URL: %s", strUrl.c_str());
|
||||
return;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[UIApplication sharedApplication] openURL:nsUrl options:@{} completionHandler:nil];
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user