2012-09-27 7 views
4

speex로 인코딩/디코딩하려고합니다. 오디오를 크고 선명하게 표시하지만 오디오 품질을 테스트하기 위해 인코딩/디코딩 할 때, 나는 정말 열악한 음질과 로봇 사운드를 얻는다.Speex (ios)의 품질이 매우 좋지 않습니다. (로봇 식)

여기 내 초기화 오디오 방법입니다 :

#define AUDIO_QUALITY 10 
- (void) initAudio { 
    try { 
     //SPEEX CONFIG 
     speex_bits_init(&bits_in); 
     speex_bits_init(&bits_out); 
     enc_state = speex_encoder_init(&speex_nb_mode); 
     dec_state = speex_decoder_init(&speex_nb_mode); 
     int quality = AUDIO_QUALITY; 
     speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &quality); 
     int tmp=1; 
     speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &tmp); 

     OSStatus status; 

     XThrowIfError(AudioSessionInitialize(NULL, NULL, rioInterruptionListener, self), "couldn't initialize audio session"); 

     float aBufferLength = 0.02; // In seconds 
     status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, 
             sizeof(aBufferLength), &aBufferLength); 
     XThrowIfError(status, ""); 

     UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord; 
     XThrowIfError(AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory), "couldn't set audio category"); 
     XThrowIfError(AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener"); 

     // Describe audio component 
     AudioComponentDescription desc; 
     desc.componentType = kAudioUnitType_Output; 
     desc.componentSubType = kAudioUnitSubType_RemoteIO; 
     desc.componentFlags = 0; 
     desc.componentFlagsMask = 0; 
     desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

     // Get component 
     AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc); 

     // Get audio units 
     status = AudioComponentInstanceNew(inputComponent, &rioUnit); 
     XThrowIfError(status, "1"); 

     // Enable IO for recording 
     UInt32 flag = 1; 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioOutputUnitProperty_EnableIO, 
             kAudioUnitScope_Input, 
             kInputBus, 
             &flag, 
             sizeof(flag)); 
     XThrowIfError(status, "2"); 

     // Enable IO for playback 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioOutputUnitProperty_EnableIO, 
             kAudioUnitScope_Output, 
             kOutputBus, 
             &flag, 
             sizeof(flag)); 
     XThrowIfError(status, "3"); 

     // Describe format 
     AudioStreamBasicDescription audioFormat; 
     audioFormat.mSampleRate   = 8000.00; 
     audioFormat.mFormatID   = kAudioFormatLinearPCM; 
     audioFormat.mFormatFlags  = kAudioFormatFlagIsSignedInteger | 
              kAudioFormatFlagsNativeEndian | 
              kAudioFormatFlagIsPacked; 
     audioFormat.mFramesPerPacket = 1; 
     audioFormat.mChannelsPerFrame = 1; 
     audioFormat.mBitsPerChannel  = 16; 
     audioFormat.mBytesPerPacket  = 2; 
     audioFormat.mBytesPerFrame  = 2; 

     // Apply format 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioUnitProperty_StreamFormat, 
             kAudioUnitScope_Output, 
             kInputBus, 
             &audioFormat, 
             sizeof(audioFormat)); 
     XThrowIfError(status, ""); 

     status = AudioUnitSetProperty(rioUnit, 
             kAudioUnitProperty_StreamFormat, 
             kAudioUnitScope_Input, 
             kOutputBus, 
             &audioFormat, 
             sizeof(audioFormat)); 
     XThrowIfError(status, ""); 

     // Set input callback 
     AURenderCallbackStruct callbackStruct; 
     callbackStruct.inputProc = recordingCallback; 
     callbackStruct.inputProcRefCon = self; 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioOutputUnitProperty_SetInputCallback, 
             kAudioUnitScope_Global, 
             kInputBus, 
             &callbackStruct, 
             sizeof(callbackStruct)); 
     XThrowIfError(status, ""); 

     // Set output callback 
     callbackStruct.inputProc = playingCallback; 
     callbackStruct.inputProcRefCon = self; 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioUnitProperty_SetRenderCallback, 
             kAudioUnitScope_Global, 
             kOutputBus, 
             &callbackStruct, 
             sizeof(callbackStruct)); 
     XThrowIfError(status, ""); 

     // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own) 
     flag = 0; 
     status = AudioUnitSetProperty(rioUnit, 
             kAudioUnitProperty_ShouldAllocateBuffer, 
             kAudioUnitScope_Output, 
             kInputBus, 
             &flag, 
             sizeof(flag)); 

     // Allocate our own buffers (1 channel, 16 bits per sample, thus 16 bits per frame, thus 2 bytes per frame). 
     // Practice learns the buffers used contain 512 frames, if this changes it will be fixed in processAudio. 
     tempBuffer.mNumberChannels = 1; 
     tempBuffer.mDataByteSize = FRAME_SIZE * 2; 
     tempBuffer.mData = malloc(FRAME_SIZE * 2); 

     XThrowIfError(AudioSessionSetActive(true), "couldn't set audio session active\n"); 

     // Initialise 
     status = AudioUnitInitialize(rioUnit); 
     XThrowIfError(status, ""); 

     status = AudioOutputUnitStart(rioUnit); 
     XThrowIfError(status, ""); 
    } 
    catch (CAXException &e) { 
     NSLog(@"CAXException..."); 
    } 
    catch (...) { 
     fprintf(stderr, "An unknown error occurred\n"); 
    } 
} 

