Browse Source

测评支持调速

Steven 8 months ago
parent
commit
5eb9ca69c8

+ 6 - 0
KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj

@@ -720,6 +720,7 @@
 		BC7CFFD22817FF6D00CAEB21 /* CardDisplayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7CFFD12817FF6D00CAEB21 /* CardDisplayView.xib */; };
 		BC7CFFD5281801A800CAEB21 /* CardBandBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7CFFD4281801A800CAEB21 /* CardBandBodyView.m */; };
 		BC7CFFD7281801B700CAEB21 /* CardBandBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC7CFFD6281801B700CAEB21 /* CardBandBodyView.xib */; };
+		BC7DEC9D2C2D555800154524 /* AudioEnginePlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7DEC9C2C2D555800154524 /* AudioEnginePlayer.m */; };
 		BC7E770C2900DD8E00EB37AF /* HomeDragButton.m in Sources */ = {isa = PBXBuildFile; fileRef = BC7E770A2900DD8E00EB37AF /* HomeDragButton.m */; };
 		BC7FF6A22BEB71B70092E0DE /* client.p12 in Resources */ = {isa = PBXBuildFile; fileRef = BC3BF6242B9EAF1700831494 /* client.p12 */; };
 		BC81F0E529232C11004106AF /* CoursewareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC81F0E429232C11004106AF /* CoursewareViewController.m */; };
