2012-08-30 18 views
5

Tôi đang viết ứng dụng iOS lấy đầu vào từ micrô, chạy nó qua bộ lọc âm thanh bộ lọc cao và phát lại qua loa. Tôi đã có thể làm điều này thành công bằng cách sử dụng API AUGraph. Trong đó, tôi đặt hai nút: một đơn vị I/O từ xa và một đơn vị âm thanh có hiệu lực (kAudioUnitType_Effect, kAudioUnitSubType_HighPassFilter) và kết nối đầu ra của phần tử đầu vào của đơn vị io với đầu vào của đơn vị hiệu ứng và đầu ra của nút hiệu ứng tới đơn vị io phạm vi đầu vào của phần tử đầu ra. Nhưng bây giờ tôi có nhu cầu làm một số phân tích dựa trên các mẫu âm thanh được xử lý, vì vậy tôi cần truy cập trực tiếp vào bộ đệm. Điều này có nghĩa (và hãy sửa tôi nếu tôi sai) Tôi không còn có thể sử dụng AUGraphConnectNodeInput để tạo kết nối giữa đầu ra của nút hiệu ứng và phần tử đầu ra của đơn vị io và phải đính kèm hàm gọi lại hiển thị cho phần tử đầu ra của đơn vị io, để tôi có thể truy cập bộ đệm bất cứ khi nào loa cần mẫu mới. Tôi đã làm như vậy, nhưng tôi nhận được lỗi -50 khi tôi gọi hàm AudioUnitRender trong gọi lại hiển thị. Tôi tin rằng tôi có một trường hợp ASBD không phù hợp giữa hai đơn vị âm thanh, vì tôi không làm bất cứ điều gì về điều đó trong gọi lại hiển thị (và biểu đồ AUGraph đã xử lý nó trước đây). Dưới đây là các mã:Sự cố khi ghi I/O từ xa hiển thị chức năng gọi lại

AudioController.h:

@interface AudioController : NSObject 
{ 
    AUGraph mGraph; 
    AudioUnit mEffects; 
    AudioUnit ioUnit; 
} 

@property (readonly, nonatomic) AudioUnit mEffects; 
@property (readonly, nonatomic) AudioUnit ioUnit; 

-(void)initializeAUGraph; 
-(void)startAUGraph; 
-(void)stopAUGraph; 

@end 

AudioController.mm:

@implementation AudioController 

… 

static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 
{ 
    AudioController *THIS = (__bridge AudioController*)inRefCon; 

    AudioBuffer buffer; 

    AudioStreamBasicDescription fxOutputASBD; 
    UInt32 fxOutputASBDSize = sizeof(fxOutputASBD); 
    AudioUnitGetProperty([THIS mEffects], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &fxOutputASBD, &fxOutputASBDSize); 

    buffer.mDataByteSize = inNumberFrames * fxOutputASBD.mBytesPerFrame; 
    buffer.mNumberChannels = fxOutputASBD.mChannelsPerFrame; 
    buffer.mData = malloc(buffer.mDataByteSize); 

    AudioBufferList bufferList; 
    bufferList.mNumberBuffers = 1; 
    bufferList.mBuffers[0] = buffer; 

    //TODO prender ARM y solucionar problema de memoria 

    OSStatus result = AudioUnitRender([THIS mEffects], ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); 
    [THIS hasError:result:__FILE__:__LINE__]; 

    memcpy(ioData, buffer.mData, buffer.mDataByteSize); 

    return noErr; 
} 


