【问题标题】:Detecting the iPhone's Ring / Silent / Mute switch using AVAudioPlayer not working?使用 AVAudioPlayer 检测 iPhone 的响铃/静音/静音开关不起作用?
【发布时间】:2011-10-17 14:22:39
【问题描述】:

我尝试使用这些方法来检测响铃/静音开关是否处于活动状态:

How to programmatically sense the iPhone mute switch?

AVAudioSession category not working as documentation dictates

但在我的 iPhone 4 上,“状态”值始终为“扬声器”(CFStringGetLength(state) 返回的长度值始终为 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]);
    ...
}

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

顺便说一句,我将 AVAudioSessionCategoryAmbient 类别与我的 [AVAudioSession sharedInstance] 一起使用。

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

一月。 2014 年 1 月 1 日更新: 这有点小题大做,我在 iPhone 5S 上使用它进行多任务处理时遇到了崩溃,但是如果您在新接受的答案中链接了 SoundSwitch 库,那么您可以这样做想检测静音开关。它甚至适用于 iOS 7。

【问题讨论】:

  • [self deviceIsSilenced] 中有什么?
  • 我已经用deviceIsSilenced 更新了帖子,谢谢你的提问,简! :)
  • FWIW,它也不适合我......
  • 我正要发布一个完全相同的副本(iPhone 4 .. 等)
  • 请注意:我使用了stackoverflow.com/questions/287543/… 的环境开关,没用...

标签: iphone ios4 iphone-sdk-3.0 avaudioplayer avaudiosession


【解决方案1】:

感谢开发者论坛的某个人,我找到了答案,你们不会喜欢的!

我收到了 Apple 的回复。

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

:(

IMO 检测静音开关并通知用户以防万一他们忘记它已打开,这绝对是有价值的......我曾有人抱怨他们没有任何声音,而静音开关是原因!哦,好吧。

PS:如果您希望 Apple 添加此功能(当然您会这样做!),请在 http://bugreport.apple.com/ 提交新的“iPhone SDK”“增强”错误报告

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

【讨论】:

  • 这样的行为似乎是合理的,但并不总是很方便——这似乎与 Apple 意识形态有关,而不仅仅是为 API 提供小功能。 “。我曾经有人抱怨他们没有任何声音,而静音开关就是原因!” - 当人们忘记关闭声音并且有人在不可接受时打电话时,我经常遇到;)如果Apple以编程方式提供开关访问权限,我们将收到有关特定应用程序的抱怨,因为有人错误地处理了应用程序中的静音开关状态。
  • 我同意@taber;可惜苹果不提供访问权限。当然,该属性不应该是可变的,只能用于检查状态并让用户知道适当的地方。我认为苹果处理音量的方式总体上很差。我仍然不明白当我按下音量降低按钮时会修改什么频道。我相信大多数用户甚至都不知道 Apple 是一个目的地。
【解决方案2】:

“但是,如果有人可以向我们展示如何使用这个 AudioSessionProperty_AudioRouteDescription,那么赏金就是他的。”

好吧,只需 NSLog() 得到结果即可

routes: {
    "RouteDetailedDescription_Inputs" =     (
    );
    "RouteDetailedDescription_Outputs" =     (
                {
            "RouteDetailedDescription_PortType" = Speaker;
        }
    );
}

不幸的是,我在 iPad2/OS 5.0 上得到了相同的结果,无论是静音还是非静音。所以它似乎在功能上等同于 kAudioSessionProperty_AudioRoute,没有乐趣。

看开发板发现这是一个经常遇到的问题,总结起来最好用

“我在 7 月份通过 rdar://9781189 报告了这个问题,但这个问题仍然存在于 GM 中。”

所以是的......在 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);

生产

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

许多常见的 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];
           }
        }
     }
  }

我们手头的字典产生的(为了清楚起见添加缩进)

key: RouteDetailedDescription_Inputs value type __NSCFArray
key: RouteDetailedDescription_Outputs value type __NSCFArray
  -- object type __NSCFDictionary
    key: RouteDetailedDescription_PortType value type __NSCFString

这让您确定可以从原始日志中推断出什么,知道 NSLog 在 ( ) 中显示数组,在 { } 中显示字典,因此正确的转换非常容易猜到。但是有些 CFType 结构比这更难解析。

【讨论】:

  • 太棒了!你又解决了这个问题的一步。使用 AudioRoute 返回一个 CFString,这很容易处理。但是您正在记录的那个 CFDictionary 怎么样。如何访问“RouteDetailedDescription_PortType”键?
  • IE应该有类似的东西: CFString s = ExtractObjectWithKey(theCFDictionary, @"RouteDetailedDescription_PortType"); ...明白我的意思吗?
  • hmmm ...无法在评论中粘贴代码?好的,我会添加另一个答案。
  • 大声笑,你太棒了:D。谢谢!
  • 谢谢 - 你有使用这种方法的 (BOOL) deviceIsSilenced 方法吗?