@@ -2304,6 +2305,8 @@
 		BC7CFFD3281801A800CAEB21 /* CardBandBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CardBandBodyView.h; sourceTree = "<group>"; };
 		BC7CFFD4281801A800CAEB21 /* CardBandBodyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CardBandBodyView.m; sourceTree = "<group>"; };
 		BC7CFFD6281801B700CAEB21 /* CardBandBodyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CardBandBodyView.xib; sourceTree = "<group>"; };
+		BC7DEC9B2C2D555800154524 /* AudioEnginePlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioEnginePlayer.h; sourceTree = "<group>"; };
+		BC7DEC9C2C2D555800154524 /* AudioEnginePlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioEnginePlayer.m; sourceTree = "<group>"; };
 		BC7E770A2900DD8E00EB37AF /* HomeDragButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeDragButton.m; sourceTree = "<group>"; };
 		BC7E770B2900DD8E00EB37AF /* HomeDragButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeDragButton.h; sourceTree = "<group>"; };
 		BC81F0E329232C11004106AF /* CoursewareViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoursewareViewController.h; sourceTree = "<group>"; };
@@ -5121,6 +5124,8 @@
 		BC3A55782BAA8633002E1616 /* AccompanyWebView */ = {
 			isa = PBXGroup;
 			children = (
+				BC7DEC9B2C2D555800154524 /* AudioEnginePlayer.h */,
+				BC7DEC9C2C2D555800154524 /* AudioEnginePlayer.m */,
 				275FA19E27E7250700CFEA2E /* KSAccompanyWebViewController.h */,
 				275FA19F27E7250700CFEA2E /* KSAccompanyWebViewController.m */,
 				BCC5841428A9FA9D00BAB4CF /* AccompanyLoadingView.h */,
@@ -8250,6 +8255,7 @@
 				BCECE2142B3D5F0800C0D555 /* FeedbackListModel.m in Sources */,
 				BC38C42A2AF900E100ABFCC2 /* KSAudioPlayAnimationView.m in Sources */,
 				BC71DF0E2A89F470003F165E /* KSRateSliderView.m in Sources */,
+				BC7DEC9D2C2D555800154524 /* AudioEnginePlayer.m in Sources */,
 				2779326427E30FD80010E277 /* FSCalendarDelegationProxy.m in Sources */,
 				BC106B852A8F4586000759A9 /* TXLiveMessageCardMessage.m in Sources */,
 				277935DF27E326DA0010E277 /* KSNetTypeManager.m in Sources */,

+ 55 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/AudioEnginePlayer.h

@@ -0,0 +1,55 @@
+//
+//  AudioEnginePlayer.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/6/4.
+//
+
+#import <Foundation/Foundation.h>
+
+@class AudioEnginePlayer;
+
+@protocol AudioEnginePlayerDelegate <NSObject>
+
+- (void)updatePlayProgress:(NSInteger)playTime andTotalTime:(NSInteger)totalTime andProgress:(CGFloat)progress currentInterval:(NSTimeInterval)currentInterval inPlayer:(AudioEnginePlayer *_Nonnull)player;
+
+@optional
+
+- (void)enginePlayFinished:(AudioEnginePlayer *_Nonnull)player;
+
+- (void)enginePlayerIsReadyPlay:(AudioEnginePlayer *_Nonnull)player;
+
+- (void)enginePlayerDidError:(AudioEnginePlayer *_Nonnull)player error:(NSError *_Nonnull)error;
+
+@end
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface AudioEnginePlayer : NSObject
+
+@property (nonatomic, weak) id <AudioEnginePlayerDelegate>delegate;
+
+@property (nonatomic, assign) float rate; // 播放速度
+
+@property (nonatomic, assign) BOOL isReady;
+
+@property (nonatomic, assign) BOOL isPlaying;
+
+@property (nonatomic, assign) BOOL isMute; // 是否禁音
+
+- (void)prepareNativeSongWithUrl:(NSURL *)nativeMusicUrl;
+
+- (void)startPlay;
+
+- (void)stopPlay;
+
+- (void)freePlayer;
+
+// 从某个位置开始播放 ms
+- (void)seekToTimePlay:(NSInteger)time;
+
+- (NSTimeInterval)getCurrentPlayTime;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 308 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/AudioEnginePlayer.m

@@ -0,0 +1,308 @@
+//
+//  AudioEnginePlayer.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/6/4.
+//
+
+#import "AudioEnginePlayer.h"
+#import <AVFoundation/AVFoundation.h>
+
+@interface AudioEnginePlayer ()
+/** 定时器 */
+@property (nonatomic, strong) NSTimer *timer;
+
+@property (nonatomic, strong) AVAudioEngine *audioEngine;
+
+@property (nonatomic, strong) AVAudioPlayerNode *bgPlayer;
+
+@property (nonatomic, strong) AVAudioUnitTimePitch *timePitchUnit;
+
+@property (nonatomic, strong) AVAudioFile *audioFile;
+
+@property (nonatomic, strong) AVAudioFormat *audioFormat;
+
+@property (nonatomic, assign) NSTimeInterval totalDuration;
+
+@property (nonatomic, assign) AVAudioFramePosition startPosition; // 开始位置
+
+@end
+
+@implementation AudioEnginePlayer
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+    }
+    return self;
+}
+
+
+- (void)setupAudioSession {
+    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
+    
+    @try {
+        NSError *err = nil;
+        AVAudioSessionCategory category = AVAudioSessionCategoryPlayAndRecord;
+        if (@available(iOS 10.0, *)) {
+            [audioSession setCategory:category mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionAllowBluetoothA2DP|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
+        }
+        else {
+            [audioSession setCategory:category withOptions:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&err];
+        }
+        [audioSession setActive:YES error:&err];
+    } @catch (NSException *exception) {
+        NSLog(@"----- exception --- %@", exception);
+    } @finally {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:audioSession];
+    }
+}
+
+// 打断处理
+- (void)handleInterruption:(NSNotification *)notification {
+    
+    NSDictionary *info = notification.userInfo;
+    AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
+    if (type == AVAudioSessionInterruptionTypeBegan) {
+        //Handle InterruptionBegan
+        if (self.delegate && [self.delegate respondsToSelector:@selector(enginePlayerDidError:error:)]) {
+            NSError *error = [[NSError alloc] initWithDomain:NSCocoaErrorDomain code:99999 userInfo:@{@"errorDesc" : @"播放被打断"}];
+            [self.delegate enginePlayerDidError:self error:error];
+        }
+    }
+    else {
+        AVAudioSessionInterruptionOptions options = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
+        if (options == AVAudioSessionInterruptionOptionShouldResume) {
+            //Handle Resume
+            
+            [[AVAudioSession sharedInstance] setActive:YES error:nil];
+//            [self startEngine];
+        }
+    }
+}
+
+
+- (void)configEngine {
+    [self setupAudioSession];
+    self.audioEngine = [[AVAudioEngine alloc] init];
+    self.bgPlayer = [[AVAudioPlayerNode alloc] init];
+    
+    // attach node
+    [self.audioEngine attachNode:self.bgPlayer];
+    [self.audioEngine attachNode:self.timePitchUnit];
+}
+
+- (void)loadAudioFile:(NSURL *)audioUrl {
+    NSError *error = nil;
+    @try {
+        self.audioFile = [[AVAudioFile alloc] initForReading:audioUrl error:&error];
+        self.audioFormat = self.audioFile.processingFormat;
+        self.totalDuration = (AVAudioFramePosition)self.audioFile.length * 1000.0 / self.audioFormat.sampleRate;
+    } @catch (NSException *exception) {
+        self.audioFile = nil;
+        self.audioFormat = nil;
+    } @finally {
+        if (error) {
+            // 错误回调
+            if (self.delegate && [self.delegate respondsToSelector:@selector(enginePlayerDidError:error:)]) {
+                [self.delegate enginePlayerDidError:self error:error];
+            }
+        }
+    }
+    
+}
+
+- (void)prepareNativeSongWithUrl:(NSURL *)nativeMusicUrl {
+    [self loadAudioFile:nativeMusicUrl];
+    
+    if (self.audioFile && self.audioFormat) {
+        [self configEngine];
+        // connect node
+        [self.audioEngine connect:self.bgPlayer to:self.timePitchUnit format:self.audioFormat];
+        [self.audioEngine connect:self.timePitchUnit to:self.audioEngine.mainMixerNode format:self.audioFormat];
+        
+        [self.audioEngine prepare];
+        
+        [self startEngine];
+        if (self.audioEngine && self.audioEngine.isRunning) {
+            if (self.delegate && [self.delegate respondsToSelector:@selector(enginePlayerIsReadyPlay:)]) {
+                [self.delegate enginePlayerIsReadyPlay:self];
+            }
+        }
+    }
+        
+}
+
+- (void)startEngine {
+    // 启动engine
+    NSError *error = nil;
+    @try {
+        [self.audioEngine startAndReturnError:&error];
+    } @catch (NSException *exception) {
+        
+    } @finally {
+        if (error) {
+            self.audioEngine = nil;
+            // 错误回调
+            if (self.delegate && [self.delegate respondsToSelector:@selector(enginePlayerDidError:error:)]) {
+                [self.delegate enginePlayerDidError:self error:error];
+            }
+        }
+    }
+}
+
+- (void)startPlay {
+    if (self.audioEngine.isRunning == NO) {
+        [self startEngine];
+    }
+    if (self.audioEngine.isRunning) {
+        [self.bgPlayer play];
+        self.isPlaying = YES;
+        [self startTimer];
+    }
+}
+
+- (void)stopPlay {
+    [self stopTimer];
+    self.isPlaying = NO;
+    if (self.bgPlayer.isPlaying) {
+        [self.bgPlayer stop];
+    }
+}
+
+// 从某个位置开始播放 ms
+- (void)seekToTimePlay:(NSInteger)time {
+    if (self.audioEngine.isRunning == NO) {
+        [self startEngine];
+    }
+    if (self.audioEngine.isRunning) {
+        [self playAudioWithStartTime:time];
+    }
+}
+
+- (void)playAudioWithStartTime:(NSTimeInterval)startTime {
+    
+    if (self.audioEngine.isRunning == NO) {
+        [self startEngine];
+    }
+    if (self.bgPlayer.isPlaying) {
+        [self.bgPlayer stop];
+    }
+    
+    AVAudioFramePosition startPosition = startTime / 1000.0 * self.audioFormat.sampleRate;
+    self.startPosition = startPosition;
+    AVAudioFrameCount frameCount = (AVAudioFrameCount)(self.audioFile.length - startPosition);
+    if (frameCount > 0) {
+        [self.bgPlayer scheduleSegment:self.audioFile startingFrame:startPosition frameCount:frameCount atTime:nil completionHandler:^{
+            
+        }];
+        
+        
+        if (self.audioEngine.isRunning) {
+            [self.bgPlayer play];
+            [self startTimer];
+            self.isPlaying = YES;
+        }
+    }
+    else { // 已无后续片段
+        // 播放完成
+        if (self.delegate && [self.delegate respondsToSelector:@selector(enginePlayFinished:)]) {
+            [self.delegate enginePlayFinished:self];
+        }
+    }
+}
+
+
+- (void)freePlayer {
+    
+    if (self.isPlaying) {
+        [self stopPlay];
+    }
+}
+
+
+- (void)startTimer {
+    [self.timer setFireDate:[NSDate distantPast]];
+}
+
+- (void)stopTimer {
+    
+    [self.timer setFireDate:[NSDate distantFuture]];//暂停计时器
+}
+
+
+#pragma mark ----- lazying
+- (NSTimer *)timer{
+    
+    if (!_timer) {
+        MJWeakSelf;
+        _timer = [NSTimer scheduledTimerWithTimeInterval:0.01 repeats:YES block:^(NSTimer * _Nonnull timer) {
+            [weakSelf timeFunction];
+        }];
+        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
+        [_timer setFireDate:[NSDate distantFuture]];
+    }
+    return _timer;
+}
+
+- (void)timeFunction {
+    NSTimeInterval currentTime = [self getCurrentPlayTime];
+    float progress = currentTime / self.totalDuration;
+    NSDate *date = [NSDate date];
+    NSTimeInterval inteveral = [date timeIntervalSince1970];
+    if (self.delegate && [self.delegate respondsToSelector:@selector(updatePlayProgress:andTotalTime:andProgress:currentInterval:inPlayer:)]) {
+        [self.delegate updatePlayProgress:currentTime andTotalTime:self.totalDuration andProgress:progress currentInterval:inteveral*1000 inPlayer:self];
+    }
+}
+
+- (void)setRate:(float)rate {
+    _rate = rate;
+    float speed = rate;
+    if (self.timePitchUnit) {
+        self.timePitchUnit.rate = speed;
+    }
+}
+
+- (void)setIsMute:(BOOL)isMute {
+    _isMute = isMute;
+    if (self.bgPlayer) {
+        self.bgPlayer.volume = isMute ? 0.0 : 1.0;
+    }
+}
+
+- (AVAudioUnitTimePitch *)timePitchUnit {
+    if (!_timePitchUnit) {
+        _timePitchUnit = [[AVAudioUnitTimePitch alloc] init];
+    }
+    return _timePitchUnit;
+}
+
+- (NSTimeInterval)getCurrentPlayTime {
+    AVAudioTime *nodeTime = [self.bgPlayer lastRenderTime];
+    if (nodeTime.sampleTimeValid && nodeTime.hostTimeValid && nodeTime && self.audioFile) {
+        
+        AVAudioTime *playerTime = [self.bgPlayer playerTimeForNodeTime:nodeTime];
+        double sampleRate = [playerTime sampleRate];
+        double elapsedSamples = (double)[playerTime sampleTime] + self.startPosition;
+        if (elapsedSamples <= 0) {
+            elapsedSamples = 0;
+        }
+        NSTimeInterval currentTime = elapsedSamples / sampleRate;
+        NSLog(@"当前时间----- %f",currentTime*1000);
+        return currentTime*1000;
+    }
+    else {
+        return 0;
+    }
+}
+
+- (void)dealloc {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    NSLog(@"---------AudioEnginePlayer dealloc ");
+    if (_timer) {
+        [_timer invalidate];
+        _timer = nil;
+    }
+}
+
+@end

