2011-08-19 14 views
14

मैं मिक्सर इकाई आउटपुट द्वारा उत्पादित ध्वनि रिकॉर्ड करने की कोशिश कर रहा हूं।मिक्सर इकाई आउटपुट (आईओएस कोर ऑडियो और ऑडियो ग्राफ) द्वारा उत्पादित ध्वनि को रिकॉर्ड करने के लिए कैसे करें

पल के लिए, मेरे कोड apple MixerHost iOS app डेमो पर आधारित है: एक मिक्सर नोड ऑडियो graphe पर एक दूरदराज के आईओ नोड से जुड़ा है।

और मुझे मिक्सर उत्पादन पर दूरदराज के आईओ नोड इनपुट पर एक इनपुट कॉलबैक स्थापित करने के लिए प्रयास करें।

मैं कुछ गलत करता हूं लेकिन मुझे त्रुटि नहीं मिल रही है।

यहां नीचे दिया गया कोड है। यह सिर्फ मल्टीचैनल मिक्सर इकाई सेटअप के बाद किया जाता है:

// I/O stream format 
iOStreamFormat.mSampleRate   = 44100.0; 
iOStreamFormat.mFormatID   = kAudioFormatLinearPCM; 
iOStreamFormat.mFormatFlags   = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
iOStreamFormat.mFramesPerPacket  = 1; 
iOStreamFormat.mChannelsPerFrame = 1; 
iOStreamFormat.mBitsPerChannel  = 16; 
iOStreamFormat.mBytesPerPacket  = 2; 
iOStreamFormat.mBytesPerFrame  = 2; 

[self printASBD: iOStreamFormat]; 

फिर प्रारूप को प्रभावित और नमूना दर निर्दिष्ट करें::

UInt32 flag = 1; 

// Enable IO for playback 
result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 
           0, // Output bus 
           &flag, 
           sizeof(flag)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;} 

/* can't do that because *** AudioUnitSetProperty EnableIO error: -1073752493 00000000 
result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 
           0, // Output bus 
           &flag, 
           sizeof(flag)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;} 
*/ 

फिर एक स्ट्रीम प्रारूप बनाने तब

result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 
           1, // Input bus 
           &iOStreamFormat, 
           sizeof(iOStreamFormat)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;} 

result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 
           0, // Output bus 
           &iOStreamFormat, 
           sizeof(iOStreamFormat)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;} 

// SampleRate I/O 
result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 
           0, // Output 
           &graphSampleRate, 
           sizeof (graphSampleRate)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty (set I/O unit input stream format)" withStatus: result]; return;} 

, मैं रेंडर कॉलबैक सेट करने का प्रयास करें। अपनी रिकॉर्डिंग कॉलबैक >>>

समाधान 1 कहा जाता है कभी नहीं है

effectState.rioUnit = iOUnit; 

AURenderCallbackStruct renderCallbackStruct; 
renderCallbackStruct.inputProc  = &recordingCallback; 
renderCallbackStruct.inputProcRefCon = &effectState; 
result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
           0, // Output bus 
           &renderCallbackStruct, 
           sizeof (renderCallbackStruct)); 
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty SetRenderCallback" withStatus: result]; return;} 

समाधान 2 >>> इस

AURenderCallbackStruct renderCallbackStruct; 
renderCallbackStruct.inputProc  = &recordingCallback; 
renderCallbackStruct.inputProcRefCon = &effectState; 

result = AUGraphSetNodeInputCallback (processingGraph, iONode, 
             0, // Output bus 
             &renderCallbackStruct); 
if (noErr != result) {[self printErrorMessage: @"AUGraphSetNodeInputCallback (I/O unit input callback bus 0)" withStatus: result]; return;} 

पर लांच पर अपने ऐप्लिकेशन क्रैश अगर कोई एक विचार है ...

समाधान संपादित करें 3 (arlo anwser के लिए धन्यवाद) >>

if (noErr != result) {[self printErrorMessage: @"AUGraphInitialize" withStatus: result]; return;} 

// On initialise le fichier audio 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [paths objectAtIndex:0]; 
NSString *destinationFilePath = [[[NSString alloc] initWithFormat: @"%@/output.caf", documentsDirectory] autorelease]; 
NSLog(@">>> %@", destinationFilePath); 
CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false); 

OSStatus setupErr = ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &dstFormat, NULL, kAudioFileFlags_EraseFile, &effectState.audioFileRef); 
CFRelease(destinationURL); 
NSAssert(setupErr == noErr, @"Couldn't create file for writing"); 

setupErr = ExtAudioFileSetProperty(effectState.audioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &stereoStreamFormat); 
NSAssert(setupErr == noErr, @"Couldn't create file for format"); 

setupErr = ExtAudioFileWriteAsync(effectState.audioFileRef, 0, NULL); 
NSAssert(setupErr == noErr, @"Couldn't initialize write buffers for audio file"); 

और रिकॉर्डिंग कॉलबैक:: वहाँ अब एक प्रारूप समस्या

