如何以编程方式检测iPhone的静音开关?

55

我似乎在SDK中找不到如何编程检测iPhone上的静音按钮/开关。当我的应用程序播放背景音乐时,它会适当地响应音量按钮,而我没有任何代码来遵循,但是当我使用静音开关时,它仍然继续播放。

我该如何测试静音的位置?

(注意:我的程序有自己的静音开关,但我希望物理开关覆盖它。)

8个回答

30

感谢您,JPM。事实上,您提供的链接最终引导我们找到了正确的答案(虽然有些困难 ;))。为了完整起见(因为S.O.应该是快速回答的来源!)...

// "Ambient" makes it respect the mute switch
// Must call this once to init session
if (!gAudioSessionInited)
{
    AudioSessionInterruptionListener    inInterruptionListener = NULL;
    OSStatus    error;
    if ((error = AudioSessionInitialize (NULL, NULL, inInterruptionListener, NULL)))
    {
        NSLog(@"*** Error *** error in AudioSessionInitialize: %d.", error);
    }
    else
    {
        gAudioSessionInited = YES;
    }
}

SInt32  ambient = kAudioSessionCategory_AmbientSound;
if (AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (ambient), &ambient))
{
    NSLog(@"*** Error *** could not set Session property to ambient.");
}

如果我之后记录环境值,无论我是否静音,我都会得到返回的1634558569。有什么想法吗? - Finn Gaida
不工作怎么了?你做了什么?你期望发生什么?相反会发生什么?如果你提供更多信息,我会尽力更新我的回答。谢谢! - Olie
你能帮我吗:https://dev59.com/Ao3da4cB1Zd3GeqPylvY - Ganee....

11

我在这里回答了一个类似的问题(链接)。相关代码:

 -(BOOL)silenced {
     #if TARGET_IPHONE_SIMULATOR
         // return NO in simulator. Code causes crashes for some reason.
         return NO;
     #endif

    CFStringRef state;
    UInt32 propertySize = sizeof(CFStringRef);
    AudioSessionInitialize(NULL, NULL, NULL, NULL);
    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
    if(CFStringGetLength(state) > 0)
            return NO;
    else
            return YES;

    }

1
当耳机插入时,这个不起作用。AudioSessionGetProperty用于音频路由的返回值始终为“Headphone”,无论静音开关如何。 - yood
但是,当耳机插入时,静音开关是否打开并不重要吗?声音仍然从耳机中播放,对吧?在我看来,静音开关的作用是让手机对其他人保持安静,而不是你自己。在佩戴耳机时,遵守它似乎并不重要(依我之见)。这似乎是苹果采取的立场,因为他们返回了“耳机”。 - Chris Ladd
7
无法在iOS 5中使用。 https://dev59.com/sGw05IYBdhLWcg3w_WxN - morgancodes
糟糕!在iOS5中不再工作的东西远不止这个... ;) - Chris Ladd
iPhone在iOS5中的静音开关无法正常工作。这是有什么原因吗? - Yuvaraj.M
显示剩余2条评论

7

其他答案中的某些代码(包括被接受的答案)可能在您不处于环境模式下,即静音开关得到尊重时无法工作。

我编写了以下程序来切换到环境模式,读取开关状态,然后返回到我应用程序所需的设置。

-(BOOL)muteSwitchEnabled {

#if TARGET_IPHONE_SIMULATOR
    // set to NO in simulator. Code causes crashes for some reason.
    return NO;
#endif

// go back to Ambient to detect the switch
AVAudioSession* sharedSession = [AVAudioSession sharedInstance];
[sharedSession setCategory:AVAudioSessionCategoryAmbient error:nil];

CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);

BOOL muteSwitch = (CFStringGetLength(state) <= 0);
NSLog(@"Mute switch: %d",muteSwitch);

// code below here is just restoring my own audio state, YMMV
_hasMicrophone = [sharedSession inputIsAvailable];
NSError* setCategoryError = nil;

if (_hasMicrophone) {

    [sharedSession setCategory: AVAudioSessionCategoryPlayAndRecord error: &setCategoryError];

    // By default PlayAndRecord plays out over the internal speaker.  We want the external speakers, thanks.
    UInt32 ASRoute = kAudioSessionOverrideAudioRoute_Speaker;
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
                             sizeof (ASRoute),
                             &ASRoute
                             );
}
else
    // Devices with no mike don't support PlayAndRecord - we don't get playback, so use just playback as we don't have a microphone anyway
    [sharedSession setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];