+ 131 - 140
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/KSAccompanyWebViewController.m

@@ -14,7 +14,7 @@
 #import <CloudAccompanyLibrary/KSVideoRecordManager.h>  // 视频录制
 #import <CloudAccompanyLibrary/KSCloudBeatView.h>     // 节拍器
 #import <KSToolLibrary/MidiPlayerEngine.h>    // midi 播放
-#import <CloudAccompanyLibrary/kSNewPlayer.h>         // mp3 播放器
+//#import <CloudAccompanyLibrary/kSNewPlayer.h>         // mp3 播放器
 
 #import "AccompanyLoadingView.h"
 
@@ -27,7 +27,9 @@
 #import <KSTunerLibrary/KSTunerLibrary-Swift.h>
 #import "KSLogManager.h"
 
-@interface KSAccompanyWebViewController ()<KSAQRecordManagerDelegate,KSAudioSessionManagerDelegate,PlayerEngineDelegate,TunerDelegate,kSNewPlayerManagerDelegate>
+#import "AudioEnginePlayer.h"
+
+@interface KSAccompanyWebViewController ()<KSAQRecordManagerDelegate,KSAudioSessionManagerDelegate,PlayerEngineDelegate,TunerDelegate,AudioEnginePlayerDelegate>
 
 @property (nonatomic, strong) KSAudioSessionManager *audioSessionManager;
 
