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

时间:2011-08-01 16:18:19

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

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

How to programmatically sense the iPhone mute switch?

AVAudioSession category not working as documentation dictates

但在我的iPhone 4上,“state”值始终为“Speaker”(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]。

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

一月1,2014更新:这是一个黑客攻击,我在iPhone 5S上遇到了多任务处理时的崩溃问题,但在新接受的答案中链接的SoundSwitch库是要走的路如果你想检测静音开关。它甚至适用于iOS 7。

7 个答案:

答案 0 :(得分:29)

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

  

我收到了Apple对此的回应。

     

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

:(

IMO在检测静音开关和通知用户以防止它们忘记它的情况下绝对有价值...我曾经有人抱怨他们没有任何声音而且静音开关是原因!哦,好吧。

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

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

答案 1 :(得分:11)

“但是,如果有人可以告诉我们如何使用这个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结构比那更难解析。

答案 2 :(得分:3)

我浏览了这个VSSilentSwitch库 没有为我工作(当你开始实际使用音频时不起作用) 我正在思考他是如何做到的,然后意识到当我们沉默时声音开始播放时,音频完成呼叫几乎被调用。
更具体一点:
使用AudioServicesPlaySystemSound播放的系统声音将在播放后立即完成播放 当然,这只适用于尊重静音开关的音频类别(默认AVAudioSessionCategoryAmbient尊重它) 因此,诀窍是创建一个系统声音,最好是静音,然后一遍又一遍地播放,同时检查从播放到完成所花费的时间(使用AudioServicesAddSystemSoundCompletion安装完成程序)。 /> 如果很快调用完成过程(允许某些阈值) - 则表示静音开关已打开。
这个技巧有许多警告,最大的一个原因是它不适用于所有音频类别 如果您的应用在后台播放音频 - 请确保您在后台停止此测试,否则您的应用将在后台永久运行(并且苹果也会拒绝)。

答案 3 :(得分:0)

尝试将此行插入到deviceIsSilenced中对AudioSessionGetProperty的调用之上

AudioSessionInitialize(NULL,NULL,NULL,NULL);

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

FWIW我不相信公共API中有任何内容会在实际切换时触发。

答案 4 :(得分:0)

好的,在使用CMD +点击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上的静音/静音开关。

答案 5 :(得分:0)

我认为你有错误的印象。一条路线就在哪里。您想知道音量级别。使用kAudioSessionProperty_CurrentHardwareOutputVolume

答案 6 :(得分:0)

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

Apple会允许那些东西吗?这是一个500Kb的图书馆,在音频和音频方面做了一些黑魔法。手机设置