Rilevare lo switch Ring / Silent / Mute dell’iPhone utilizzando AVAudioPlayer non funziona?

Ho provato a utilizzare questi metodi nel tentativo di rilevare che lo switch Ring / Silent è attivo o meno:

Come rilevare a livello di codice l’interruttore di distriggerszione dell’iPhone?

La categoria AVAudioSession non funziona come indica la documentazione

Ma sul mio iPhone 4, il valore “stato” è sempre “Altoparlante” (e il valore di lunghezza restituito da CFStringGetLength (stato) è sempre 7). Qualcuno ha usato questo metodo con successo? Se sì, su che tipo di dispositivo e versione dell’SDK?

Lo chiamo così:

- (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]); ... } 

Stavo pensando che forse un altro (più accurato) evento kAudioSessionProperty viene triggersto quando l’interruttore fisico del telefono è … commutato. Qualcuno ha qualche idea?

A proposito, sto usando la categoria AVAudioSessionCategoryAmbient con il mio [AVAudioSession sharedInstance].

Aggiornamento: ho anche provato a utilizzare diverse categorie audio e una manciata di altre proprietà della sessione audio, nessuna sembra triggersrsi quando si triggers / distriggers l’triggerszione dello switch. 🙁

Aggiornamento del 1 ° gennaio 2014: è un po ‘un hack, e ho riscontrato un crash durante il multitasking sul mio iPhone 5S, ma la libreria SoundSwitch collegata nella nuova risposta accettata è la strada da percorrere se si desidera rilevare il interruttore silenzioso. Funziona anche su iOS 7.

Ho passato questa libreria VSSilentSwitch.
Non ha funzionato per me (non funziona quando inizi a utilizzare effettivamente l’audio).
Stavo pensando a come l’ha fatto, e poi mi sono reso conto che la chiamata di completamento audio viene chiamata quasi quando il suono inizia a suonare quando siamo in silenzio.
Per essere un po ‘più specifici:
I suoni di sistema riprodotti utilizzando AudioServicesPlaySystemSound completeranno la riproduzione non appena è stata avviata.
Ovviamente, questo funzionerà solo su categorie audio che rispettano lo switch silenzioso (il valore predefinito di AVAudioSessionCategoryAmbient rispetta).
Quindi il trucco è creare un suono di sistema, preferibilmente di un suono silenzioso, e continuare a suonarlo più e più volte, controllando nel contempo il tempo impiegato dalla riproduzione fino al completamento (installare una procedura di completamento utilizzando AudioServicesAddSystemSoundCompletion ).
Se il processo di completamento viene chiamato molto presto (consentire alcune soglie), significa che l’interruttore silenzioso è attivo.
Questo trucco ha molti avvertimenti, il più importante è il fatto che non funzionerà su tutte le categorie audio.
Se la tua app riproduce l’audio in sottofondo, assicurati di interrompere questo test mentre sei in background o la tua app funzionerà per sempre in background (e verrà respinta anche da Apple).

Bene, ho trovato la risposta grazie a qualcuno dei Forum degli sviluppatori, e voi ragazzi non vi piacerà!

Ho ricevuto una risposta da Apple su questo.

Hanno detto che non hanno e non hanno mai fornito un metodo per rilevare l’interruttore di silenziamento dell’hardware e non hanno intenzione di farlo.

🙁

IMO c’è sicuramente un valore nel rilevare l’interruttore silenzioso e avvisare l’utente nel caso in cui si siano dimenticati che era su … Ho avuto delle persone che si lamentavano del fatto che non avevano alcun suono e l’interruttore silenzioso era la ragione! Oh bene.

PS: Se desideri che Apple aggiunga questa funzione (e ovviamente lo fai!), Invia un nuovo rapporto bug “Miglioramento” per “iPhone SDK” all’indirizzo http://bugreport.apple.com/

Aggiornamento: Mentre non esiste ancora un modo ufficiale per controllare lo stato dell’interruttore muto, c’è una soluzione alternativa / libreria chiamata “SoundSwitch” che sembra fare il trucco. Controlla la nuova risposta accettata per il collegamento.