@@ -84,12 +86,12 @@
 // 延迟校准开始时发送 AdjustStart消息标识
 @property (nonatomic, assign) BOOL isDelayCheckStart;
 // 检测延迟播放器
-@property (nonatomic, strong) kSNewPlayer *dingPlayer;
-
-@property (nonatomic, strong) kSNewPlayer *dongPlayer;
+@property (nonatomic, strong) AudioEnginePlayer *delayCheckPlayer;
 
 // 音频播放器
-@property (nonatomic, strong) kSNewPlayer *musicPlayer;
+@property (nonatomic, strong) AudioEnginePlayer *musicPlayer;
+
+@property (nonatomic, assign) float musicSpeed; //播放速度
 // 录音开始时间
 @property (nonatomic, assign) NSTimeInterval recordStartTime;
 // 播放开始时间
@@ -97,9 +99,7 @@
 // 播放延迟
 @property (nonatomic, assign) NSInteger offsetTime;
 
-
-@property (nonatomic, assign) BOOL dingPlayerReady;
-@property (nonatomic, assign) BOOL dongPlayerReady;
+@property (nonatomic, assign) BOOL checkPlayerReady;
 
 @property (nonatomic, assign) BOOL musicPlayerReady;
 
@@ -109,9 +109,7 @@
 
 @property (nonatomic, assign) NSInteger checkIndex;
 
