2010-10-23 15 views
10

Estoy desarrollando una aplicación para iOS (dirigida específicamente para iPhone, por el momento) que requiere la aplicación para grabar audio solo desde el micrófono interno del iPhone (incluso cuando los auriculares/auriculares están enchufados), y reproducción en auriculares (supongamos que los auriculares están enchufados por el momento).Forcing iPhone Micrófono como entrada de audio

Me pregunto si esto es posible actualmente con las API disponibles? Si es así, ¿alguien puede arrojar algo de luz sobre cómo hago esto?

Gracias!

+1

las preguntas más interesantes e innovadores, naturalmente, quedarán sin respuesta. tendrás mucho trabajo por hacer solo. – cregox

+0

La grabación a través del micrófono interno y la reproducción simultánea a través de los auriculares de un auricular (y el micrófono del auricular no está en uso) era imposible en iOS6. En iOS7, esto es posible a través de las extensiones de API que se encuentran en la clase AVAudioSession. –

+0

@ Daniel S. ¿Cómo podemos grabar desde el micrófono interno y la reproducción a través de auriculares con auriculares? –

Respuesta

2

estoy bastante seguro de que esto es posible a través de sesiones de audio de su aplicación:

Una sesión de audio es un intermediario entre la aplicación y el IOS. Cada aplicación de iPhone tiene exactamente una sesión de audio . Lo configura en para expresar las intenciones de audio de su aplicación . Para empezar, su respuesta es algunas preguntas acerca de cómo desea que la aplicación se comporte :

  • ¿Cómo desea su aplicación a responden a las interrupciones, tales como una llamada telefónica ?
  • ¿Tiene la intención de mezclar los sonidos de la aplicación con los de otras aplicaciones en ejecución, o tiene la intención de silenciarlos?
  • ¿Cómo debe su aplicación responda a un cambio de ruta de audio , por ejemplo, cuando un usuario tapones en o desenchufa un auricular?

Con respuestas en la mano, que emplean la interfaz de sesión de audio (declarada en AudioToolbox/AudioServices.h) a configurar la sesión de audio y su aplicación .

Dig en estos documentos:

y quiero saber cómo va!

+0

Hasta el punto de respuesta. Profundizaré en los puntos anteriores y les dejaré saber qué es lo que me funciona.Gracias @defbyte –

8

Creo que la respuesta a esta pregunta es 'no'. Usé un iPhone 4 y la AVFoundation nueva para iOS 4 para experimentar, centrándome en la clase AVCaptureDevice.

que añade lo siguiente a una aplicación:

NSLog(@"%@", [AVCaptureDevice devices]); 

Así que pide que todos los dispositivos que se pueden utilizar para la captura de audio y/o vídeo pueden enumerar.Sin los auriculares enchufados, me sale:

(
    "Back Camera", 
    "Front Camera", 
    "iPhone Microphone" 
) 

Con los auriculares conectados consigo:

(
    "Back Camera", 
    "Front Camera", 
    Headphones 
) 

Así el micrófono iPhone cae fuera de la lista de AVCaptureDevices disponibles tan pronto como los auriculares estén disponibles. Para probar esto más a fondo, agregué un poco de código rápido para tomar la instancia de AVCaptureDevice para el dispositivo de audio disponible e imprimir su identificación única. Por tanto el dispositivo que se identifica como "iPhone Micrófono" y el dispositivo que se identifica como "auriculares", que tengo:

com.apple.avfoundation.avcapturedevice.built-in_audio:0 

Parecería a mí ser obvio que dos dispositivos no pueden tener el mismo identificador único , así que claramente es el mismo dispositivo cambiando su estado. Aunque AVCaptureDevices tiene muchas cosas para establecer el estado, se limita a elementos visuales como el enfoque, la exposición, el flash y el balance de blancos.

2

No es posible, trato de averiguar con la ruta modificada oyente (con AudioSession). Mi resultado es: no se puede configurar por separado la entrada o la salida debido a categories proporcionada por Apple. Trato * PlayAndRecord, cuando conecto un dispositivo bluetooth, cambio de ruta de esta manera:

old route : HeadsetBT 
new route : SpeakerAndMicrophone 

De hecho, mi bluetooth no es unos auriculares, altavoces sólo ... Así que para mí no hay solución.

+0

mismo problema. mi altavoz BT y los auriculares BT muestran BluetoothHFP en lugar de BluetoothA2DP para el altavoz –

4

Parece que no es posible.

Mi objetivo es enviar la salida a los auriculares bluetooth y registrar la entrada de ella también. Por lo que puedo ver, mis mejores opciones son: "PlayAndRecord + AllowBluetoothInput" propiedad (iPhone 4, Nokia BH-214 auricular)

Lo importante es que de acuerdo a la documentación de Apple, que siempre tiene que volver a anulación su categoría de audio cuando cambia la ruta de audio!

ESTA ES MI método detector cambio de ruta, que las impresiones: RouteChangeReasons, outputRoute, audioRout:

