//
//  AudioConverter.m
//  ContactPoster
//
//  Created by TSYH on 2024/1/25.
//

#import "AudioConverter.h"
#import "lame.h"
#import <AVFoundation/AVFoundation.h>

@implementation AudioConverter
// 转换为mp3
+ (void)convenrtToMp3WithResult:(NSString *)originalPath
                        outPath:(NSString *)outPath
                     completion:(ConvertCompletionHandler)completion {
    
    [[NSFileManager defaultManager] removeItemAtPath:outPath error:nil];
  
    @try {
        int read, write;
        
        FILE *pcm = fopen([originalPath cStringUsingEncoding:1], "rb");//被转换的文件
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([outPath cStringUsingEncoding:1], "wb");//转换后文件的存放位置
        
        const int PCM_SIZE = 8192;
        const int MP3_SIZE = 8192;
        short int pcm_buffer[PCM_SIZE*2];
        unsigned char mp3_buffer[MP3_SIZE];
        
        lame_t lame = lame_init();
        lame_set_num_channels (lame, 2 ); // 设置 1 为单通道，默认为 2 双通道
        lame_set_in_samplerate(lame, 44100);//
        lame_set_brate (lame, 8);
        lame_set_mode (lame, 3);
        lame_set_VBR(lame, vbr_default);
        lame_set_quality (lame, 2); /* 2=high  5 = medium  7=low 音 质 */
        lame_init_params(lame);
        
        do {
            read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
            if (read == 0)
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            else
                write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
            
            fwrite(mp3_buffer, write, 1, mp3);
            
        } while (read != 0);
        
        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    }
    @catch (NSException *exception) {
        // NSLog(@"%@",[exception description]);
        completion(nil, exception.reason);
    }
    @finally {
        completion(outPath, nil);
    }
}

+ (void)convertM4aToWav:(NSString *)originalPath
                outPath:(NSString *)outPath
              compltion:(ConvertCompletionHandler)compltion {
    if ([[NSFileManager defaultManager] fileExistsAtPath:outPath]) {
        NSError *error;
        [[NSFileManager defaultManager] removeItemAtPath:outPath error:&error];
    }
    NSURL *originalUrl = [NSURL fileURLWithPath:originalPath];
    NSURL *outPutUrl = [NSURL fileURLWithPath:outPath];
    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:originalUrl options:nil];    //读取原始文件信息
    NSError *error = nil;
    AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset error:&error];
    if (error) {
        NSLog (@"error: %@", error);
        compltion(nil, error.description);
        return;
    }
    AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput                                                assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks                                                audioSettings: nil];
    if (![assetReader canAddOutput:assetReaderOutput]) {
        NSLog (@"can't add reader output... die!");
        compltion(nil, @"can't add reader output... die!");
        return;
    }
    [assetReader addOutput:assetReaderOutput];
    
    AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:outPutUrl                                                            fileType:AVFileTypeCoreAudioFormat error:&error];
    if (error) {
        NSLog (@"error: %@", error);
        compltion(nil, error.description);
        return;
    }
    AudioChannelLayout channelLayout;
    memset(&channelLayout, 0, sizeof(AudioChannelLayout));
    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
    
    /** 配置音频参数 */
    NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,                                     [NSNumber numberWithFloat:44100.0], AVSampleRateKey,                                     [NSNumber numberWithInt:2], AVNumberOfChannelsKey,                                     [NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,                                     [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,                                     [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,                                     [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,                                    nil];
    AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:outputSettings];
    if ([assetWriter canAddInput:assetWriterInput]) {
        [assetWriter addInput:assetWriterInput];
    } else {
        NSLog (@"can't add asset writer input... die!");
        compltion(nil, @"can't add asset writer input... die!");
        return;
    }
    assetWriterInput.expectsMediaDataInRealTime = NO;
    [assetWriter startWriting];
    [assetReader startReading];
    AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
    CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
    [assetWriter startSessionAtSourceTime:startTime];
    __block UInt64 convertedByteCount = 0;
    dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
    [assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue  usingBlock: ^      {
        while (assetWriterInput.readyForMoreMediaData) {
            CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
            if (nextBuffer) {
                // append buffer
                [assetWriterInput appendSampleBuffer: nextBuffer];
                convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
            } else {
                [assetWriterInput markAsFinished];
                [assetWriter finishWritingWithCompletionHandler:^{
                }];
                [assetReader cancelReading];
                
                NSDictionary *outputFileAttributes = [[NSFileManager defaultManager]                                                        attributesOfItemAtPath:[outPutUrl path]                                                        error:nil];
                NSLog (@"FlyElephant %lld",[outputFileAttributes fileSize]);
                
                compltion(outPath, nil);
                break;
            }
        }
    }];
}

@end