-@property (nonatomic, assign) NSInteger firstFrequence;
-
-@property (nonatomic, assign) NSInteger secondFrequence;
+@property (nonatomic, assign) NSInteger checkPrequence;
 
 @property (nonatomic, strong) NSURL *bgAudioUrl;
 
@@ -123,6 +121,8 @@
 
 @property (nonatomic, assign) NSInteger musicStartTime;  // 开始播放的时间
 
+@property (nonatomic, assign) BOOL hasRecordMusicOffset; // 是否记录了播放延迟
+
 @end
 
 @implementation KSAccompanyWebViewController
@@ -165,10 +165,8 @@
 
 - (void)resetPlayerConfig {
     [self freeMp3Player]; // 若之前有播放器,剔除
-    self.firstFrequence = 800;
-    self.secondFrequence = 800;
-    self.dingPlayerReady = NO;
-    self.dongPlayerReady = NO;
+    self.checkPrequence = 800;
+    self.checkPlayerReady = NO;
     self.musicPlayerReady = NO;
     self.recordStartTime = 0;
     self.playerStartTime = 0;
@@ -182,11 +180,13 @@
         NSURL *fileUrl = [[NSURL alloc] initFileURLWithPath:filePath];
         if ([self checkSongHasSaveAccompanyWithSongUrl:musicUrl]) {
             [self configVideoRecord:fileUrl];
+            [self initMusicPlayer:fileUrl];
         }
         else {
             MJWeakSelf;
             [self downloadUrl:musicUrl success:^{
                 [weakSelf configVideoRecord:fileUrl];
+                [weakSelf initMusicPlayer:fileUrl];
             } faliure:^{
                 
             }];
@@ -197,57 +197,57 @@
     }
 }
 