내 된 Speex 인코딩 & 디코드 기능 :

#define FRAME_SIZE 160 
#define COMP_FRAME_SIZE 62 
char* encodeSpeex(spx_int16_t *buffer, UInt32 inSize, int *encodedSize) { 
    char *outputBuffer = (char *)malloc(COMP_FRAME_SIZE); 

    speex_bits_reset(&bits_in); 
    speex_encode_int(enc_state, buffer, &bits_in); 
    *encodedSize = speex_bits_write(&bits_in, outputBuffer, FRAME_SIZE * 2); 
    return outputBuffer; 
} 

short* decodeSpeex(char* buffer, int encodedSize, int decodedSize) { 
    short *outTemp = (short *)calloc(1, FRAME_SIZE * 2); 
    speex_bits_read_from(&bits_out, buffer, encodedSize * FRAME_SIZE * *2); 
    speex_decode_int(dec_state, &bits_out, outTemp); 
    return outTemp; 
} 

그리고 마침내

이 된 Speex 인코딩 & 디코드를 호출하고 함수가 버퍼에 복사하는 특정 콜백으로 재생됩니다.

- (void) processAudio: (AudioBufferList*) bufferList 
{ 
    AudioBuffer sourceBuffer = bufferList->mBuffers[0]; 

    NSLog(@"Origin size: %lu", sourceBuffer.mDataByteSize); 
    int size = 0; 
    char *encodedAudio = encodeSpeex((spx_int16_t*) sourceBuffer.mData, sourceBuffer.mDataByteSize, &size); 
    NSLog(@"Encoded size: %i", size); 
    short* decodedAudio = decodeSpeex(encodedAudio, size, sourceBuffer.mDataByteSize); 
    free(encodedAudio); 

    memcpy(tempBuffer.mData, decodedAudio, FRAME_SIZE * 2); 
    free(decodedAudio);   
} 

누구나 내가 왜 그렇게 열악한 지 알 수있을 것입니다. 웹 사이트의 speex 샘플에 따르면, 그렇게 렌더링되어서는 안됩니다 ...

답변

2

나는이 문제에 대해서도 우연히 발견했습니다. 나는 버퍼가 실제로 올바르게 채워 졌는지 확인하여 문제를 해결했습니다. 그렇지 않으면 빈 데이터가 재생되어 로봇 소리가납니다.

+0

원형 버퍼를 추가했으며 이제는 모두 잘 작동합니다 ... – TheSquad