if (setCategoryError)
    NSLog(@"Error setting audio category! %@", setCategoryError);

return muteSwitch;
}

5
为了确定静音开关和音量控制的状态,我编写了这两个函数。如果您希望在用户尝试创建音频输出之前警告他们,这些函数是理想的选择。
-(NSString*)audioRoute
{
    CFStringRef state;
    UInt32 propertySize = sizeof(CFStringRef);
    OSStatus n = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
    if( n )
    {
        // TODO: Throw an exception
        NSLog( @"AudioSessionGetProperty: %@", osString( n ) );
    }

    NSString *result = (NSString*)state;
    [result autorelease];
    return result;
}

-(Float32)audioVolume
{
    Float32 state;
    UInt32 propertySize = sizeof(CFStringRef);
    OSStatus n = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputVolume, &propertySize, &state);
    if( n )
    {
        // TODO: Throw an exception
        NSLog( @"AudioSessionGetProperty: %@", osString( n ) );
    }
    return state;
}

5
-(BOOL)isDeviceMuted
{
 CFStringRef state;
 UInt32 propertySize = sizeof(CFStringRef);
 AudioSessionInitialize(NULL, NULL, NULL, NULL);
 AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
 return (CFStringGetLength(state) > 0 ? NO : YES);
}

4
(CFStringGetLength(state) > 0 ? NO : YES)与(CFStringGetLength(state) <= 0)意思相同。 - Daniel
@simpleBob 如何检测 iPhone 静音按钮的值。(例如,如果 iPhone 静音开关处于打开状态(静音),如何检测静音值)。 - Yuvaraj.M
@Yuvaraj.M 这就是这个问题的重点。选择你最喜欢的答案;) 例如,您可以运行上面的方法,如果设备被静音则返回YES。 - Daniel
@simpleBob 感谢回复。非常抱歉打扰您。这对所有的iOS系统都适用吗?因为它在我的iOS5上无法运行。 - Yuvaraj.M

4
我按照通用理论并成功实现了以下操作:http://inforceapps.wordpress.com/2009/07/08/detect-mute-switch-state-on-iphone/。以下是摘要:播放一个短暂的静音声音,计算播放时间,如果静音开关打开,则播放时间比声音本身短得多。我使用500毫秒的声音,如果播放时间少于此时间,则说明静音开关已打开。我使用音频服务播放静音声音(始终遵守静音开关)。这篇文章说可以使用AVAudioPlayer播放这个声音。如果您使用AVAudioPlayer,我认为您需要设置AVAudioSession的类别以遵守静音开关,但我没有尝试过。

4

在相机屏幕上播放视频时,使用环境模式,录制视频时使用播放和录制模式,这样可以解决我们的问题。

应用程序中的代码:didFinishLaunchingWithOptions:

NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&error];
[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeVideoRecording error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];

如果你的应用程序需要使用相机或录制功能,那么在cameraController的viewWillAppear中的代码会涉及到此部分。

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

在摄像头控制器上的viewWillDisappear中的代码

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];

使用这些代码,我们的应用可以录制和播放视频,并且在iOS8和iOS7下静音开关都可以完美工作!


请问能帮我一下吗?我的应用程序中有VoIP通话功能,当用户接到电话时,我需要播放音乐/铃声。我希望即使应用程序处于后台模式,也能播放这个铃声。如果我使用“AVAudioSessionCategoryPlayAndRecord”,它无法与静音开关配合使用;如果我使用“AVAudioSessionCategoryAmbient”,它无法在后台播放。请给我建议,以实现这两种情况。 - Ganee....

3

针对Swift

以下框架在设备上运行完美。

https://github.com/akramhussein/Mute

只需使用pod安装或从Git下载即可。

pod 'Mute'

并使用如下代码

import UIKit
import Mute

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel! {
        didSet {
            self.label.text = ""
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Notify every 2 seconds
        Mute.shared.checkInterval = 2.0

        // Always notify on interval
        Mute.shared.alwaysNotify = true

        // Update label when notification received
        Mute.shared.notify = { m in
            self.label.text = m ? "Muted" : "Not Muted"
        }

        // Stop after 5 seconds
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
            Mute.shared.isPaused = true
        }

        // Re-start after 10 seconds
        DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
            Mute.shared.isPaused = false
        }
    }

}

请问您能否分享Objective-C的代码?我是iOS的新手。 - Kushal Desai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接