Change volume and turn on/off silent mode - ios

This is for a jailbreak tweak, so it doesn't matter that I need to use private frameworks.
How can you change the volume of the device and how can you turn off silent mode?
If there is an easier way to play a sound at a specific volume and will always play regardless of silent mode is on or off, this will actually be better.

You can change the volume using the VolumeControl class:
static void setVolume(float volume) {
VolumeControl *volumeControl = [VolumeControl sharedVolumeControl];
[volumeControl setMediaVolume:volume];
}
I don't know how to toggle the silent switch yet.

I haven't tried this out, so no guarantees regarding it functioning properly ...
but just by looking at the dumped header, I would try this for turning silent mode on or off:
VolumeControl *volumeControl = [VolumeControl sharedVolumeControl];
[volumeControl toggleMute];
let me know if it works for you ...

Related

Does iOS Reduce Speaker Volume for Apps Using a Microphone?

I am developing an Xcode/Swift/SwiftUI app for real-time music visualization. I allow the user to push a button to toggle between microphone-input and file-play input (but never both at the same time). My app runs fine on my Mac and on my iPad, but on my iPhone, the speaker audio is only at half-volume (and appears to be only coming from the back speakers) - even when I am in file-play mode. I have traced the problem to one offending line in my code - namely the declaration
let mic = engine.inputNode // where engine = AVAudioEngine()
When I comment-out this line, the iPhone speaker level (for file-play mode) is fine. But when I un-comment it, the iPhone speaker level is barely audible. Even when I wrap this line inside a conditional if(micEnabled){} construct, the sound level is fine at first; but as soon as I select the microphone and then toggle back to file-play, the volume again decreases.
I suspect that iOS detects when a microphone is declared and automatically reduces the speaker volume to avoid audio feedback. This would make sense because nobody wants music playing when they are speaking on a telephone call. But it would also make sense to provide developers a way to override this feature if they want to handle it themselves. In my case, for the microphone-input case, I purposely assign the audio stream a zero-volume after it is tapped and before going to the speaker.
My source code is available here. All of the audio code is inside the MuVis / Shared / AudioManager.swift class.
Can anyone help me to get the file-play mode to work with full volume on my iPhone - while also allowing the user the option to select microphone-input mode?
Many thanks to Rob Napier for pointing me in the right direction for solving my problem.
As a macOS-only developer, I had ignored AVAudioSession (since it caused compiler errors on macOS). When I converted my MuVis app from macOS-only to multiplatform, I simply started a new Xcode project with the appropriate multiplatform settings, and then pasted my existing code into the shared folder. After cleaning up a few errors (mostly calls to NSObject), it magically worked on all Apple platforms - except for the iPhone audio problem described in my question. After a little research and a lot of trial-and-error, I found that my audio-volume problem is solved by inserting the following code into my setupAudio() function:
#if os(iOS)
// For iOS devices, set the audioSession category, mode, and options:
let session = AVAudioSession.sharedInstance() // Get the singleton instance of an AVAudioSession.
do {
if(filePlayEnabled) {
// This is required by iOS to prevent output audio from going only to the iPhone's rear speaker.
try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.default, options: [.defaultToSpeaker])
}
else {
try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.default, options: [])
}
} catch { print("Failed to set audioSession category.") }
#endif
Again, thank you Rob.

Objective C - How can I detect that the volume is 0? (both the mute button and just by lowering the volume)

I would like to present an alert if the sound is 0.
I found this library https://github.com/moshegottlieb/SoundSwitch, but it doesn't seem to work. At least not on a simulator
Have you seen this question? They give various answers:
float vol = [[AVAudioSession sharedInstance] outputVolume];
NSLog(#"output volume: %1.2f dB", 20.f*log10f(vol+FLT_MIN));
Nonetheless it doesn't seems to work using the simulator (I'm trying and it always return the same value). This lead me to think maybe it's not something we can check from the simulator. Can you try on a real device? Let me know if it works.
EDIT: Ok so reading about it it seems there's no API avaiable to check silent mode. Anyway what people have found a workaround: Playing a short audio with no volume. If the time when it finishes (minus time when it started) is lower than the actual length of the audio is on mute mode (being in the silent mode the audio will last 0 seconds).
So, here somebody posted a class that do that for you. Let me know if it works

iOS: How to set ringer and alert volume within my App

For my APP, one of the important function is to mute the iPhone, but I can't find any available iOS API that I can use to mute the phone(or change the ringer volume level to minimum). Is their a specific API for developer to mute (or change the ringer volume of) the phone, if their is not, is there a indirect way to do this?
I believe you can only mute other application sounds. You need to configure the AVAudioSession category :
AVAudioSession Class Reference : http://goo.gl/rh7CX7 .
Look for which fit the most for your application. You only need to set it once in your code (make sure it's called).
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient, error: nil) // AVAudioSessionCategorySoloAmbient is default AVAudioSession.sharedInstance().setActive(true, error: nil)
No.
Applications developed using the official SDK cannot change (and in most cases cannot even access) system-wide settings.
It is possible, but only using private API's. I only went as far as muting the ringer, but you should be able to control the master level as well.
See How to disable iOS System Sounds