- (void)initializeAUGraph 
{ 
    OSStatus result = noErr; 

    // create a new AUGraph 
    result = NewAUGraph(&mGraph); 

    AUNode outputNode; 
    AUNode effectsNode; 

    AudioComponentDescription effects_desc; 
    effects_desc.componentType = kAudioUnitType_Effect; 
    effects_desc.componentSubType = kAudioUnitSubType_LowPassFilter; 
    effects_desc.componentFlags = 0; 
    effects_desc.componentFlagsMask = 0; 
    effects_desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

    AudioComponentDescription output_desc; 
    output_desc.componentType = kAudioUnitType_Output; 
    output_desc.componentSubType = kAudioUnitSubType_RemoteIO; 
    output_desc.componentFlags = 0; 
    output_desc.componentFlagsMask = 0; 
    output_desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

    // Add nodes to the graph to hold the AudioUnits 
    result = AUGraphAddNode(mGraph, &output_desc, &outputNode); 
    [self hasError:result:__FILE__:__LINE__]; 
    result = AUGraphAddNode(mGraph, &effects_desc, &effectsNode); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Connect the effect node's output to the output node's input 
    // This is no longer the case, as I need to access the buffer 
    // result = AUGraphConnectNodeInput(mGraph, effectsNode, 0, outputNode, 0); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Connect the output node's input scope's output to the effectsNode input 
    result = AUGraphConnectNodeInput(mGraph, outputNode, 1, effectsNode, 0); 
    [self hasError:result:__FILE__:__LINE__]; 

    // open the graph AudioUnits 
    result = AUGraphOpen(mGraph); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Get a link to the effect AU 
    result = AUGraphNodeInfo(mGraph, effectsNode, NULL, &mEffects); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Same for io unit 
    result = AUGraphNodeInfo(mGraph, outputNode, NULL, &ioUnit); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Enable input on io unit 
    UInt32 flag = 1; 
    result = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flag, sizeof(flag)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Setup render callback struct 
    AURenderCallbackStruct renderCallbackStruct; 
    renderCallbackStruct.inputProc = &renderInput; 
    renderCallbackStruct.inputProcRefCon = (__bridge void*)self; 

    // Set a callback for the specified node's specified input 
    result = AUGraphSetNodeInputCallback(mGraph, outputNode, 0, &renderCallbackStruct); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Get fx unit's input current stream format... 
    AudioStreamBasicDescription fxInputASBD; 
    UInt32 sizeOfASBD = sizeof(AudioStreamBasicDescription); 

    result = AudioUnitGetProperty(mEffects, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &fxInputASBD, &sizeOfASBD); 
    [self hasError:result:__FILE__:__LINE__]; 

    // ...and set it on the io unit's input scope's output 
    result = AudioUnitSetProperty(ioUnit, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Output, 
            1, 
            &fxInputASBD, 
            sizeof(fxInputASBD)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Set fx unit's output sample rate, just in case 
    Float64 sampleRate = 44100.0; 

    result = AudioUnitSetProperty(mEffects, 
            kAudioUnitProperty_SampleRate, 
            kAudioUnitScope_Output, 
            0, 
            &sampleRate, 
            sizeof(sampleRate)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Once everything is set up call initialize to validate connections 
    result = AUGraphInitialize(mGraph); 
    [self hasError:result:__FILE__:__LINE__]; 
} 

@end 

Như tôi đã nói trước đây, tôi nhận được một lỗi -50 trên AudioUnitRender cuộc gọi, và Tôi đang tìm kiếm ít hoặc không có tài liệu nào về nó.

Mọi trợ giúp sẽ được đánh giá cao.

Nhờ Tim Bolstad (http://timbolstad.com/2010/03/14/core-audio-getting-started/) để cung cấp hướng dẫn về điểm xuất phát tuyệt vời.

Trả lời

0

Có những ví dụ đơn giản hơn khi sử dụng RemoteIO để chỉ phát bộ đệm âm thanh. Có lẽ bắt đầu với một trong những người đầu tiên chứ không phải là một đồ thị.

0

Kiểm tra để đảm bảo rằng bạn đang thực sự tạo tất cả các kết nối cần thiết. Có vẻ như bạn đang khởi tạo hầu hết mọi thứ cần thiết, nhưng nếu bạn chỉ đơn giản muốn truyền âm thanh, bạn không cần hàm gọi lại trả về.

Bây giờ, nếu bạn muốn thực hiện bộ lọc, bạn có thể cần một bộ lọc, nhưng ngay cả như vậy, hãy đảm bảo rằng bạn đang thực sự kết nối các thành phần với nhau một cách chính xác.

Dưới đây là một đoạn trích từ một ứng dụng tôi đang làm việc trên:

AUGraphConnectNodeInput(graph, outputNode, kInputBus, mixerNode, kInputBus); 
AUGraphConnectNodeInput(graph, mixerNode, kOutputBus, outputNode, kOutputBus); 

này kết nối đầu vào từ các đơn vị RemoteIO cho một đơn vị đa kênh Mixer, sau đó kết nối đầu ra từ máy trộn đến sản lượng của RemoteIO đến loa.

0

Có vẻ như tôi đang truyền đơn vị âm thanh sai đến AudioUnitRender. Tôi nghĩ rằng bạn cần phải vượt qua trong ioUnit thay vì mEffects. Trong mọi trường hợp, hãy kiểm tra kỹ tất cả các tham số bạn đang truy cập vào AudioUnitRender. Khi tôi thấy -50 trả lại là bởi vì tôi đã phá hỏng một trong số họ.

Các vấn đề liên quan