-- (void)initMp3Player:(NSString *)musicUrl checkUrl:(NSString *)checkUrl {
-    [self resetPlayerConfig];
-    self.accompanyUrl = musicUrl;
-    [self.musicPlayer preparePlaySongWithUrl:musicUrl];
-    [self.dingPlayer preparePlaySongWithUrl:checkUrl];
-    [self.dongPlayer preparePlaySongWithUrl:checkUrl];
+- (void)initMusicPlayer:(NSURL *)musicUrl {
     
-    [self prepareMusic];
+    [self.musicPlayer prepareNativeSongWithUrl:musicUrl];
+}
+
+- (void)downloadCheckMusic:(NSString *)checkMusicUrl {
+    if (![NSString isEmptyString:checkMusicUrl]) {
+        NSString *fileName = [checkMusicUrl getUrlFileName];
+        NSString *filePath = [self getAccompanyFilePathWithName:fileName];
+        NSURL *fileUrl = [[NSURL alloc] initFileURLWithPath:filePath];
+        if ([self checkSongHasSaveAccompanyWithSongUrl:checkMusicUrl]) {
+            [self initCheckPlayer:fileUrl];
+        }
+        else {
+            MJWeakSelf;
+            [self downloadUrl:checkMusicUrl success:^{
+                [weakSelf initCheckPlayer:fileUrl];
+            } faliure:^{
+                
+            }];
+        }
+    }
 }
 
-- (void)prepareMusic {
+- (void)initCheckPlayer:(NSURL *)checkUrl {
+    [self.delayCheckPlayer prepareNativeSongWithUrl:checkUrl];
+}
+
+- (void)initMp3Player:(NSString *)musicUrl checkUrl:(NSString *)checkUrl {
     
-    self.dingPlayer.isMute = YES;
-    [self.dingPlayer startPlayNoSeek];
-    self.dongPlayer.isMute = YES;
-    [self.dongPlayer startPlayNoSeek];
-    self.musicPlayer.isMute = YES;
-    [self.musicPlayer startPlayNoSeek];
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        [self.musicPlayer puasePlay];
-        self.musicPlayer.isMute = NO;
-        [self.dingPlayer puasePlay];
-        self.dingPlayer.isMute = NO;
-        [self.dongPlayer puasePlay];
-        self.dongPlayer.isMute = NO;
-        [self configPlayerDelegate];
-    });
+    [self resetPlayerConfig];
+    self.accompanyUrl = musicUrl;
+    [self downloadCheckMusic:checkUrl];
 }
 
 -  (void)freeMp3Player {
-    if (_dingPlayer) {
-        [self.dingPlayer freePlayer];
-    }
-    if (_dongPlayer) {
-        [self.dongPlayer freePlayer];
-    }
-    if (_musicPlayer) {
-        [self.musicPlayer freePlayer];
+    if (_delayCheckPlayer) {
+        [self.delayCheckPlayer freePlayer];
     }
+     if (_musicPlayer) {
+          [self.musicPlayer freePlayer];
+     }
 }
 
 - (void)stopMp3Player {
-    if (_dingPlayer) {
-        [self.dingPlayer puasePlay];
-    }
-    if (_dongPlayer) {
-        [self.dongPlayer puasePlay];
-    }
-    if (_musicPlayer) {
-        [self.musicPlayer puasePlay];
+    if (_delayCheckPlayer) {
+        [self.delayCheckPlayer stopPlay];
     }
+     if (_musicPlayer) {
+          [self.musicPlayer stopPlay];
+     }
 }
 
 
@@ -266,7 +266,9 @@
     if ([type isEqualToString:@"DELAY_CHECK"] && [commond isEqualToString:@"recordEnd"]) {
         NSDictionary *body = [result ks_dictionaryValueForKey:@"body"];
         NSTimeInterval micDelay = [body ks_doubleValueForKey:@"firstNoteDelayDuration"] - self.offsetTime;
-        [self.delayArray addObject:[NSNumber numberWithDouble:micDelay]];
+        if (micDelay > 0) {
+            [self.delayArray addObject:[NSNumber numberWithDouble:micDelay]];
+        }
     }
 }
 
@@ -554,6 +556,12 @@
                 else {
                     self.muteAccompany = NO;
                 }
+                if ([[content allKeys] containsObject:@"speedRate"]) { // 播放速度
+                    self.musicSpeed = [content ks_floatValueForKey:@"speedRate"];
+                }
+                else {
+                    self.musicSpeed = 1.0f;
+                }
                 if (self->_videoRecordManager) {
                     [self.videoRecordManager clearVideoFile];
                 }
@@ -665,6 +673,12 @@
                         mergeView.recordId = [content ks_stringValueForKey:@"recordId"];
                         mergeView.songName = [content ks_stringValueForKey:@"title"];
                         mergeView.coverImage = [content ks_stringValueForKey:@"coverImg"];
+                        //                        if ([[content allKeys] containsObject:@"speedRate"]) {
+                        //                            mergeView.musicSpeed = [content ks_floatValueForKey:@"speedRate"];
+                        //                        }
+                        //                        else {
+                        //                            mergeView.musicSpeed = 1.0f;
+                        //                        }
                         MJWeakSelf;
                         NSInteger micDelay = [UserDefaultObjectForKey(@"micDelay") integerValue];
                         NSInteger defaultDelay = self.offsetTime + micDelay;
@@ -1273,18 +1287,14 @@
 #pragma mark ------- 评测app播放
 
 - (void)recordDidStart:(NSTimeInterval)time { // ms
+    self.hasRecordMusicOffset = NO;
     self.recordStartTime = time;
     if (self.isDelayCheckStart) {
         NSLog(@"---- delay - record did start %f", time);
         // 播放音频
         // 播放校音音频
         dispatch_main_sync_safe(^{
-            if (self.checkIndex % 2 == 0) {
-                [self.dongPlayer startPlay];
-            }
-            else {
-                [self.dingPlayer startPlay];
-            }
+            [self.delayCheckPlayer seekToTimePlay:0];
         });
     }
     else if (self.isCompareStart) {
@@ -1292,7 +1302,8 @@
         // 播放伴奏
         dispatch_main_sync_safe(^{
             self.musicPlayer.isMute = self.muteAccompany;
-            [self.musicPlayer startPlay];
+            self.musicPlayer.rate = self.musicSpeed;
+            // 进度跳转
             [self.musicPlayer seekToTimePlay:self.musicStartTime];
         });
     }
@@ -1335,13 +1346,7 @@
         NSLog(@"--------- send delay check start message");
         _isDelayCheckStart = NO;
         NSString *checkStartMessage = @"recordStart";
-        NSInteger frequence = 0.0f;
-        if (self.checkIndex % 2 == 0) {
-            frequence = self.secondFrequence;
-        }
-        else {
-            frequence = self.firstFrequence;
-        }
+        NSInteger frequence = self.checkPrequence;
         NSDictionary *parm = @{@"HZ" : @(frequence)};
         NSString *startString = [self configDataCommond:checkStartMessage body:parm type:@"DELAY_CHECK"];
         [self sendDataToSocketService:startString];
@@ -1678,97 +1683,78 @@
     return hasSaveFile;
 }
 
-#pragma mark ---- player
-- (void)configPlayerDelegate {
-    self.dingPlayer.delegate = self;
-    self.dongPlayer.delegate = self;
-    self.musicPlayer.delegate = self;
-}
-- (kSNewPlayer *)dingPlayer {
-    if (!_dingPlayer) {
-        _dingPlayer = [[kSNewPlayer alloc] init];
+#pragma mark ------- Audio Engine player
+- (AudioEnginePlayer *)delayCheckPlayer {
+    if (!_delayCheckPlayer) {
+        _delayCheckPlayer = [[AudioEnginePlayer alloc] init];
+        _delayCheckPlayer.delegate = self;
     }
-    return _dingPlayer;
+    return _delayCheckPlayer;
 }
-
-- (kSNewPlayer *)dongPlayer {
-    if (!_dongPlayer) {
-        _dongPlayer = [[kSNewPlayer alloc] init];
+- (AudioEnginePlayer *)musicPlayer {
+    if (!_musicPlayer) {
+        _musicPlayer = [[AudioEnginePlayer alloc] init];
+        _musicPlayer.delegate = self;
     }
-    return _dongPlayer;
+    return _musicPlayer;
 }
 
-- (kSNewPlayer *)musicPlayer {
-    if (!_musicPlayer) {
-        _musicPlayer = [[kSNewPlayer alloc] init];
+#pragma mark ---- Audio Engine player delegate
+- (void)enginePlayerIsReadyPlay:(AudioEnginePlayer *)player {
+    if (player == self.delayCheckPlayer) {
+        self.checkPlayerReady = YES;
+    }
+    else if (player == self.musicPlayer) {
+        self.musicPlayerReady = YES;
+    }
+    // 如果都准备好
+    if (self.musicPlayerReady && self.checkPlayerReady) {
+         [self sendPlayerReadyMsg];
     }
-    return _musicPlayer;
 }
 
-#pragma mark ---- new player delegate
-- (void)getSongCurrentTime:(NSInteger)currentTime andTotalTime:(NSInteger)totalTime andProgress:(CGFloat)progress currentInterval:(NSTimeInterval)currentInterval playTime:(NSTimeInterval)playTime inPlayer:(kSNewPlayer *)player {
-    
-    if (player == self.dingPlayer || player == self.dongPlayer) {
-        if (playTime >= 300 && playTime < 310 && self.recordStartTime > 0) {
-            NSLog(@" --- check player start play time %f", currentInterval*1000 - playTime);
-            self.playerStartTime = currentInterval*1000 - playTime;
+// 播放进度
+- (void)updatePlayProgress:(NSInteger)playTime andTotalTime:(NSInteger)totalTime andProgress:(CGFloat)progress currentInterval:(NSTimeInterval)currentInterval inPlayer:(AudioEnginePlayer *)player {
+    if (player == self.delayCheckPlayer) {
+        if (playTime >= 300 && self.recordStartTime > 0 && self.hasRecordMusicOffset == NO) {
+            self.hasRecordMusicOffset = YES;
+            NSLog(@" --- check player start play time %f", currentInterval - playTime);
+            self.playerStartTime = currentInterval - playTime;
             self.offsetTime = self.playerStartTime - self.recordStartTime;
             NSLog(@"--------- check player offset time -- %zd", self.offsetTime);
         }
     }
-    
-    if (playTime >= self.musicStartTime + 300 && playTime < self.musicStartTime + 310 && player == self.musicPlayer) {
+    // 如果未记录延迟
+    if (playTime >= (self.musicStartTime + 300) && player == self.musicPlayer && self.hasRecordMusicOffset == NO) {
         if (self.recordStartTime > 0) {
-            NSInteger newPlayTime = playTime - self.musicStartTime; // 选段
-            NSLog(@" --- music player start play time %f", currentInterval*1000 - newPlayTime);
-            self.playerStartTime = currentInterval*1000 - newPlayTime;
+            self.hasRecordMusicOffset = YES;
+            NSInteger newPlayTime = (playTime - self.musicStartTime) / player.rate; // 选段
+            NSLog(@" --- music player start play time %f", currentInterval - newPlayTime);
+            self.playerStartTime = currentInterval - newPlayTime;
             self.offsetTime = self.playerStartTime - self.recordStartTime;
             NSLog(@"--------- music play offset time -- %zd", self.offsetTime);
             [self sendOffsetTimeToService];
         }
         NSLog(@"------- record start time %f", self.recordStartTime);
-    }
+   }
     
     // 回调进度
     if (player == self.musicPlayer) {
-        //          NSLog(@"------ music play progress - %f", progress);
-        // 回调进度
-        NSDictionary *parm = @{
-            @"api" : @"playProgress",
-            @"content" : @{@"currentTime" : [NSNumber numberWithInteger:currentTime],
-                           @"totalDuration" : [NSNumber numberWithInteger:totalTime],
-            }
-        };
-        //          NSLog(@" -----music play progress  %@---- ", parm);
-        [self postMessage:parm];
-    }
-}
-
-
-- (void)sendPlayerReadyMsg {
-    if (self.playerParm) {
-        [self postMessage:self.playerParm];
-    }
-}
-
-- (void)playerIsReadyPlay:(kSNewPlayer *)player {
-    if (player == self.musicPlayer) {
-        self.musicPlayerReady = YES;
-    }
-    else if (player == self.dingPlayer) {
-        self.dingPlayerReady = YES;
-        
-    }
-    else if (player == self.dongPlayer) {
-        self.dongPlayerReady = YES;
-    }
-    // 如果都准备好
-    if (self.musicPlayerReady && self.dingPlayerReady && self.dongPlayerReady) {
-        [self sendPlayerReadyMsg];
+//          NSLog(@"------ music play progress - %f", progress);
+         // 回调进度
+         NSDictionary *parm = @{
+              @"api" : @"playProgress",
+              @"content" : @{@"currentTime" : [NSNumber numberWithInteger:playTime],
+                             @"totalDuration" : [NSNumber numberWithInteger:totalTime],
+              }
+         };
+          NSLog(@" -----music play progress  %@---- ", parm);
+         [self postMessage:parm];
     }
+    
 }
-
-- (void)playerDidError:(kSNewPlayer *)player {
+// 错误
+- (void)enginePlayerDidError:(AudioEnginePlayer *)player error:(NSError *)error {
     [self stopRecordService];
     [self stopMp3Player]; // 停止播放
     // 播放出现问题
@@ -1777,7 +1763,6 @@
     };
     [self postMessage:postParm];
     
-    NSError *error = player.player.error;
     if (error) {
         NSLog(@"-- error desc - %@", error.description);
         NSMutableDictionary *parm = [NSMutableDictionary dictionary];
@@ -1796,10 +1781,16 @@
         } faliure:^(NSError * _Nonnull error) {
             
         }];
-        
     }
 }
 
+
+- (void)sendPlayerReadyMsg {
+     if (self.playerParm) {
+          [self postMessage:self.playerParm];
+     }
+}
+
 - (NSMutableArray *)delayArray {
     if (!_delayArray) {
         _delayArray = [NSMutableArray array];