How know if iOS device is sleeping in a background process

I have a application running in background and I need to know if device is sleeping in order to start a sincronisation process, but I didn't find information about this.
Does anyone know if it is posible and how do it?
Thanks.
You cannot know if the device is asleep because you have no control over the OS.
You can, otherwise, use the App Delegate method:
- (void)applicationWillResignActive:(UIApplication *)application
{
//your code goes here
}
if you want to wait till your app goes to background
I believe you can't do this using public API. The only thing which you can check whether your application is active or in background (using AppDelegate callbacks). And as Luke pointed out in comments, checking whether device "falls asleep" isn't iOS best design practice.
There are some private API's to do what you want, you can look at following questions:
Is there a way to check if the iOS device is locked/unlocked?
Detect screen on/off from iOS service
However, you should be aware that your app won't be accepted in AppStore in such case.

Volume Control in a mostly Silent iOS app

I've asked this question before but I feel I should start a new thread since my other thread is dated and probably poorly worded. I'm wondering what the best approach would be for adding volume control to an iOS app the is mostly silent. A good example would be a navigation app that only plays audio when you approach or miss a turn. In such an app, hearing a turn prompt which is not loud enough, the user would want the volume for the prompts to be audible and would naturally used the side volume controls to adjust prompts to their liking.
There are several problems here. One is that audio is not currently playing so the user has no reference as to how much it has been increased. This is more or less expected however there are technical issues that I am more interested in. To link the side volume control to your app you have to start and manage an audio session. I have not found an authoritative reference for such a situation as most documentation assumes you are currently playing or in the process of starting audio. Managing an audio session for a mostly silent app seems to be an edge case, though I find it rather common in that two of the major apps I've worked on require such functionality.
Of the various problems associated with audio session management, you have to address killing and restoring the audio session as you move in and out of the background. You have to consider other apps playing audio as you begin and stop the session. Depending on your type of app, you may have other more advanced needs such as custom override routing to the speakers, custom mute controls, etc. If you have any experience with such an app could you elaborate on how you addressed such challenges and expound on other issues?
One very common merhod is to set the audio session category appropriate for the type of app at launch, no matter whether sound is immanent or won't be played till tomorrow (as long as the purpose and settings of the app is to play such).
Added:
One way to allow to user to adjust the volume when the app is silent is to provide some means for the user to have your app to immediately start (and/or maybe stop) playing some sound with an amplitude typical for your app: some calibration tone/talk, your copyright notice, trademark jingle, or a safety message, for instance.
The main issue I see when developing apps that are mostly silent regard moving in/out of the foreground and playing nicely with other audio. To give a better idea of what I usually do I'll give some snippets from a recent project. (These are intentionally incomplete and only meant to illustrate a point.) For the sake of argument let's assume we have an AudioManager class that is responsible for maintaining the audio sessions. This class is what we use to instantiate our custom audio player. In such a class we put:
#interface MyAudioManager ()
#property (nonatomic, retain) BOOL alwaysMaintainAudioSession;
#property (nonatomic, retain) MyCustomAudioPlayer *player;
#end
#implementation MyAudioManager
#synthesize alwaysMaintainAudioSession;
#synthesize player;
-(void) applicationWillEnterForeground
{
isInBackground = NO;
if (NO==[self anyAudioIsPlaying] && self.alwaysMaintainAudioSession) {
[self activateAudioSession];
}
}
-(void) activateAudioSession
{
AudioSessionSetActive(TRUE);
AudioSessionAddPropertyListener ( kAudioSessionProperty_AudioRouteChange, AudioPropertyListener, self);
}
-(BOOL) anyAudioIsPlaying
{
return [self otherAudioIsPlaying] || [player isPlaying];
}
-(BOOL) otherAudioIsPlaying
{
UInt32 yesNo;
UInt32 propertySize = sizeof(yesNo);
OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &yesNo);
if (kAudioSessionUnsupportedPropertyError == status) {
return MPMusicPlaybackStatePlaying == [theiPodMusicPlayer playbackState];
} else {
return MPMusicPlaybackStatePlaying == [theiPodMusicPlayer playbackState] || yesNo;
}
}
The manager allows you to set a property that always keeps the volume control linked to the app sounds which means we always make sure either a session is active or some other app is playing audio. In any other case the volume control reverts to controlling the ringer. So when entering the foreground we have to check for any other audio playing and conditionally activate the audio session. We also need to close the session when moving to the background to restore the ringer volume control.
-(void) applicationDidEnterBackground
{
if (NO==[self anyAudioIsPlaying]) {
AudioSessionSetActive(NO);
}
}
In my solution I include a bunch of other code to handle things like responding intelligently when bluetooth audio devices are connected, factory methods for creating the custom player, custom audio compression and more. The main idea, however, is handling other apps playing audio while attempting to keep the volume control linked to app volume while in the foreground.

Resources