AudioStreamBasicDescription dstFormat = {0}; 
dstFormat.mSampleRate=44100.0; 
dstFormat.mFormatID=kAudioFormatLinearPCM; 
dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked; 
dstFormat.mBytesPerPacket=4; 
dstFormat.mBytesPerFrame=4; 
dstFormat.mFramesPerPacket=1; 
dstFormat.mChannelsPerFrame=2; 
dstFormat.mBitsPerChannel=16; 
dstFormat.mReserved=0; 

result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 
        1, 
        &stereoStreamFormat, 
        sizeof(stereoStreamFormat)); 

if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;} 


result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 
        0, 
        &stereoStreamFormat, 
        sizeof(stereoStreamFormat)); 

if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;} 


AudioUnitAddRenderNotify(
         iOUnit, 
         &recordingCallback, 
         &effectState 
         ); 

और फ़ाइल सेटअप है

static OSStatus recordingCallback  (void *       inRefCon, 
           AudioUnitRenderActionFlags *  ioActionFlags, 
           const AudioTimeStamp *   inTimeStamp, 
           UInt32       inBusNumber, 
           UInt32       inNumberFrames, 
           AudioBufferList *     ioData) { 
if (*ioActionFlags == kAudioUnitRenderAction_PostRender && inBusNumber == 0) 
{ 
    EffectState *effectState = (EffectState *)inRefCon; 

    ExtAudioFileWriteAsync(effectState->audioFileRef, inNumberFrames, ioData); 
} 
return noErr;  
} 

वहाँ कुछ आउटपुट फ़ाइल output.caf :) में लापता है। मैं आवेदन करने के लिए प्रारूपों में पूरी तरह से खो गया हूँ।

+0

मैं एक ही bt MixerHost उदाहरण से अधिक उर कोड लागू करने के लिए यू कर सकते हैं plz मेरी मदद नहीं कर पा .. – Aadil

+0

हाय lefakir करने के लिए कोशिश कर रहा हूँ और arlomedia, क्या यह संभव है कि आप EffectState क्लास पोस्ट कर सकें? मैं मिक्सरहोस्ट और उपरोक्त का उपयोग कर कामकाजी कोड को पुन: पेश करने की कोशिश कर रहा हूं। बेस्ट, ग्रेगोर –

+0

हाय ग्रेगोर, आपको यहां देखना चाहिए http://stackoverflow.com/questions/7032468/record-sounds-played-by-my-iphone-app-with-audio-units। इस सवाल में EffectState संरचना घोषित की गई है। – lefakir

उत्तर

15

मुझे नहीं लगता कि आपको I/O इकाई पर इनपुट सक्षम करने की आवश्यकता है। मैं आपके कॉलबैक को चलाने तक I/O इकाई पर प्रारूप और नमूना दर कॉन्फ़िगरेशन पर भी टिप्पणी करूंगा, क्योंकि एक बेमेल या असमर्थित प्रारूप ऑडियो इकाइयों को एक साथ जोड़ने से रोक सकता है।

इस विधि कॉलबैक जोड़ने के लिए, कोशिश करने के लिए:

AudioUnitAddRenderNotify(
    iOUnit, 
    &recordingCallback, 
    self 
); 

जाहिर अन्य तरीकों नोड कनेक्शन का स्थान ले लेगा, लेकिन इस पद्धति नहीं होंगे - इसलिए आपके ऑडियो इकाइयों कनेक्ट रह सकते हैं, भले ही आपके द्वारा जोड़ी गई एक कॉलबैक

अपने कॉलबैक एक बार चल रहा है, यदि आप पाते हैं वहाँ बफ़र्स (ioData) में कोई डेटा उपलब्ध न, अपने कॉलबैक कोड चारों ओर इस कोड को लपेट:

if (*ioActionFlags == kAudioUnitRenderAction_PostRender) { 
    // your code 
} 

यह इसलिए आवश्यक है क्योंकि एक कॉलबैक इस तरह से रन में जोड़ा ऑडियो इकाई के पहले और बाद में दोनों अपने ऑडियो प्रस्तुत करते हैं, लेकिन आप इसे प्रस्तुत करने के बाद बस अपना कोड चलाने के लिए चाहते हैं।

कॉलबैक चलने के बाद, अगला चरण यह पता लगाना है कि यह कौन सा ऑडियो प्रारूप प्राप्त कर रहा है और इसे उचित तरीके से संभाल रहा है। अपने कॉलबैक करने के लिए इस जोड़ने का प्रयास करें:

SInt16 *dataLeftChannel = (SInt16 *)ioData->mBuffers[0].mData; 
for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) { 
    NSLog(@"sample %lu: %d", frameNumber, dataLeftChannel[frameNumber]); 
} 

