使用AVAudioPlayer检测iPhone的响铃/静音/静音开关不起作用?

tab*_*ber 31 iphone avaudioplayer iphone-sdk-3.0 ios4 avaudiosession

我尝试使用这些方法试图检测Ring/Silent开关是否处于活动状态:

如何以编程方式感知iPhone静音开关?

AVAudioSession类别不能用作文档规定

但是在我的iPhone 4上,"状态"值始终是"扬声器"(并且CFStringGetLength(状态)返回的长度值始终为7).有没有人成功使用过这种方法?如果是这样,关于什么样的设备和SDK版本?

我这样称呼它:


- (BOOL)deviceIsSilenced {
    CFStringRef state;
    UInt32 propertySize = sizeof(CFStringRef);
    OSStatus audioStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
    if (audioStatus == kAudioSessionNoError) {
        NSLog(@"audio route: %@", state) // "Speaker" regardless of silent switch setting, but "Headphone" when my headphones are plugged in
        return (CFStringGetLength(state) <= 0);
    }
    return NO;
}

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    audioSession.delegate = self;
    [audioSession setCategory:AVAudioSessionCategoryAmbient error:nil];
    [audioSession setActive:YES error:nil];
    NSLog(@"muted? %i", [self deviceIsSilenced]);
    ...
}
Run Code Online (Sandbox Code Playgroud)

我想当手机上的物理开关被切换时,可能会触发其他一些(更准确的)kAudioSessionProperty事件.有人有主意吗?

顺便说一句,我正在使用AVAudioSessionCategoryAmbient类别和我的[AVAudioSession sharedInstance].

更新:我还尝试使用不同的音频类别和一些其他音频会话属性,在静音/取消静音开关时似乎都没有.:(

2014年1月1日更新:这是一个黑客位,我遇到了崩溃,而多任务瓦特/它在我的iPhone 5S,但SoundSwitch图书馆在新接受的答案链接是去,如果你要检测的方式静音开关.它甚至适用于iOS 7.

tab*_*ber 29

好吧,我得到了开发者论坛的人的答案,你们不会喜欢它!

我收到了Apple对此的回应.

他们说他们没有,也从未提供过检测硬件静音开关的方法,也不打算这样做.

:(

IMO绝对有价值检测静音开关并通知用户,以防他们忘记了它...我有人抱怨他们没有任何声音和静音开关是原因!那好吧.

PS:如果您希望Apple添加此功能(当然您也可以!),请在http://bugreport.apple.com/上为"iPhone SDK"提交新的"增强"错误报告

更新:虽然仍然没有正式的方法来检查静音开关的状态,但有一个名为"SoundSwitch"的解决方法/库似乎可以解决问题.查看链接的新接受答案.

  • 我同意@taber; Apple 不提供访问权限,这是一种耻辱。当然,该属性不应该是可变的,只能用于检查状态并在适当的时候让用户知道。我认为 Apple 处理音量的方式总体上非常糟糕。我还是不明白按音量减键什么时候会修改哪个频道。我相信大多数用户甚至都不知道 Apple 制造了一个目的地。 (2认同)

Ale*_*ylo 11

"但是,如果有人能告诉我们如何使用这个AudioSessionProperty_AudioRouteDescription,那么赏金就是他的理所当然."

好吧,只有NSLog()结果,你得到

routes: {
    "RouteDetailedDescription_Inputs" =     (
    );
    "RouteDetailedDescription_Outputs" =     (
                {
            "RouteDetailedDescription_PortType" = Speaker;
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我在iPad2/OS 5.0上获得了相同的结果,无论是静音还是非静音.因此它看起来在功能上等同于kAudioSessionProperty_AudioRoute,没有任何乐趣.

在开发板上看,发现这是一个经常遇到的问题,总结得最好

"我在7月份用rdar:// 9781189报道了这个问题,这个问题仍然存在于通用汽车中."

所以是的...确定在5.0中看起来你是SOL的.

附录:

"但是你正在记录的CFDictionary怎么样.我如何访问"RouteDetailedDescription_PortType"键?"

免费桥接是你的朋友.

  CFDictionaryRef asCFType = nil;
  UInt32 dataSize = sizeof(asCFType);
  AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, &asCFType);
  NSDictionary *easyPeasy = (NSDictionary *)asCFType;
  NSDictionary *firstOutput = (NSDictionary *)[[easyPeasy valueForKey:@"RouteDetailedDescription_Outputs"] objectAtIndex:0];
  NSString *portType = (NSString *)[firstOutput valueForKey:@"RouteDetailedDescription_PortType"];
  NSLog(@"first output port type is: %@!", portType);
Run Code Online (Sandbox Code Playgroud)

产生

第一个输出端口类型是:扬声器!

许多常见的CFType被桥接到更方便的类型.

http://developer.apple.com/library/ios/#documentation/CoreFoundation/Conceptual/CFDesignConcepts/Articles/tollFreeBridgedTypes.html

现在,需要一些练习才能正确猜出魔法咒语如何从字典中获得有用的东西.沿着这些行的类转储助手将帮助您快速掌握:

  - (void)whatsInThis:(CFDictionaryRef)thingy
  {
     NSDictionary *dict = (NSDictionary *)thingy;
     for (NSString *key in dict.allKeys)
     {
        id value = [dict valueForKey:key];
        NSLog(@"key: %@ value type %@", key, [value class]);
        if ([value isKindOfClass:[NSArray class]])
        {
           NSArray *array = (NSArray *)value;
           for (id item in array)
           {
              NSLog(@" -- object type %@", [item class]);
              if ([item isKindOfClass:[NSDictionary class]])
                 [self whatsInThis:item];
           }
        }
     }
  }
Run Code Online (Sandbox Code Playgroud)

对于我们手边的字典产生(为了清晰起见,添加缩进)

key: RouteDetailedDescription_Inputs value type __NSCFArray
key: RouteDetailedDescription_Outputs value type __NSCFArray
  -- object type __NSCFDictionary
    key: RouteDetailedDescription_PortType value type __NSCFString
Run Code Online (Sandbox Code Playgroud)

这让你知道你可以从原始日志中推断出什么,知道NSLog在{}中显示数组,在{}中显示字典,因此正确的强制转换是非常可猜测的.但是一些CFType结构比这更难解析.

  • 谢谢 - 你有一个工作`(BOOL)deviceIsSilenced`方法,利用这种方法? (4认同)

Mos*_*ieb 4

我浏览了这个 VSSilentSwitch 库。
对我不起作用(当您开始实际使用音频时不起作用)。
我正在思考他是如何做到的,然后意识到当我们保持沉默时,几乎在声音开始播放时就调用了音频完成调用。
更具体地说:
正在播放的系统声音AudioServicesPlaySystemSound将在开始后立即完成播放。
当然,这仅适用于尊重静音开关的音频类别(默认AVAudioSessionCategoryAmbient尊重它)。
因此,诀窍是创建一个系统声音,最好是无声的声音,然后一遍又一遍地播放它,同时检查从播放到完成所需的时间(使用安装完成程序AudioServicesAddSystemSoundCompletion)。
如果很快就调用完成过程(允许一定的阈值) - 这意味着静默开关已打开。
这个技巧有很多注意事项,其中最大的一个是它不适用于所有音频类别。
如果您的应用程序在后台播放音频 - 请确保在后台停止此测试,否则您的应用程序将永远在后台运行(并且也会被苹果拒绝)。

  • 人们在问这个问题,所以这里是 - 我在 github 上设置了一个示例项目:https://github.com/moshegottlieb/SoundSwitch 而不是死链接。 (3认同)