AKAudioPlayer: No sound in speakers, only with headphones - core-audio

Using AudioKit for sound management, I noticed an issue (bug?) with this very simple piece of code.
import AudioKit
class MainViewController: UIViewController {
var audioFile: AKAudioFile?
var audioPlayer: AKAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func onPlayButtonClick(_ sender: Any) {
do {
audioFile = try AKAudioFile(forReading: Bundle.main.url(forResource: "3e", withExtension: "mp3")!)
audioPlayer = try AKAudioPlayer(file: audioFile!)
AudioKit.output = audioPlayer
AudioKit.start()
audioPlayer!.play()
} catch {
print(error)
}
}
}
When launching the playback with play() method, everything is normal in logs and in the process (player duration, currentTime). BUT I do not hear the audio in speakers (only a kind of wind noise). As soon as I plug my headphones and tap the button again, I normally hear the audio. Then, I unplug my headphones and tap the button, I don’t hear audio (only that wind noise).
I face this on iPhone 5S.
I do not face this on iPad5, I do not face this on simulators. I don’t have the other devices to try to reproduce.
Both devices: iOS 11.1.2 and AudioKit : v4.0.4
NB: my speakers works normally with any other app and I’ve checked the volume. The default outputDevice is set to Speakers when headphones are not plugged.

According to the Configuring an Audio Session guide, by default, the AVAudioSessionCategory is set so that
In iOS, setting the Ring/Silent switch to silent mode silences any audio being played by the app.
Since iPads and the simulator don't have this switch they will always play to the speaker, but in the case of hardware iPhones, they will only play to the headphones and not to the speakers when in silent mode, unless the session category is changed.
You can change the session category directly with AVAudioSession:
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
catch {
print("failed to set category")
}
or you can use AudioKit's AKSettings wrapper:
AudioKit.start()
do {
try AKSettings.setSession(category: AKSettings.SessionCategory.playback)
} catch {
print("failed to set category")
}
According to the AVSessionCategory docs, the Playback category is
The category for playing recorded music or other sounds that are
central to the successful use of your app.
so it will assume the user wants the silent mode to be overridden when using the app.

Related

How can I capture an image from a preview video stream from the device camera using custom renderer view xamarin forms

I'm implementing biometric facial authentication in my Xamarin.forms app (Android and iOS). I am basing myself on this example to capture the user's face which implements custom renderer (Android), but in this example: https://github.com/UNIT-23/Xam-Android-Camera2-Sample the image must be touched to capture it, I would like to capture this image every 3 seconds without the user having to touch, like second option I would like to capture the photo with a button, but I don't really know how to implement it, so any help or example suggestions would be greatly appreciated.
Thanks in advance for your help and your time!
check
Alternatively, for Xamarin.Forms, you have access to a cross-platform Timer via the Device class:
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
// called every 1 second
// do stuff here
return true; // return true to repeat counting, false to stop timer
});

Resume NSProgressIndicator animation after window minimised and then restored

I'm having trouble with the animation of some subclassed indeterminate NSProgressIndicators. They start and stop animating without any issues. However, if I minimise the window while animating, stopAnimation: / StopAnimation(NSObject sender) is called, which makes sense to save resources if the window is not visible. I assume this is invoked from the cocoa framework itself looking at the stacktrace.
The problem then arises when the window is restored, the animation is not resumed.
I've seen you can use the NSCoding Protocol and can override encodeWithEncoder: / EncodeTo(NSCoder encoder) to save some state, and then use that saved state in initWithCoder: / AppProgressIndicatorBar(NSCoder coder) to resume. But the problem here was that my encodeWithEncoder: / EncodeTo(NSCoder encoder) was never called.
Looking at this SO question and answer, it should be handled automatically if the object needs to be serialized. So I'm not sure why it's not being called.
That same answer says you can do it explicitly with NSKeyedArchiver, but then I would need to listen with NSWindowDelegate to know when the window is minimizing / restoring. In which case, I could just use this, and not use the NSCoding Protocol...
This just feels dirty, and I would imagine this is a very common scenario. So how should / do you resume animation? I'm new to cocoa, coming from a mostly .NET background, and I think this problem is a symptom of my limited cocoa knowledge.
I'm using Xamarin Mac, and have tried to give the Objective-C and C# method signatures. I'll be happy for a solution in either, I'll be able to (hopefully!) convert it to the C# equivalent.
For completeness, here is my current Xamarin Mac subclass using the NSCoder Protocol where EncodeTo is not being called. I'm running OS X 10.11.3 and Xamarin Studio 5.10.2.
[Register("AppProgressIndicatorBar")]
public class AppProgressIndicatorBar : NSProgressIndicator, INSCoding
{
...
public AppProgressIndicatorBar(NSCoder coder) : base(coder)
{
...
}
...
public override void EncodeTo(NSCoder encoder)
{
base.EncodeTo(encoder);
...
}
...
}
You should be able to use the NSWindowWillMiniaturizeNotification, NSWindowDidMiniaturizeNotification and NSWindowDidDeminiaturizeNotification notifications or the windowWillMiniaturize:, windowDidMiniaturize: and windowDidDeminiaturize: Window delegate methods to track the state of your window and restore the state of your progress bar when the window deminiaturises (is that really a word?).
HTH

