Обнаружение переключателя iPhone Ring/Silent/Mute с использованием AVAudioPlayer не работает?

Я попытался использовать эти методы в попытке обнаружить, что переключатель Ring/Silent активен или нет:

Как программно определить переключатель отключения звука iPhone?

Категория AVAudioSession не работает в соответствии с документацией

Но на моем iPhone 4 значение "state" всегда "Speaker" (и значение длины, возвращаемое 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]);
    ...
}

Я думал, может быть, какое-то другое (более точное) событие kAudioSessionProperty запускается при переключении физического переключателя на телефоне. У кого-нибудь есть идеи?

Кстати, я использую категорию AVAudioSessionCategoryAmbient с моим [AVAudioSession sharedInstance].

Обновление: Я также пытался использовать разные категории аудио и несколько других свойств сеанса аудио, ни один из них не срабатывает при отключении/отключении коммутатора.: (

Январь 1, 2014 Обновление: Это немного взломало, и я столкнулся с сбоем, когда многозадачность была на моем iPhone 5S, но SoundSwitch библиотека, связанная в новом принятом ответе, - это путь, если вы хотите обнаружить тихий переключатель. Он работает даже в iOS 7.

Ответ 1

Я прошел через эту библиотеку VSSilentSwitch.
Не работал у меня (не работает, когда вы начинаете использовать аудио).
Я думал о том, как он это сделал, а затем понял, что вызов завершения звука называется почти сразу после начала звучания звука, когда мы молчим.
Чтобы быть более конкретным:
Звуки системы, воспроизводимые с использованием AudioServicesPlaySystemSound, завершат воспроизведение сразу же после его запуска.
Конечно, это будет работать только с аудио категориями, которые относятся к тихим переключателям (по умолчанию это соответствует AVAudioSessionCategoryAmbient).
Итак, фокус в том, чтобы создать системный звук, желательно тихий звук, и продолжать воспроизводить его снова и снова, проверяя время, которое требуется от воспроизведения до завершения (установите процедуру завершения с помощью AudioServicesAddSystemSoundCompletion).
Если завершение proc вызывается очень скоро (допустим некоторый порог) - это означает, что включен тихий переключатель.
Этот трюк имеет много предостережений, самый большой из которых заключается в том, что он не будет работать во всех категориях аудио.
Если ваше приложение воспроизводит аудио в фоновом режиме - убедитесь, что вы остановили этот тест в фоновом режиме, или ваше приложение будет работать навсегда в фоновом режиме (и также будет отклонено яблоком).

Ответ 2

Ну, я нашел ответ благодаря кому-то из форумов разработчиков, и вам, ребята, это не понравится!

У меня был ответ от Apple.

Они сказали, что они этого не делают и никогда не предоставляли метод обнаружения аппаратного отключения звука и не намеревались это делать.

: (

IMO определенно имеет значение для обнаружения молчащего коммутатора и уведомления пользователя, если они забыли, что он был включен... У меня были люди, жалующиеся на то, что у них нет звука, и причиной молчания стал! О, хорошо.

PS: Если вы хотите, чтобы Apple добавила эту функцию (и, конечно же, вы делаете!), пожалуйста, напишите новый отчет об ошибке "Улучшение" для "iPhone SDK" в http://bugreport.apple.com/

Обновление: Пока еще нет официального способа проверить статус переключателя отключения звука, есть обходной путь/библиотека под названием "SoundSwitch", которая, похоже, делает трюк. Ознакомьтесь с новым принятым ответом на ссылку.

Ответ 3

"Однако, если кто-то может показать нам, как использовать эту AudioSessionProperty_AudioRouteDescription, то щедрость по праву принадлежит ему".

Ну, просто NSLog() результат, и вы получите

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

К сожалению, я получаю этот идентичный результат на iPad2/OS 5.0 как приглушенный, так и без звука. Таким образом, он, по-видимому, функционально эквивалентен kAudioSessionProperty_AudioRoute, там нет радости.

Глядя на платы разработчиков, выясняется, что это часто встречающаяся проблема, которая лучше всего подытоживает

"Я сообщил об этой проблеме с rdar://9781189 еще в июле, и проблема все еще присутствует в GM".

Итак, да... конечно, похоже, что вы SOL с этим в 5.0.

ДОПОЛНЕНИЕ:

"Но как насчет того 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);

производит

Первый тип выходного порта: Speaker!

Многие распространенные типы CFTypes соединяются с более удобными типами.

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 довольно сложны для анализа.

Ответ 4

Попробуйте вставить эту строку над вашим вызовом в AudioSessionGetProperty внутри устройства. IsSilenced

AudioSessionInitialize (NULL, NULL, NULL, NULL);

Затем следует начать возвращать пустую строку, когда переключатель не работает (хотя будет отображаться Headphone и некоторые другие состояния, если BT-гарнитура или аксессуар подключены, например).

FWIW Я не верю, что в публичном API будет что-то, что будет срабатывать при перемещении фактического переключателя.

Ответ 5

Хорошо, после выполнения kAudioSessionProperty_AudioRoute с помощью CMD + click я нашел следующее: (

/*!
 @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 не работает с переключателем silent/mute на iPhone из-за указанного устаревшего значения.

Ответ 6

Я думаю, что вы ошибались. Маршрут - это путь. Вы хотите знать уровень громкости. Используйте kAudioSessionProperty_CurrentHardwareOutputVolume