Question

So I have the current code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //for recording audio
    _stopButton.enabled = NO;
    _playButton.hidden = true;

    NSArray *dirPaths;
    NSString *docsDir;

    dirPaths = NSSearchPathForDirectoriesInDomains(
                                                   NSDocumentDirectory, NSUserDomainMask, YES);
    docsDir = dirPaths[0];

    NSString *soundFilePath = [docsDir
                               stringByAppendingPathComponent:@"recording.caf"];

    NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];

    NSDictionary *recordSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
                                    [NSNumber numberWithFloat:44100.0], AVSampleRateKey,
                                    [NSNumber numberWithInt:1], AVNumberOfChannelsKey,
                                    [NSNumber numberWithInt:AVAudioQualityHigh], AVSampleRateConverterAudioQualityKey,
                                    [NSNumber numberWithInt:128000], AVEncoderBitRateKey,
                                    [NSNumber numberWithInt:16], AVEncoderBitDepthHintKey,
                                    nil];

    NSError *error = nil;

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
                        error:nil];

    _audioRecorder = [[AVAudioRecorder alloc]
                      initWithURL:soundFileURL
                      settings:recordSettings
                      error:&error];

    if (error)
    {
        NSLog(@"error: %@", [error localizedDescription]);
    } else {
        [_audioRecorder prepareToRecord];
    }
    //----------------------------
    //end

}

And the player:

- (IBAction)playAudio:(id)sender {
    [_playButton setEnabled:NO];
    if (!_audioRecorder.recording)
    {
        _stopButton.enabled = YES;
        _recordButton.enabled = NO;

        NSError *error;

        _audioPlayer = [[AVAudioPlayer alloc]
                        initWithContentsOfURL:_audioRecorder.url
                        error:&error];
        _audioPlayer.volume = 5;
        _audioPlayer.delegate = self;

        if (error)
            NSLog(@"Error: %@",
                  [error localizedDescription]);
        else
            [_audioPlayer play];
    }else{
        NSLog(@"errormax");
    }
}

I have the _audioPlayer.volume at 5 because any lower you can barely here it. But it peeks and sounds extremely distorted at that volume. Why can it not sound like "Voice Memos" where it plays it back at a reasonable volume without it distorting?

What are the best quality settings for this?

Was it helpful?

Solution

I personaly prefer PCM encoding, I've had better quality using it.

try:

NSDictionary *recordSettings = 
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:2], AVNumberOfChannelsKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
nil];

or to make it more readable:

NSDictionary * recordSetting;
recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
[recordSetting setValue :[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];

Adjust your function like this:

- (IBAction)playAudio:(id)sender {
    [_playButton setEnabled:NO];
    if (!_audioRecorder.recording)
    {
        _stopButton.enabled = YES;
        _recordButton.enabled = NO;

        //force the session to play to come out of speakers!
        UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
        AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
        UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
        AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);

        NSError *error;

        _audioPlayer = [[AVAudioPlayer alloc]
                        initWithContentsOfURL:_audioRecorder.url
                        error:&error];
        _audioPlayer.delegate = self;
        [_audioPlayer prepareToPlay];

        if (error)
            NSLog(@"Error: %@",
                  [error localizedDescription]);
        else
            [_audioPlayer play];
    }else{
        NSLog(@"errormax");
    }
}

OTHER TIPS

It's because of audio session category "AVAudioSessionCategoryPlayAndRecord". It always play audio in receiver unless you explicitly change the overrideOutputAudioPort. You may have to add listener for AVAudioSessionRouteChangeNotification to change the category based on your out put. Anyway why this headache, just use AVAudioSessionCategoryRecord before you start recording and AVAudioSessionCategoryPlayback before you start player.

//Player

 newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];

NSError *setCategoryError = nil;
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];

//Recorder

newRecorder = [[AVAudioRecorder alloc]initWithURL:fileURL settings:recordSettings error:&error];

NSError *setCategoryError = nil;
[audioSession setCategory: AVAudioSessionCategoryRecord error: &setCategoryError];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top