void RouteChangeListener(void     *inClientData, 
        AudioSessionPropertyID inID, 
        UInt32     inDataSize, 
        const void    *inData) { 


if (inID == kAudioSessionProperty_AudioRouteChange) { 

    NSLog(@"]-----------------[ Audio Route Change ]--------------------["); 

    // ************************************************************************************************ 
    // Check route change reason ********************************************************************** 
    // ************************************************************************************************ 
    CFDictionaryRef routeDict = (CFDictionaryRef)inData; 
    NSNumber* reasonValue = (NSNumber*)CFDictionaryGetValue(routeDict, CFSTR(kAudioSession_AudioRouteChangeKey_Reason)); 
    int reason = [reasonValue intValue]; 

    if (reason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) { 
     NSLog(@"] Logic: audio route change reason: OldDeviceUnavailable"); 
    }else if (reason == kAudioSessionRouteChangeReason_NewDeviceAvailable) { 
     NSLog(@"] Logic: audio route change reason: NewDeviceAvailable"); 
    }else if (reason == kAudioSessionRouteChangeReason_Unknown) { 
     NSLog(@"] Logic: audio route change reason: Unknown"); 
    }else if (reason == kAudioSessionRouteChangeReason_CategoryChange) { 
     NSLog(@"] Logic: audio route change reason: CategoryChange"); 
    }else if (reason == kAudioSessionRouteChangeReason_Override) { 
     NSLog(@"] Logic: audio route change reason: Override"); 
    }else if (reason == kAudioSessionRouteChangeReason_WakeFromSleep) { 
     NSLog(@"] Logic: audio route change reason: WakeFromSleep"); 
    }else if (reason == kAudioSessionRouteChangeReason_NoSuitableRouteForCategory) { 
     NSLog(@"] Logic: audio route chang reasone: NoSuitableRouteForCategory"); 
    } 

    // ************************************************************************************************ 
    // Check output type ****************************************************************************** 
    // ************************************************************************************************ 
    CFDictionaryRef currentRouteDescriptionDictionary = nil; 
    UInt32 dataSize = sizeof(currentRouteDescriptionDictionary); 
    AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, &currentRouteDescriptionDictionary); 
    if (currentRouteDescriptionDictionary) { 
     CFArrayRef outputs = CFDictionaryGetValue(currentRouteDescriptionDictionary, kAudioSession_AudioRouteKey_Outputs); 
     if(CFArrayGetCount(outputs) > 0) { 
      CFDictionaryRef currentOutput = CFArrayGetValueAtIndex(outputs, 0); 
      CFStringRef outputType = CFDictionaryGetValue(currentOutput, kAudioSession_AudioRouteKey_Type); 

      if ((CFStringCompare(outputType, kAudioSessionOutputRoute_AirPlay, 0) == kCFCompareEqualTo)) {    // if Airplay 
       NSLog(@"] Logic: output changed to Airplay"); 
      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_BluetoothA2DP, 0) == kCFCompareEqualTo)) {  // if Bluetooth A2DP 
       NSLog(@"] Logic: output changed to A2DP"); 

       // Mix with others category 
       UInt32 doSetProperty = 1; 
       AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); 

       // Bluetooth support enable 
       UInt32 allowBluetoothInput = 1; 
       AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); 


      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_BluetoothHFP, 0) == kCFCompareEqualTo)) {  // if Bluetooth HFP 
       NSLog(@"] Logic: output changed to HFP"); 
       // Mix with others category 
       UInt32 doSetProperty = 1; 
       AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); 

       // Bluetooth support enable 
       UInt32 allowBluetoothInput = 1; 
       AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); 
      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_LineOut, 0) == kCFCompareEqualTo)) {   // if Line Out 
       NSLog(@"] Logic: output changed to Line Out"); 
      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_Headphones, 0) == kCFCompareEqualTo)) {  // if Headphones 
       NSLog(@"] Logic: output changed to Headphone"); 

       // Mix with others category 
       UInt32 doSetProperty = 1; 
       AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); 

       // Bluetooth support disable 
       UInt32 allowBluetoothInput = 0; 
       AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); 

      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_BuiltInSpeaker, 0) == kCFCompareEqualTo)) { // if Built In Speaker 
       NSLog(@"] Logic: output changed to Built In Speaker"); 

       // Mix with others category 
       UInt32 doSetProperty = 1; 
       AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); 

      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_USBAudio, 0) == kCFCompareEqualTo)) {   // if USB audio 
       NSLog(@"] Logic: output changed to USB Audio"); 
      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_HDMI, 0) == kCFCompareEqualTo)) {    // if HDMI 
       NSLog(@"] Logic: output changed to HDMI"); 
      } 
      else if ((CFStringCompare(outputType, kAudioSessionOutputRoute_BuiltInReceiver, 0) == kCFCompareEqualTo)) { // if Built in Reciever 
       NSLog(@"] Logic: output changed to Built in Reciever"); 

       // Mix with others category 
       UInt32 doSetProperty = 1; 
       AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); 
      } 
      else {                           // Unknown audio type 
       NSLog(@"] Logic: WARNING: Unknown audio type: %@",(NSString*)outputType); 
      } 
     } 



    } 

    // ************************************************************************************************ 
    // Check audio route ****************************************************************************** 
    // ************************************************************************************************ 
    UInt32 routeSize = sizeof(CFStringRef); 
    CFStringRef route; 
    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route); 
    NSLog(@"] Logic: the audio route is: %@",(NSString*)route); 


    // ************************************************************************************************ 
    NSLog(@"]--------------------------[ ]-----------------------------[");   

} 

}