यह इतना अपने अनुप्रयोग कि यह शायद वास्तव में खेलने से किसी भी ऑडियो पाएगा धीमी हो जाएगी, लेकिन आप इसे काफी लंबे समय क्या नमूने की तरह लग रही देखने के लिए चलाने के लिए सक्षम होना चाहिए। यदि कॉलबैक 16-बिट ऑडियो प्राप्त कर रहा है, तो नमूने -32000 और 32000 के बीच सकारात्मक या नकारात्मक पूर्णांक होना चाहिए। यदि नमूने सामान्य दिखने वाले नंबर और बहुत छोटी संख्या के बीच वैकल्पिक होते हैं, तो इस कोड को अपने कॉलबैक में इसके बजाय आज़माएं:

SInt32 *dataLeftChannel = (SInt32 *)ioData->mBuffers[0].mData; 
for (UInt32 frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber) { 
    NSLog(@"sample %lu: %ld", frameNumber, dataLeftChannel[frameNumber]); 
} 

यह आपको पूर्ण 8.24 नमूने दिखाएगा।

यदि आप कॉलबैक प्राप्त करने वाले प्रारूप में डेटा को सहेज सकते हैं, तो आपको अपनी आवश्यकता होनी चाहिए। यदि आपको इसे किसी भिन्न प्रारूप में सहेजने की आवश्यकता है, तो आप रिमोट I/O ऑडियो इकाई में प्रारूप को रूपांतरित करने में सक्षम होना चाहिए ... लेकिन जब मैं मल्टीचैनल मिक्सर इकाई से कनेक्ट होता हूं तो haven't been able to figure out how to do that। एक विकल्प के रूप में, आप Audio Converter Services का उपयोग कर डेटा को कन्वर्ट कर सकते हैं। सबसे पहले, इनपुट और आउटपुट स्वरूपों को परिभाषित:

AudioStreamBasicDescription monoCanonicalFormat; 
size_t bytesPerSample = sizeof (AudioUnitSampleType); 
monoCanonicalFormat.mFormatID   = kAudioFormatLinearPCM; 
monoCanonicalFormat.mFormatFlags  = kAudioFormatFlagsAudioUnitCanonical; 
monoCanonicalFormat.mBytesPerPacket = bytesPerSample; 
monoCanonicalFormat.mFramesPerPacket = 1; 
monoCanonicalFormat.mBytesPerFrame  = bytesPerSample; 
monoCanonicalFormat.mChannelsPerFrame = 1; 
monoCanonicalFormat.mBitsPerChannel = 8 * bytesPerSample; 
monoCanonicalFormat.mSampleRate  = graphSampleRate; 

AudioStreamBasicDescription mono16Format; 
bytesPerSample = sizeof (SInt16); 
mono16Format.mFormatID   = kAudioFormatLinearPCM; 
mono16Format.mFormatFlags  = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
mono16Format.mChannelsPerFrame = 1; 
mono16Format.mSampleRate  = graphSampleRate; 
mono16Format.mBitsPerChannel = 16; 
mono16Format.mFramesPerPacket = 1; 
mono16Format.mBytesPerPacket = 2; 
mono16Format.mBytesPerFrame = 2; 

फिर अपने कॉलबैक बाहर कहीं एक कनवर्टर परिभाषित करते हैं, और रूपांतरण के दौरान डेटा को संभालने के लिए एक अस्थायी बफर बनाने के लिए:

AudioConverterRef formatConverterCanonicalTo16; 
@property AudioConverterRef formatConverterCanonicalTo16; 
@synthesize AudioConverterRef; 
AudioConverterNew(
    &monoCanonicalFormat, 
    &mono16Format, 
    &formatConverterCanonicalTo16 
); 

SInt16 *data16; 
@property (readwrite) SInt16 *data16; 
@synthesize data16; 
data16 = malloc(sizeof(SInt16) * 4096); 

फिर अपने कॉलबैक में जोड़ना , आप अपने डेटा को बचाने से पहले:

UInt32 dataSizeCanonical = ioData->mBuffers[0].mDataByteSize; 
SInt32 *dataCanonical = (SInt32 *)ioData->mBuffers[0].mData; 
UInt32 dataSize16 = dataSizeCanonical; 

AudioConverterConvertBuffer(
    effectState->formatConverterCanonicalTo16, 
    dataSizeCanonical, 
    dataCanonical, 
    &dataSize16, 
    effectState->data16 
); 

तो फिर तुम data16 बचा सकता है, जो 16-बिट प्रारूप में है और हो सकता है कि आप अपने फ़ाइल में सहेजा चाहते हैं। यह कैननिकल डेटा के रूप में अधिक संगत और आधे से अधिक होगा।

जब आप कर रहे हैं, आप नीचे दिए कुछ साफ कर सकते हैं:

AudioConverterDispose(formatConverterCanonicalTo16); 
free(data16); 
+0

धन्यवाद! मेरा कॉलबैक संभाला जाता है लेकिन मैं शोर रिकॉर्ड कर रहा हूं! – lefakir

+0

मैंने अभी अगले चरण को शामिल करने के लिए अपना उत्तर अपडेट किया है कि आपके पास कॉलबैक चल रहा है। – arlomedia

+0

मैंने अपने प्रश्न को संपादित किया है कि मैं – lefakir

संबंधित मुद्दे