“Tuttavia, se qualcuno potrebbe mostrarci come usare questo AudioSessionProperty_AudioRouteDescription, la taglia è giustamente sua.”

Bene, solo NSLog () il risultato e ottieni

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

Sfortunatamente, ottengo lo stesso risultato su un iPad2 / OS 5.0 sia distriggersto che ritriggersto. Quindi sembra essere funzionalmente equivalente a kAudioSessionProperty_AudioRoute, nessuna gioia lì.

Guardando le tabs degli sviluppatori si scopre che questo è un problema frequentemente riscontrato, sintetizzato al meglio con

“Ho segnalato questo problema con rdar: // 9781189 a luglio e il problema è ancora presente nel GM.”

Quindi sì … sembra che tu sia SOL con questo in 5.0.

APPENDICE:

“Ma che ne dici di questo CFDictionary che stai registrando? Come posso accedere al tasto” RouteDetailedDescription_PortType “?”

Il collegamento telefonico gratuito è tuo amico.

  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); 

produce

il primo tipo di porta di uscita è: altoparlante!

Molti comuni CFTypes sono collegati a tipi più convenienti.

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

Ora, ci vuole un po ‘di pratica per indovinare correttamente quali magie di incantesimi otterranno qualcosa di utile da un dizionario come sopra. Un aiutante di discarica di class lungo queste linee ti aiuterà ad essere subito aggiornato:

  - (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]; } } } } 

che per il nostro dizionario produce (aggiungendo indentazione per chiarezza)

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

che ti consente di sapere con certezza cosa potresti dedurre dal log originale, sapendo che NSLog visualizza gli array all’interno di () e i dizionari all’interno di {} in modo che i cast corretti fossero eminentemente ipotizzabili. Ma alcune strutture CFType sono piuttosto difficili da analizzare di quella.

Prova a inserire questa linea sopra la chiamata a AudioSessionGetProperty all’interno del dispositivoIsSilenced

AudioSessionInitialize (NULL, NULL, NULL, NULL);

Dovrebbe quindi iniziare a restituire una stringa vuota quando lo switch è inattivo (anche se mostrerà Cuffie e altri stati se l’auricolare BT o l’accessorio sono collegati per esempio).

FWIW Non credo che nell’API pubblica ci sia qualcosa che si triggers quando viene spostato l’interruttore vero e proprio.

Penso che tu abbia avuto l’impressione sbagliata. Un percorso è dove sta andando. Vuoi conoscere il livello del volume. Usa kAudioSessionProperty_CurrentHardwareOutputVolume

Ok, dopo aver seguito kAudioSessionProperty_AudioRoute usando CMD + clic, ho trovato questo 🙁

 /*! @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) }; 

risulta che dobbiamo usare kAudioSessionProperty_AudioRouteDescription , ma questo ragazzo restituisce un CFDictionaryRef o qualcosa del genere, e non ho assolutamente idea di come affrontarlo ….

Ho fatto questa risposta nel caso in cui nessuno ci mostra come usare kAudioSessionProperty_AudioRouteDescription , dove cercherò di accettare la mia risposta …

Tuttavia, se qualcuno potrebbe mostrarci come usare questo kAudioSessionProperty_AudioRouteDescription , la taglia è giustamente sua.

modificare:

Chiaramente, questo è un problema di iOS 5. Non l’ho detto prima perché sembrava troppo ovvio, ma poi ho pensato che potrebbe non essere così ovvio per i motori di ricerca … se capisci cosa intendo.

Quindi, iOS 5 non funziona con l’interruttore silenzioso / silenzioso sull’iPhone a causa del valore deprecato riferito.

Ho trovato questa libreria http://www.verietassoftware.com/index.php?option=com_content&view=article&id=27&Itemid=115

La Apple avrebbe permesso quella roba? È una libreria da 500Kb che fa magie nere con impostazioni audio e telefono