+0

en los simuladores iOS 8, es necesario cambiar: if (CFArrayGetCount (outputs)> 0) a: if (outputs && CFArrayGetCount (outputs)> 0) –

3

Desde Apple cambió el sistema de audio de nuevo a partir de 7,0 voy a publique el código de actualización aquí:

#pragma mark Route change listener 
// ********************************************************************************************************* 
// *********** Route change listener *********************************************************************** 
// ********************************************************************************************************* 
-(void)routeChanged:(NSNotification*)notification { 

    NSLog(@"]-----------------[ Audio Route Change ]--------------------["); 

    AVAudioSession *session = [AVAudioSession sharedInstance]; 

    //AVAudioSessionRouteDescription* prevRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey]; 

    // Reason 
    NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; 
    switch (reason) { 
     case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: 
      NSLog(@"] Audio Route: The route changed because no suitable route is now available for the specified category."); 
      break; 
     case AVAudioSessionRouteChangeReasonWakeFromSleep: 
      NSLog(@"] Audio Route: The route changed when the device woke up from sleep."); 
      break; 
     case AVAudioSessionRouteChangeReasonOverride: 
      NSLog(@"] Audio Route: The output route was overridden by the app."); 
      break; 
     case AVAudioSessionRouteChangeReasonCategoryChange: 
      NSLog(@"] Audio Route: The category of the session object changed."); 
      break; 
     case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: 
      NSLog(@"] Audio Route: The previous audio output path is no longer available."); 
      break; 
     case AVAudioSessionRouteChangeReasonNewDeviceAvailable: 
      NSLog(@"] Audio Route: A preferred new audio output path is now available."); 
      break; 
     case AVAudioSessionRouteChangeReasonUnknown: 
      NSLog(@"] Audio Route: The reason for the change is unknown."); 
      break; 
     default: 
      NSLog(@"] Audio Route: The reason for the change is very unknown."); 
      break; 
    } 

    // Output 
    AVAudioSessionPortDescription *output = [[session.currentRoute.outputs count]?session.currentRoute.outputs:nil objectAtIndex:0]; 
    if ([output.portType isEqualToString:AVAudioSessionPortLineOut]) { 
     NSLog(@"] Audio Route: Output Port: LineOut"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortHeadphones]) { 
     NSLog(@"] Audio Route: Output Port: Headphones"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) { 
     NSLog(@"] Audio Route: Output Port: BluetoothA2DP"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortBuiltInReceiver]) { 
     NSLog(@"] Audio Route: Output Port: BuiltInReceiver"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) { 
     NSLog(@"] Audio Route: Output Port: BuiltInSpeaker"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortHDMI]) { 
     NSLog(@"] Audio Route: Output Port: HDMI"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortAirPlay]) { 
     NSLog(@"] Audio Route: Output Port: AirPlay"); 
    } 
    else if ([output.portType isEqualToString:AVAudioSessionPortBluetoothLE]) { 
     NSLog(@"] Audio Route: Output Port: BluetoothLE"); 
    } 
    else { 
     NSLog(@"] Audio Route: Output Port: Unknown: %@",output.portType); 
    } 

    // Input 
    AVAudioSessionPortDescription *input = [[session.currentRoute.inputs count] ? session.currentRoute.inputs:nil objectAtIndex:0]; 

    if ([input.portType isEqualToString:AVAudioSessionPortLineIn]) { 
     NSLog(@"] Audio Route: Input Port: LineIn"); 
    } 
    else if ([input.portType isEqualToString:AVAudioSessionPortBuiltInMic]) { 
     NSLog(@"] Audio Route: Input Port: BuiltInMic"); 
    } 
    else if ([input.portType isEqualToString:AVAudioSessionPortHeadsetMic]) { 
     NSLog(@"] Audio Route: Input Port: HeadsetMic"); 
    } 
    else if ([input.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) { 
     NSLog(@"] Audio Route: Input Port: BluetoothHFP"); 
    } 
    else if ([input.portType isEqualToString:AVAudioSessionPortUSBAudio]) { 
     NSLog(@"] Audio Route: Input Port: USBAudio"); 
    } 
    else if ([input.portType isEqualToString:AVAudioSessionPortCarAudio]) { 
     NSLog(@"] Audio Route: Input Port: CarAudio"); 
    } 
    else { 
     NSLog(@"] Audio Input Port: Unknown: %@",input.portType); 
    } 

    NSLog(@"]--------------------------[ ]-----------------------------["); 

} 

Recuerde agregar el observador desde la delegación de la sesión de audio e está en desuso también:

[[NSNotificationCenter defaultCenter] addObserver: self 
               selector: @selector(audioInterruption:) 
                name: AVAudioSessionInterruptionNotification 
                object: nil]; 

PD: ya no tienes que reiniciar la categoría aquí (como en 6.0)

Cuestiones relacionadas