How to send high-quality voice on iOS

1. Set audio recording settings

NSDictionary *recordSettings = @{
    AVFormatIDKey : @(kAudioFormatMPEG4AAC_HE),
    AVNumberOfChannelsKey : @1,
    AVEncoderBitRateKey : @(32000)
};

2. Generate temporary voice file path

NSURL *recordTempFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() 
                                      stringByAppendingPathComponent:@"HQTempAC.m4a"]];

3. Record high-quality voice message

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
[audioSession setActive:YES error:nil];

NSError *error = nil;
if (self.recorder == nil) {
    AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:recordTempFileURL 
                                                          settings:recordSettings error:&error];
    recorder.delegate = self;
    recorder.meteringEnabled = YES;
}

// Prepare to record
[recorder prepareToRecord];
// Start recording
[recorder record];

4. Publish voice message after recording

if (!recorder.url) { return; }

NSURL *url = [[NSURL alloc] initWithString:recorder.url.absoluteString];

// Current recording duration
NSTimeInterval audioLength = recorder.currentTime;

// Stop recording
[recorder stop];

// Recording file data
NSData *currentRecordData = [NSData dataWithContentsOfURL:url];

recorder = nil;

// Move voice from temporary path to permanent path
NSString *path = [self getHQVoiceMessageCachePath];
[currentRecordData writeToFile:path atomically:YES];

// Construct voice message content
NCVoiceMessage *hqVoiceMsg = [NCVoiceMessage messageWithPath:path duration:(NSInteger)audioLength];

// Construct message body
NCChannelIdentifier *identifier = [[NCChannelIdentifier alloc] initWithChannelType:NCChannelTypeDirect
                                                                          channelId:@"2"];
NCMessage *message = [[NCMessage alloc] initWithIdentifier:identifier content:hqVoiceMsg];

// Build send params
NCSendMessageParams *params = [[NCSendMessageParams alloc] initWithMessage:message];

// Send media message
NCDirectChannel *channel = [[NCDirectChannel alloc] initWithChannelId:@"2"];
[channel sendMediaMessageWithParams:params
                    attachedHandler:^(NCMessage * _Nullable localMessage) {}
                    progressHandler:^(NSInteger progress, NCMessage * _Nullable progressMessage) {}
                  completionHandler:^(NCMessage * _Nullable sentMessage, NCError * _Nullable error) {
    if (error) {
        NSLog(@"--- Message sending failed %@", error);
    } else {
        NSLog(@"--- Message sent successfully");
    }
}
                      cancelHandler:^(NCMessage * _Nullable cancelMessage) {}];


// Local path for voice message
- (NSString *)getHQVoiceMessageCachePath {
    long long currentTime = (long long)([[NSDate date] timeIntervalSince1970] * 1000);

    // Replace RCUtilities with standard iOS cache directory
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    NSString *userId = [NCEngine getCurrentUserId] ?: @"unknown";
    path = [path stringByAppendingFormat:@"/%@/NCHQVoiceCache", userId];

    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:path
                                  withIntermediateDirectories:YES
                                                   attributes:nil
                                                        error:nil];
    }

    NSString *fileName = [NSString stringWithFormat:@"Voice_%lld.m4a", currentTime];
    path = [path stringByAppendingPathComponent:fileName];

    NSLog(@"--- path %@", path);

    return path;
}