【解决方案3】:

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

【讨论】:

  • 链接现在失效了,答案说明了如何使用api实现这个AudioServicesAddSystemSoundCompletion,AudioServicesPlaySystemSound。
  • 人们在问这个问题,所以这里是 - 我在 github 上设置了一个示例项目:github.com/moshegottlieb/SoundSwitch 而不是死链接。
  • @Pang VSSilentSwitch 的链接是由编辑我的答案的人添加的,而不是由我添加的。这是一个编辑错误,我纠正了它。该库在此问题的另一个答案中提到(以“找到此库”开头)
【解决方案4】:

尝试将此行插入到 deviceIsSilenced 内对 AudioSessionGetProperty 的调用上方

AudioSessionInitialize(NULL, NULL, NULL, NULL);

然后应该在开关关闭时开始返回空字符串(尽管如果连接了 BT 耳机或配件会显示 Headphone 和其他一些状态)。

FWIW 我不相信公共 API 中有任何东西会在实际开关被移动时触发。

【讨论】:

  • 谢谢,我只是试了一下,但不幸的是没有运气。也许是与 AVAudioPlayer 结合使用,嗯。
  • 我将它与 AVAudioPlayer 结合使用,它对我有用。实际上,我不检查 kAudioSessionNoError - 你有没有检查过你没有得到一个?
  • @taber 你有没有打开(或)关闭静音开关的答案?
【解决方案5】:

我想你有错误的印象。路线是它要去的地方。您想知道音量。使用kAudioSessionProperty_CurrentHardwareOutputVolume

【讨论】:

  • 抱歉,这完全无关紧要。我不是想找到音量级别,而是想知道静音开关是否打开/关闭。问题中发布的代码适用于 iOS 4.0。在 iOS 5 中,它在我发布时已被弃用。
  • @Mazyod 你找到静音开关按钮开(或)关了吗?。
  • @user1586650 检查 alexcurylo 的答案。我还没有实现它,tbh。
  • @user1586650 我说,tbh,我还没有实现它。
【解决方案6】:

好的,在使用 CMD + click 关注kAudioSessionProperty_AudioRoute 之后,我发现了这个:(

/*!
 @enum           AudioSession audio categories states
 @abstract       Deprecated AudioSession properties
 @constant       kAudioSessionProperty_AudioRoute 
 Deprecated in iOS 5.0; Use kAudioSessionProperty_AudioRouteDescription 
 */
enum {
    kAudioSessionProperty_AudioRoute                            = 'rout',   // CFStringRef      (get only)        
};

原来我们必须使用kAudioSessionProperty_AudioRouteDescription,但是这家伙返回了CFDictionaryRef 什么的,我完全不知道如何处理它......

如果没有人向我们展示如何使用kAudioSessionProperty_AudioRouteDescription,我将其作为答案,我将尝试接受我的答案...

但是,如果有人可以向我们展示如何使用这个kAudioSessionProperty_AudioRouteDescription,那么赏金就是他的。

编辑:

显然,这是 iOS 5 的问题。我之前没有说明这一点,因为它看起来太明显了,但后来我认为这对搜索引擎来说可能不那么明显......如果你明白我的意思的话。

因此,由于引用的已弃用值,iOS 5 无法使用 iPhone 上的静音/静音开关。

【讨论】:

  • 您可能无法获得答案,因为 AFAIK iOS5 SDK 仍处于 NDA 之下。实际上,您发布的答案在这方面是不确定的。我的建议是查找您所指的常量的标题文档(右键单击并跳转到定​​义)。你会在那里找到答案。
  • 但答案可能是“否定”
  • 好吧,我只是想知道如何在这种情况下使用 CFDictionary .. CFDictionary 专家会很容易地回答这个问题.. 我很遗憾没有发布宝贵的赏金 :(
  • 顺便说一句,iOS 5 SDK 已在几周前向公众发布。它不再属于 NDA :)
  • 就像我说的,在标题中他们解释了结构的布局。这非常神秘,在这种情况下,您得到的答案与您从已弃用的 API 中得到的答案没有任何不同。叹息。
【解决方案7】:

找到这个库 http://www.verietassoftware.com/index.php?option=com_content&view=article&id=27&Itemid=115

Apple 会允许这些东西吗?这是一个 500Kb 的库,在音频和电话设置方面做了一些黑魔法

【讨论】:

  • 在下面查看我的答案,与开源格式的 VSSilentSwitch 功能相同
猜你喜欢
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-09
  • 2010-10-16
  • 1970-01-01
相关资源
最近更新 更多