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

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

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

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

Но на моем 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 ответов

Решение

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

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

Я получил ответ от Apple на это.

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

:(

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

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

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

"Однако, если кто-то может показать нам, как использовать эту 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);

производит

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

Многие распространенные типы CFT связаны с более удобными типами.

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 труднее разобрать, чем это.

Хорошо, после kAudioSessionProperty_AudioRoute используя CMD + клик, я нашел это:(

/*!
 @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 из-за указанного устаревшего значения.

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

AudioSessionInitialize (NULL, NULL, NULL, NULL);

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

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

Нашел эту библиотеку http://www.verietassoftware.com/index.php?option=com_content&view=article&id=27&Itemid=115

Разрешит ли Apple такое? Это библиотека размером 500 Кбайт, выполняющая черную магию с настройками звука и телефона.

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

Другие вопросы по тегам