2010-10-23 5 views
10

Sto sviluppando un'applicazione iOS (destinata specificamente per iPhone, al momento) che richiede l'applicazione a registrazione audio solo da microfono interno iPhone (anche quando cuffia/cuffia è collegata), e riproduzione in cuffia (supponiamo che la cuffia sia collegata per ora).Forzatura microfono iPhone come ingresso audio

Mi chiedo se questo sia attualmente possibile con le API disponibili? Se è così, qualcuno può per favore fare un po 'di luce su come faccio a fare questo?

Grazie!

+1

le domande più interessanti e innovative, naturalmente, andranno senza risposta. avrai molto lavoro da fare da solo. – cregox

+0

La registrazione tramite microfono interno e la riproduzione simultanea tramite gli auricolari delle cuffie (e il microfono delle cuffie non è inutilizzato) era impossibile in iOS6. In iOS7, questo è possibile tramite le estensioni API trovate nella classe AVAudioSession. –

+0

@Daniel S. come possiamo registrare dal microfono interno e la riproduzione tramite gli auricolari della cuffia? –

risposta

2

Io sono abbastanza fiducioso questo è possibile tramite Audio Session dell'applicazione:

Un sessione audio svolge attività di intermediazione tra l'applicazione e iOS. Ogni applicazione per iPhone ha esattamente una sessione audio . Lo si configura in per esprimere le intenzioni audio della propria applicazione . Per iniziare, è rispondere ad alcune domande su come si desidera che l'applicazione a comportarsi:

  • Come si desidera che l'applicazione rispondere alle interruzioni, come ad esempio una chiamata telefono?
  • Avete intenzione di mescolare i suoni dell'applicazione con quelli di altre applicazioni in esecuzione o avete intenzione di silenziarli con lo ?
  • Come dovrebbe l'applicazione risponde a un cambiamento di percorso audio , ad esempio, quando un utente tappi in o stacca un auricolare?

Con risposte in mano, si impiegano l'interfaccia sessione audio (dichiarata in AudioToolbox/AudioServices.h) per configurare la sessione audio e l'applicazione .

Dig su questi documenti:

e fatemi sapere come va!

+0

Alla risposta punto. Scaverai in profondità nei punti sopra e ti faccio sapere cosa mi fa lavorare.Grazie @defbyte –

8

Credo che la risposta a questa domanda sia "no". Ho usato un iPhone 4 e l'AVFoundation da nuovo a iOS 4 per sperimentare, concentrandomi sulla classe AVCaptureDevice.

ho aggiunto il testo seguente un'applicazione:

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

Così che chiede che tutti i dispositivi che possono essere utilizzati per la cattura audio e/o video essere incluso.Senza le cuffie collegate, ottengo:

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

Con le cuffie collegate in ottengo:

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

Così il microfono iPhone cade fuori dalla lista dei AVCaptureDevices disponibili non appena le cuffie diventano disponibili. Per verificare ulteriormente, ho aggiunto un breve bit di codice per afferrare l'istanza di AVCaptureDevice per il dispositivo audio disponibile e per stampare il suo ID univoco. Sia per il dispositivo che si identifica come "iPhone Microfono" e il dispositivo si identifica come "Cuffie", ho ottenuto:

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

Sembrerebbe a me di essere ovvio che due dispositivi non possono avere lo stesso ID univoco , così chiaramente è lo stesso dispositivo che cambia il suo stato. Sebbene AVCaptureDevices abbia un sacco di roba per impostare lo stato, è limitato alle cose visive come messa a fuoco, esposizione, flash e bilanciamento del bianco.

2

Non è possibile, provo a capire con il listener di route modificato (con AudioSession). Il mio risultato è: non è possibile configurare separatamente input o output a causa di categories fornito da Apple. Provo * PlayAndRecord, quando accoppiare un dispositivo Bluetooth, il cambiamento percorso come questo:

old route : HeadsetBT 
new route : SpeakerAndMicrophone 

Infatti, il mio bluetooth non è una cuffia, a soli oratori ... Quindi per me non esiste una soluzione.

+0

stesso problema. i miei altoparlanti BT e BT hanno entrambi BluetoothHFP al posto di BluetoothA2DP per gli altoparlanti –

4

Sembra proprio impossibile.

Il mio obiettivo è inviare l'output agli auricolari bluetooth e registrare l'input anche da esso. Per quanto posso vedere, i miei migliori opzioni sono: "PlayAndRecord + AllowBluetoothInput" proprietà (iPhone 4, Nokia BH-214 auricolare)

cosa importante è che secondo la documentazione di Apple, si ha sempre a RE-override la tua categoria audio quando cambia rotta audio!

QUESTO È IL MIO metodo listener ROUTE CHANGE, che le stampe: 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

nei simulatori iOS 8, è necessario modificare: if (CFArrayGetCount (output)> 0) a: if (output && CFArrayGetCount (output)> 0) –

3

da quando Apple ha cambiato il sistema audio di nuovo a partire dal 7,0 ho intenzione di inserire il codice di aggiornamento qui:

#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(@"]--------------------------[ ]-----------------------------["); 

} 

Ricordarsi di aggiungere osservatore dal delegato della sessione audio e è deprecata troppo:

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

PS: Non avete bisogno di ripristinare la categoria qui (come in 6.0)