Need help setting up an interface where rotation is fixed for most elements, but alert and sharing boxes auto-rotate with the device

I'm working with Xcode 7 and Swift 2. I am working on an interface with a camera preview layer and controls that display in a manner similar to the native iOS camera app. The controls all stay in place as you turn the device, but the icons "pivot" in place to orient properly for the device orientation. (I hope I explained that in a way that makes sense. If not, open the native camera app on your iPhone and turn the device around a few times to see what I'm talking about.)
I have the basic interface working already by fixing the overall interface orientation using:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.LandscapeRight
}
Then I use transform to rotate each button for the device orientation.
The problem is: I need to be able to present alert messages (UIAlertController) and a sharing interface (UIActivityViewController) in this same interface. How do I get those items to rotate to the correct orientation while still keeping the rest of the interface static?
As I see it, there are two possible approaches here -- I just don't know how to make either one work:
Set the interface to auto rotate and support all orientations, but disable auto-rotation for the views that I need to keep locked in place.
Set the interface to only allow .landscapeLeft (which is currently how it's set up) and find a way to rotate the alert messages and sharing dialog box.
Got it working. I needed to access presentedViewController.view to rotate the alert and share views.
//used to periodically trigger a check of orientation
var updateTimer: NSTimer?
//Checks if the device has rotated and, if so, rotates the controls. Also prompts the user that portrait orientation is bad.
func checkOrientation(timer: NSTimer) {
//Array of the views that need to be rotated as the device rotates
var viewsToRotate = [oneView, anotherView]
//This adds the alert or sharing view to the list, if there is one
if let presentedVC = presentedViewController?.view {
viewsToRotate.append(presentedVC)
}
//Rotate all of the views identified above
for viewToRotate in viewsToRotate {
switch UIDevice.currentDevice().orientation {
case UIDeviceOrientation.Portrait:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_2))
case UIDeviceOrientation.PortraitUpsideDown:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
case UIDeviceOrientation.LandscapeRight:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(2 * M_PI_2))
default:
viewToRotate.transform = CGAffineTransformMakeRotation(CGFloat(0))
}
}
}

Detecting When App Enters Full Screen Mode (Swift/Mac)

I'm hoping this is a simple question, but I am trying to discern a way to figure out when a user has selected to enter Full Screen mode in an app. Effectively, I have a table in a Cocoa app that looks rather silly when the app enters full-screen mode. I would like to, programmatically, adjust the height of my table rows once the app enters full screen mode, but I cannot seem to figure out how to do so.
I recognize the need to use windowWillEnterFullScreen: and windowDidEnterFullScreen:, or find a way for my Window to conform to my App Delegate file, though I'm struggling to figure this out. Are there any resources that could be provided that may be able to point in the right direction?
Thank you!
Edit: Here's what I've tried to do;
AppDelegate.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
var window: NSWindow!
func windowDidResize (notification: NSNotification) {
window.delegate = self
print("resized")
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
windowWillEnterFullScreen: and windowDidEnterFullScreen: are NSWindowDelegate methods — to be able to use them, you just need to be the NSWindow's delegate. Your app delegate object or any other object could serve this purpose.
If you want to use custom animations during the transition, there are some other delegate methods such as window:startCustomAnimationToEnterFullScreenOnScreen:withDuration: that you could use.
You can also check window.styleMask & NSFullScreenWindowMask != 0 to check whether the window is currently fullscreen.

Reset users default app brightness in applicationDidEnterBackground with swift

I've been trying to reset the user's default device brightness in the app delegate method: applicationDidEnterBackground by using this code:
UIScreen.mainScreen().brightness = screenBrightness!
The code gets called but the brightness is not reset. Anyone know how to get this working using Swift (not obj-c)
This code looks correct, but note that it will not work in the simulator, it will only take effect on a physical device.
Also, ensure that the value of screenBrightness is between 0 and 1.
You will likely not be able to change the screen brightness while in the background. From Apple's documentation:
Brightness changes made by an app remain in effect only while the app
is active. The system restores the user-supplied brightness setting at
appropriate times when your app is not in the foreground.
You need to change the brightness in the AppDelegate. For some reason it doesn't work properly when triggered in a view controller from a notification (willResignActiveNotification, didEnterBackgroundNotification, willTerminateNotification). Although, you can use AppDelegate methods for that:
func applicationWillResignActive(_ application: UIApplication) {
UIScreen.main.brightness = 0.5
}

Resources