KSAccompanyWebViewController.m 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709
  1. //
  2. // KSAccompanyWebViewController.m
  3. // KulexiuForTeacher
  4. //
  5. // Created by Kyle on 2022/3/20.
  6. //
  7. #import "KSAccompanyWebViewController.h"
  8. #import "RecordCheckManager.h"
  9. #import "KSAQRecordManager.h"
  10. #import "KSWebSocketManager.h"
  11. #import "KSVideoRecordManager.h"
  12. #import "KSWebNavView.h"
  13. #import "KSAudioSessionManager.h"
  14. #import "KSCloudBeatView.h"
  15. #import "MidiPlayerEngine.h"
  16. #import "AccompanyLoadingView.h"
  17. #import "KSPremissionAlert.h"
  18. #define KSMidiSongFileKey (@"KSDownloadMidiSong")
  19. #import "KulexiuForStudent-swift.h"
  20. #import "kSNewPlayer.h"
  21. #import "KSMediaEditor.h"
  22. #import "KSMediaMergeView.h"
  23. @interface KSAccompanyWebViewController ()<KSAQRecordManagerDelegate,KSAudioSessionManagerDelegate,PlayerEngineDelegate,TunerDelegate,kSNewPlayerManagerDelegate>
  24. @property (nonatomic, strong) KSAudioSessionManager *audioSessionManager;
  25. @property (nonatomic, assign) MetronomeType beatType;
  26. @property (nonatomic, strong) MidiPlayerEngine *playerEngine; // player
  27. @property (nonatomic, assign) BOOL initEngineSuccess; // 加载引擎是否成功
  28. @property (nonatomic, assign) float songOriginalSpeed;
  29. @property (nonatomic, assign) float currentSpeed; // 当前播放的速度
  30. @property (nonatomic, assign) BOOL isPlaying; // 是否正在播放的状态
  31. @property (nonatomic, strong) NSString *currentSongId; // song id
  32. @property (nonatomic, strong) NSDictionary *configEngineParm; // 初始化mid播放引擎的参数
  33. @property (nonatomic, strong) NSMutableDictionary *metronomeParm; // 节拍器播放的参数
  34. // 是否发送了musicXML信息
  35. @property (nonatomic, assign) BOOL hasSendStartMessage;
  36. @property (nonatomic, strong) KSAQRecordManager *AQManager;
  37. @property (nonatomic, strong) KSWebSocketManager *socketManager;
  38. @property (nonatomic, strong) NSMutableDictionary *evaluatParm;
  39. // 录制的message
  40. @property (nonatomic, strong) NSMutableDictionary *recordParm;
  41. // 评测开始时发送recordStart消息的标识
  42. @property (nonatomic, assign) BOOL isCompareStart;
  43. // 校音开始时发送 checkStart消息标识
  44. @property (nonatomic, assign) BOOL isSoundCheckStart;
  45. // 自定义UI控件容器
  46. @property (nonatomic, strong) UIView *viewContainer;
  47. @property (nonatomic, strong) KSVideoRecordManager *videoRecordManager;
  48. @property (nonatomic, strong) NSDictionary *endRecordParm;
  49. @property (nonatomic, assign) BOOL isCameraOpen;
  50. @property (nonatomic, strong) AccompanyLoadingView *loadingView;
  51. @property (nonatomic, assign) BOOL isTunerRuning;
  52. @property (nonatomic, strong) Tuner *tuner;
  53. // 延迟校准开始时发送 AdjustStart消息标识
  54. @property (nonatomic, assign) BOOL isDelayCheckStart;
  55. // 检测延迟播放器
  56. @property (nonatomic, strong) kSNewPlayer *dingPlayer;
  57. @property (nonatomic, strong) kSNewPlayer *dongPlayer;
  58. // 音频播放器
  59. @property (nonatomic, strong) kSNewPlayer *musicPlayer;
  60. // 录音开始时间
  61. @property (nonatomic, assign) NSTimeInterval recordStartTime;
  62. // 播放开始时间
  63. @property (nonatomic, assign) NSTimeInterval playerStartTime;
  64. // 播放延迟
  65. @property (nonatomic, assign) NSInteger offsetTime;
  66. @property (nonatomic, assign) BOOL dingPlayerReady;
  67. @property (nonatomic, assign) BOOL dongPlayerReady;
  68. @property (nonatomic, assign) BOOL musicPlayerReady;
  69. @property (nonatomic, strong) NSDictionary *playerParm;
  70. @property (nonatomic, strong) NSMutableArray *delayArray;
  71. @property (nonatomic, assign) NSInteger checkIndex;
  72. @property (nonatomic, assign) NSInteger firstFrequence;
  73. @property (nonatomic, assign) NSInteger secondFrequence;
  74. @property (nonatomic, strong) NSURL *bgAudioUrl;
  75. @property (nonatomic, strong) NSURL *recordUrl;
  76. @property (nonatomic, strong) NSString *accompanyUrl;
  77. @end
  78. @implementation KSAccompanyWebViewController
  79. - (void)handerAudioInterruption {
  80. if (_playerEngine) {
  81. [self stopPlayAction];
  82. }
  83. }
  84. - (void)resumeAudioSession {
  85. // 恢复
  86. if (_playerEngine) {
  87. [self.playerEngine resumeAUGraph];
  88. }
  89. }
  90. // 打断处理
  91. - (void)audioInterruption {
  92. if (_videoRecordManager) {
  93. [self.videoRecordManager resetSession];
  94. }
  95. [self handerAudioInterruption];
  96. }
  97. - (void)ignorRecordVideo {
  98. if (_videoRecordManager) {
  99. self.videoRecordManager.skipSaveRecord = YES;
  100. }
  101. }
  102. - (void)stopSession {
  103. if (_videoRecordManager) {
  104. [self.videoRecordManager stopSession];
  105. }
  106. }
  107. - (void)resetPlayerConfig {
  108. [self freeMp3Player]; // 若之前有播放器,剔除
  109. self.firstFrequence = 800;
  110. self.secondFrequence = 800;
  111. self.dingPlayerReady = NO;
  112. self.dongPlayerReady = NO;
  113. self.musicPlayerReady = NO;
  114. self.recordStartTime = 0;
  115. self.playerStartTime = 0;
  116. self.offsetTime = 0;
  117. }
  118. - (void)initMp3Player:(NSString *)musicUrl checkUrl:(NSString *)checkUrl {
  119. [self resetPlayerConfig];
  120. self.accompanyUrl = musicUrl;
  121. [self.musicPlayer preparePlaySongWithUrl:musicUrl];
  122. [self.dingPlayer preparePlaySongWithUrl:checkUrl];
  123. [self.dongPlayer preparePlaySongWithUrl:checkUrl];
  124. [self prepareMusic];
  125. }
  126. - (void)prepareMusic {
  127. self.dingPlayer.isMute = YES;
  128. [self.dingPlayer startPlay];
  129. self.dongPlayer.isMute = YES;
  130. [self.dongPlayer startPlay];
  131. self.musicPlayer.isMute = YES;
  132. [self.musicPlayer startPlay];
  133. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  134. [self.musicPlayer puasePlay];
  135. self.musicPlayer.isMute = NO;
  136. [self.dingPlayer puasePlay];
  137. self.dingPlayer.isMute = NO;
  138. [self.dongPlayer puasePlay];
  139. self.dongPlayer.isMute = NO;
  140. [self configPlayerDelegate];
  141. });
  142. }
  143. - (void)freeMp3Player {
  144. if (_dingPlayer) {
  145. [self.dingPlayer freePlayer];
  146. }
  147. if (_dongPlayer) {
  148. [self.dongPlayer freePlayer];
  149. }
  150. if (_musicPlayer) {
  151. [self.musicPlayer freePlayer];
  152. }
  153. }
  154. - (void)stopMp3Player {
  155. if (_dingPlayer) {
  156. [self.dingPlayer puasePlay];
  157. }
  158. if (_dongPlayer) {
  159. [self.dongPlayer puasePlay];
  160. }
  161. if (_musicPlayer) {
  162. [self.musicPlayer puasePlay];
  163. }
  164. }
  165. - (void)viewDidLoad {
  166. [super viewDidLoad];
  167. // Do any additional setup after loading the view.
  168. [self configAudioSession];
  169. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterBackground) name:@"appEnterBackground" object:nil];
  170. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterForeground) name:@"appEnterForeground" object:nil];
  171. }
  172. - (void)checkMessage:(id)message {
  173. NSDictionary *result = [message mj_JSONObject];
  174. NSString *type = [[result ks_dictionaryValueForKey:@"header"] ks_stringValueForKey:@"type"];
  175. NSString *commond = [[result ks_dictionaryValueForKey:@"header"] ks_stringValueForKey:@"commond"];
  176. if ([type isEqualToString:@"DELAY_CHECK"] && [commond isEqualToString:@"recordEnd"]) {
  177. NSDictionary *body = [result ks_dictionaryValueForKey:@"body"];
  178. NSTimeInterval micDelay = [body ks_doubleValueForKey:@"firstNoteDelayDuration"] - self.offsetTime;
  179. [self.delayArray addObject:[NSNumber numberWithDouble:micDelay]];
  180. }
  181. }
  182. - (void)connectSocketService {
  183. MJWeakSelf;
  184. self.socketManager.didReceiveMessage = ^(id _Nonnull message) {
  185. dispatch_async(dispatch_get_main_queue(), ^{
  186. [weakSelf checkMessage:message];
  187. // api
  188. NSMutableDictionary *sendMessage = [NSMutableDictionary dictionary];
  189. [sendMessage setValue:@"sendResult" forKey:@"api"];
  190. [sendMessage setValue:message forKey:@"content"];
  191. // 服务返回数据传给H5
  192. [weakSelf postMessage:sendMessage];
  193. });
  194. };
  195. self.socketManager.connectionStatus = ^(BOOL isSuccess) {
  196. dispatch_async(dispatch_get_main_queue(), ^{
  197. if (!isSuccess) {
  198. // NSLog(@"-----连接失败");
  199. if (weakSelf.hasSendStartMessage) {
  200. if (weakSelf.AQManager.isRunning) {
  201. NSDictionary *postParm = @{@"api" : @"cancelEvaluating",
  202. @"content" : @{@"reson":@"服务异常,请重试"}
  203. };
  204. [weakSelf postMessage:postParm];
  205. [weakSelf stopRecordService];
  206. weakSelf.isCompareStart = NO;
  207. weakSelf.isSoundCheckStart = NO;
  208. weakSelf.isDelayCheckStart = NO;
  209. }
  210. }
  211. else if (weakSelf.evaluatParm) {
  212. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:weakSelf.evaluatParm];
  213. NSDictionary *valueDic = [weakSelf.evaluatParm ks_dictionaryValueForKey:@"content"];
  214. [valueDic setValue:@"服务异常,请重试" forKey:@"reson"];
  215. [sendParm setValue:valueDic forKey:@"content"];
  216. [weakSelf postMessage:sendParm];
  217. weakSelf.hasSendStartMessage = YES;
  218. weakSelf.isCompareStart = NO;
  219. weakSelf.isSoundCheckStart = NO;
  220. weakSelf.isDelayCheckStart = NO;
  221. }
  222. else { // 其他断开
  223. if (weakSelf.AQManager.isRunning) {
  224. NSDictionary *postParm = @{@"api" : @"cancelEvaluating",
  225. @"content" : @{@"reson":@"服务异常,请重试"}
  226. };
  227. [weakSelf postMessage:postParm];
  228. [weakSelf stopRecordService];
  229. weakSelf.isCompareStart = NO;
  230. weakSelf.isSoundCheckStart = NO;
  231. weakSelf.isDelayCheckStart = NO;
  232. }
  233. }
  234. }
  235. else {
  236. // NSLog(@"-----连接成功");
  237. if (weakSelf.hasSendStartMessage == NO && weakSelf.evaluatParm) {
  238. NSDictionary *content = [weakSelf.evaluatParm ks_dictionaryValueForKey:@"content"];
  239. NSString *sendData = [weakSelf configDataCommond:@"musicXml" body:content type:@"SOUND_COMPARE"];
  240. [weakSelf sendDataToSocketService:sendData];
  241. [weakSelf postMessage:weakSelf.evaluatParm];
  242. weakSelf.hasSendStartMessage = YES;
  243. }
  244. }
  245. });
  246. };
  247. [self.socketManager SRWebSocketOpen];
  248. }
  249. - (void)appEnterBackground {
  250. NSDictionary *parm = @{@"api":@"suspendPlay"};
  251. [self postMessage:parm];
  252. [self handerAudioInterruption];
  253. }
  254. - (void)appEnterForeground {
  255. if (self.isCameraOpen) {
  256. if ([self.videoRecordManager getSessionStatusisActive] == NO) {
  257. [self.videoRecordManager configSessiondisplayInView:self.viewContainer];
  258. }
  259. }
  260. }
  261. - (void)initWebView {
  262. [self.scrollView removeFromSuperview];
  263. [self.view addSubview:self.viewContainer];
  264. [self.viewContainer mas_makeConstraints:^(MASConstraintMaker *make) {
  265. make.left.right.top.bottom.mas_equalTo(self.view);
  266. }];
  267. if (self.myWebView == nil) {
  268. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  269. config.selectionGranularity = WKSelectionGranularityDynamic;
  270. config.allowsInlineMediaPlayback = YES;
  271. config.mediaTypesRequiringUserActionForPlayback = NO;
  272. config.processPool = [KSBaseWKWebViewController singleWkProcessPool];
  273. config.websiteDataStore = [WKWebsiteDataStore defaultDataStore];
  274. [self configUserAgent:config];
  275. //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
  276. WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
  277. //这个类主要用来做native与JavaScript的交互管理
  278. WKUserContentController * wkUController = [[WKUserContentController alloc] init];
  279. [wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"COLEXIU"];
  280. config.userContentController = wkUController;
  281. WKPreferences *preferences = [WKPreferences new];
  282. // 是否支出javaScript
  283. preferences.javaScriptEnabled = YES;
  284. //不通过用户交互,是否可以打开窗口
  285. preferences.javaScriptCanOpenWindowsAutomatically = YES;
  286. config.preferences = preferences;
  287. self.myWebView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
  288. self.myWebView.opaque = NO;
  289. self.myWebView.UIDelegate = self;
  290. self.myWebView.navigationDelegate = self;
  291. self.myWebView.scrollView.bounces = NO;
  292. self.myWebView.backgroundColor = [UIColor clearColor];
  293. self.myWebView.scrollView.backgroundColor = [UIColor clearColor];
  294. // 加载进度条和title
  295. [self.myWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
  296. [self.view addSubview:self.myWebView];
  297. [self.myWebView mas_makeConstraints:^(MASConstraintMaker *make) {
  298. make.left.right.mas_equalTo(self.view);
  299. make.top.mas_equalTo(self.view.mas_top);
  300. make.bottom.mas_equalTo(self.view.mas_bottom);
  301. }];
  302. self.myWebView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  303. [self setupProgress];
  304. [self loadRequest];
  305. }
  306. else {
  307. [self.myWebView reload];
  308. }
  309. }
  310. - (void)configUserAgent:(WKWebViewConfiguration *)config {
  311. NSString *oldUserAgent = config.applicationNameForUserAgent;
  312. NSString *newAgent = [NSString stringWithFormat:@"%@ %@ %@",oldUserAgent,@"ORCHESTRAAPPI",@"ORCHESTRASTUDENT"];
  313. config.applicationNameForUserAgent = newAgent;
  314. }
  315. - (void)configRecordManager {
  316. self.AQManager = [[KSAQRecordManager alloc] init];
  317. self.AQManager.delegate = self;
  318. }
  319. - (void)viewWillAppear:(BOOL)animated {
  320. [super viewWillAppear:animated];
  321. [self connectSocketService];
  322. if (self.isCameraOpen) {
  323. [self.videoRecordManager configSessiondisplayInView:self.viewContainer];
  324. }
  325. }
  326. - (void)viewWillDisappear:(BOOL)animated {
  327. [super viewWillDisappear:animated];
  328. if (_socketManager) {
  329. [self.socketManager SRWebSocketClose];
  330. _socketManager = nil;
  331. }
  332. // 停止播放和录制
  333. [self stopSession];
  334. [self stopPlayAction];
  335. [self stopRecordService];
  336. [self stopTuner];
  337. BOOL isBack = [self isViewPopDismiss];
  338. if (isBack) { // 页面销毁才删除
  339. if (_AQManager) {
  340. [_AQManager freeAudioQueue];
  341. _AQManager = nil;
  342. }
  343. // 如果退出评测页面 清除 playerEngine
  344. if (self.playerEngine) {
  345. [self.playerEngine cleanup];
  346. self.playerEngine = nil;
  347. }
  348. // 返回不保存视频
  349. [self ignorRecordVideo];
  350. [self freeMp3Player];
  351. }
  352. }
  353. - (void)sendDataToSocketService:(id)data {
  354. if (_socketManager) {
  355. [self.socketManager sendData:data];
  356. }
  357. }
  358. #pragma mark --- WKScriptMessageHandler
  359. - (void)userContentController:(WKUserContentController *)userContentController
  360. didReceiveScriptMessage:(WKScriptMessage *)message {
  361. if ([message.name isEqualToString:@"COLEXIU"]) {
  362. NSDictionary *parm = [self convertJsonStringToNSDictionary:message.body];
  363. NSLog(@"---- receive parm %@", [parm mj_JSONString]);
  364. // 回到主线程
  365. dispatch_async(dispatch_get_main_queue(), ^{
  366. if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"createMusicPlayer"]) {
  367. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  368. NSString *musicUrl = [content ks_stringValueForKey:@"musicSrc"];
  369. NSString *checkUrl = [content ks_stringValueForKey:@"tuneSrc"];
  370. self.playerParm = parm;
  371. [self initMp3Player:musicUrl checkUrl:checkUrl];
  372. }
  373. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"startEvaluating"]) { // 开始评测
  374. [self configRecordManager];
  375. self.hasSendStartMessage = NO;
  376. PREMISSIONTYPE isOk = [RecordCheckManager checkPermissionShowAlert:NO showInView:nil];
  377. if (isOk == PREMISSIONTYPE_YES) {
  378. self.evaluatParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  379. // 如果socket 连上了
  380. if (self.socketManager.socketReadyState == SR_OPEN) {
  381. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  382. NSString *sendData = [self configDataCommond:@"musicXml" body:content type:@"SOUND_COMPARE"];
  383. [self sendDataToSocketService:sendData];
  384. [self postMessage:parm];
  385. self.hasSendStartMessage = YES;
  386. }
  387. else {
  388. [self connectSocketService];
  389. }
  390. }
  391. else {
  392. NSDictionary *postParm = @{@"api" : @"cancelEvaluating",
  393. @"content" : @{@"reson":@"没有麦克风权限"}
  394. };
  395. [self postMessage:postParm];
  396. }
  397. }
  398. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"endEvaluating"]) {// 停止评测
  399. self.evaluatParm = nil;
  400. [self stopRecordService];
  401. [self postMessage:parm];
  402. [self sendEndMessage];
  403. [self stopMp3Player]; // 停止播放
  404. }
  405. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cancelEvaluating"]) { // 取消评测
  406. self.evaluatParm = nil;
  407. [self stopRecordService];
  408. [self postMessage:parm];
  409. // [self sendEndMessage];
  410. [self stopMp3Player]; // 停止播放
  411. }
  412. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"startRecording"]) { // 开始录制
  413. if (self.videoRecordManager) {
  414. [self.videoRecordManager clearVideoFile];
  415. }
  416. [self postMessage:parm];
  417. self.isCompareStart = YES;
  418. [self startRecordService];
  419. }
  420. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"endRecording"]) { // 停止录音
  421. self.recordParm = nil;
  422. [self stopRecordService];
  423. [self postMessage:parm];
  424. }
  425. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"pauseRecording"]) {
  426. [self puaseRecordService];
  427. [self postMessage:parm];
  428. }
  429. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"resumeRecording"]) {
  430. [self resumeRecordService];
  431. [self postMessage:parm];
  432. }
  433. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"isWiredHeadsetOn"]) {
  434. [self configAudioDeviceType:parm];
  435. }
  436. // 发送消息给socket service
  437. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"proxyMessage"]) {
  438. [self sendMessageToSocket:parm];
  439. }
  440. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"proxyServiceMessage"]) {
  441. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  442. NSString *sendData = [content mj_JSONString];
  443. NSLog(@"proxyServiceMessage ------- %@",sendData);
  444. [self sendDataToSocketService:sendData];
  445. }
  446. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"openCamera"]) { // 开启摄像头
  447. PREMISSIONTYPE canOpenCamera = [RecordCheckManager checkCameraPremissionAvaiable:NO showInView:nil];
  448. PREMISSIONTYPE albumEnable = [RecordCheckManager checkPhotoLibraryPremissionAvaiable:NO showInView:nil];
  449. if (canOpenCamera == PREMISSIONTYPE_YES) {
  450. self.isCameraOpen = YES;
  451. [self.videoRecordManager setIgnoreAudio:YES];
  452. [self.videoRecordManager configSessiondisplayInView:self.viewContainer];
  453. [self postMessage:parm];
  454. }
  455. if (albumEnable == PREMISSIONTYPE_NO) {
  456. [self showAlertWithMessage:@"请开启相册访问权限" type:CHECKDEVICETYPE_CAMREA];
  457. }
  458. }
  459. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"closeCamera"]) { // 关闭摄像头
  460. self.isCameraOpen = NO;
  461. if (self->_videoRecordManager) {
  462. [self.videoRecordManager removeDisplay];
  463. }
  464. [self postMessage:parm];
  465. }
  466. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"startCapture"]) { // 开始录制
  467. // 需要合成音频
  468. [self.videoRecordManager setIgnoreAudio:YES];
  469. [RecordCheckManager checkPhotoLibraryPremissionAvaiable:YES showInView:self.view];
  470. self.videoRecordManager.audioUrl = self.AQManager.audioUrl;
  471. [self.videoRecordManager startRecord];
  472. [self postMessage:parm];
  473. }
  474. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"endCapture"]) { // 结束录制
  475. if (self->_videoRecordManager) {
  476. self.endRecordParm = parm;
  477. [self.videoRecordManager stopRecord];
  478. }
  479. else {
  480. [self postMessage:parm];
  481. }
  482. }
  483. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"setCaptureMode"]) {
  484. NSString *modeString = [[parm ks_dictionaryValueForKey:@"content"] ks_stringValueForKey:@"mode"];
  485. BOOL isIgnoreAudio = [modeString isEqualToString:@"evaluating"];
  486. [self postMessage:parm];
  487. [self.videoRecordManager setIgnoreAudio:isIgnoreAudio];
  488. }
  489. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"startSoundCheck"]) { // 开始校音
  490. [self configRecordManager];
  491. [self postMessage:parm];
  492. self.isCompareStart = NO;
  493. self.isSoundCheckStart = YES;
  494. self.isDelayCheckStart = NO;
  495. [self startRecordService];
  496. }
  497. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"endSoundCheck"]) {
  498. // 结束校音
  499. self.isSoundCheckStart = NO;
  500. [self stopRecordService];
  501. [self postMessage:parm];
  502. }
  503. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"videoUpdate"]) { // 上传
  504. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  505. NSMutableDictionary *contentParm = [NSMutableDictionary dictionaryWithDictionary:[sendParm ks_dictionaryValueForKey:@"content"]];
  506. if (self.videoRecordManager) {
  507. MJWeakSelf;
  508. [self.videoRecordManager saveVideoCallback:^(BOOL isSuccess, NSString * _Nullable message) {
  509. if (isSuccess) {
  510. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"已保存到相册"];
  511. [weakSelf uploadVideoWithParm:contentParm sendParm:sendParm];
  512. }
  513. }];
  514. }
  515. }
  516. #pragma mark -------- 云教练原生播放对接
  517. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudDetail"]) { // 初始化方法
  518. /**
  519. api: 'cloudDetail',
  520. content: {
  521. midi: '',
  522. denominator: 4,
  523. numerator: 4,
  524. // xml整体原始速度
  525. originalSpeed: 90,
  526. // 间隔(ms)
  527. interval: 50
  528. }
  529. */
  530. [self configAudioSession];
  531. // 重置track num array
  532. self.configEngineParm = [parm copy];
  533. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  534. NSString *midiUrl = [content ks_stringValueForKey:@"midi"];
  535. NSInteger denominator = [content ks_integerValueForKey:@"denominator"];
  536. NSInteger numerator = [content ks_integerValueForKey:@"numerator"];
  537. NSString *beatString = [NSString stringWithFormat:@"%zd/%zd", numerator,denominator];
  538. self.beatType = [self getBeatTypeFromString:beatString];
  539. float originalSpeed = [content ks_floatValueForKey:@"originalSpeed"];
  540. self.songOriginalSpeed = originalSpeed;
  541. self.currentSpeed = originalSpeed;
  542. NSInteger reportInterval = [content ks_integerValueForKey:@"interval"];
  543. // 下载midi文件
  544. BOOL hasSaveSong = [self checkSongHasSaveWithSongUrl:midiUrl];
  545. NSString *fileName = [midiUrl getUrlFileName];
  546. NSString *filePath = [self getFilePathWithName:fileName];
  547. if (hasSaveSong) {
  548. [self configPlayerEngineWithSong:filePath reportTime:reportInterval];
  549. }
  550. else {
  551. MJWeakSelf;
  552. [self downloadMidiFile:midiUrl success:^{
  553. [weakSelf configPlayerEngineWithSong:filePath reportTime:reportInterval];
  554. } faliure:^{
  555. }];
  556. }
  557. }
  558. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudGetMediaStatus"]) { // 获取播放状态
  559. /**
  560. api: 'cloudGetMediaStatus',
  561. content: {
  562. status: 'init' | 'play' | 'suspend'
  563. }
  564. */
  565. NSString *engineStatus = @"init";
  566. if (self.initEngineSuccess) {
  567. if (self.isPlaying) {
  568. engineStatus = @"play";
  569. }
  570. else {
  571. engineStatus = @"suspend";
  572. }
  573. }
  574. NSMutableDictionary *valueDic = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
  575. [valueDic setValue:engineStatus forKey:@"status"];
  576. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  577. [sendParm setValue:valueDic forKey:@"content"];
  578. [self postMessage:sendParm];
  579. }
  580. // 播放、暂停、进度、播放结束、跳转指定位置
  581. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudPlay"]) { // 播放
  582. /**
  583. api: 'cloudPlay',
  584. content: {
  585. // 当前曲目id
  586. songID: 0,
  587. // xml整体原始速度
  588. originalSpeed: 90,
  589. // 当前选择速度
  590. speed: 90,
  591. // 开始时间(ms)
  592. startTime: 0
  593. // 播放频率
  594. hertz:440
  595. }
  596. */
  597. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  598. self.currentSongId = [content ks_stringValueForKey:@"songID"];
  599. float speed = [content ks_floatValueForKey:@"speed"];
  600. float originalSpeed = [content ks_floatValueForKey:@"originalSpeed"];
  601. double rate = speed / originalSpeed;
  602. self.currentSpeed = speed;
  603. float hertz = [content ks_floatValueForKey:@"hertz"];
  604. // 播放的hertz
  605. [self.playerEngine adjustPitchByHZ:hertz];
  606. [self.playerEngine setMusicPlayerSpeed:rate];
  607. Float64 startTime = [content ks_doubleValueForKey:@"startTime"];
  608. NSLog(@"------%@", [content ks_stringValueForKey:@"startTime"]);
  609. [self.playerEngine setProgressTime:(startTime/1000)];
  610. // 播放
  611. [self playAction];
  612. [self postMessage:parm];
  613. }
  614. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudSuspend"]) { // 暂停
  615. /**
  616. api: 'cloudSuspend',
  617. content: {
  618. // 当前曲目id
  619. songID: 0,
  620. }
  621. */
  622. [self stopPlayAction];
  623. [self postMessage:parm];
  624. }
  625. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudSetCurrentTime"]) { // // 跳转指定位置
  626. /**
  627. api: 'cloudSetCurrentTime',
  628. content: {
  629. // 当前曲目id
  630. songID: 0,
  631. // 指定位置时间(ms)
  632. currentTime: 0
  633. }
  634. */
  635. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  636. Float64 currentTime = [content ks_doubleValueForKey:@"currentTime"];
  637. if (self.playerEngine) {
  638. [self.playerEngine setProgressTime:(currentTime/1000)];
  639. }
  640. [self postMessage:parm];
  641. }
  642. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudChangeSpeed"]) { // 调速 范围(45-270整数)
  643. /**
  644. api: 'cloudChangeSpeed',
  645. content: {
  646. // 当前曲目id
  647. songID: 0,
  648. // 调整速度
  649. speed: 90
  650. // xml整体原始速度
  651. originalSpeed: 90,
  652. }
  653. */
  654. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  655. float speed = [content ks_floatValueForKey:@"speed"];
  656. float originalSpeed = [content ks_floatValueForKey:@"originalSpeed"];
  657. double rate = speed / originalSpeed;
  658. self.currentSpeed = speed;
  659. [self.playerEngine setMusicPlayerSpeed:rate];
  660. // 回报信息
  661. [self postMessage:parm];
  662. }
  663. // 设置每个轨道音量
  664. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudVolume"]) {
  665. /**
  666. api: 'cloudVolume',
  667. content: {
  668. parts: [
  669. {
  670. name: '',
  671. volume: 90,//0-100
  672. }
  673. ]
  674. }
  675. */
  676. NSLog(@"-cloudVolume -----%@",parm);
  677. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  678. int instrumentId = [content ks_intValueForKey:@"activeMidiId"];
  679. float volume = [content ks_floatValueForKey:@"activeMidiVolume"];
  680. if (instrumentId < 0) {
  681. [self postMessage:parm];
  682. [self.playerEngine getAllTrackVolume];
  683. return;
  684. }
  685. [self.playerEngine volumeTrackVolumeWithInstrumentId:instrumentId volume:volume/100];
  686. [self postMessage:parm];
  687. [self.playerEngine getAllTrackVolume];
  688. }
  689. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudMetronome"]) { // 节拍器播放
  690. self.metronomeParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  691. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  692. NSInteger repeatCount = [content ks_integerValueForKey:@"repeat"];
  693. NSInteger denominator = [content ks_integerValueForKey:@"denominator"];
  694. NSInteger numerator = [content ks_integerValueForKey:@"numerator"];
  695. NSInteger supplement = [content ks_integerValueForKey:@"supplement"];
  696. NSString *beatString = [NSString stringWithFormat:@"%zd/%zd", numerator,denominator];
  697. self.beatType = [self getBeatTypeFromString:beatString];
  698. [self showBeatViewRepeatCount:repeatCount supplement:supplement];
  699. }
  700. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudDestroy"]) { // 销毁播放器
  701. self.initEngineSuccess = NO;
  702. // 重置track num array
  703. self.isPlaying = NO;
  704. if (self.playerEngine) {
  705. [self.playerEngine cleanup];
  706. self.playerEngine = nil;
  707. }
  708. }
  709. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudLoading"]) { // loading
  710. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  711. BOOL showLoading = [content ks_boolValueForKey:@"show"];
  712. if (showLoading) {
  713. [self showCustomLoading];
  714. }
  715. else {
  716. [self removeCustomLoadingView];
  717. }
  718. }
  719. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudAccompanyMessage"]) { // 获取伴奏
  720. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  721. NSString *accompanyUrl = [content ks_stringValueForKey:@"accompanyUrl"];
  722. if (![NSString isEmptyString:accompanyUrl]) {
  723. NSString *fileName = [accompanyUrl getUrlFileName];
  724. NSString *filePath = [self getAccompanyFilePathWithName:fileName];
  725. NSURL *fileUrl = [[NSURL alloc] initFileURLWithPath:filePath];
  726. self.accompanyUrl = accompanyUrl;
  727. if ([self checkSongHasSaveAccompanyWithSongUrl:accompanyUrl]) {
  728. [self configVideoRecord:fileUrl];
  729. }
  730. else {
  731. MJWeakSelf;
  732. [self downloadUrl:accompanyUrl success:^{
  733. [weakSelf configVideoRecord:fileUrl];
  734. } faliure:^{
  735. }];
  736. }
  737. }
  738. else {
  739. // [LOADING_MANAGER MBShowAUTOHidingInWindow:@"当前曲目无mp3伴奏"];
  740. [self configVideoRecord:nil];
  741. }
  742. }
  743. // 跟音
  744. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"cloudToggleFollow"]) {
  745. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  746. NSString *status = [content ks_stringValueForKey:@"state"];
  747. if ([status isEqualToString:@"start"]) { // 开始
  748. [self startTuner];
  749. }
  750. else if ([status isEqualToString:@"end"]) { // 结束
  751. [self stopTuner];
  752. }
  753. }
  754. // 延迟检测
  755. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"startTune"]) { // 延迟测试开始
  756. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  757. NSInteger count = [content ks_integerValueForKey:@"count"];
  758. if (count == 0) {
  759. [self.delayArray removeAllObjects];
  760. self.checkIndex = 0;
  761. }
  762. self.checkIndex += 1;
  763. [self configRecordManager];
  764. [self postMessage:parm];
  765. self.isCompareStart = NO;
  766. self.isSoundCheckStart = NO;
  767. self.isDelayCheckStart = YES;
  768. [self startRecordService];
  769. }
  770. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"endTune"]) { // 延迟测试结束
  771. self.isDelayCheckStart = NO;
  772. [self stopRecordService];
  773. [self postMessage:parm];
  774. [self stopMp3Player];
  775. [self sendAdjustEndMessage]; // 发送结束消息
  776. }
  777. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"finishTune"]) { // 延迟测试结束
  778. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  779. NSInteger errorCount = 0;
  780. NSInteger totalDelay = 0;
  781. for (NSInteger index = 0 ; index < self.delayArray.count; index++) {
  782. NSInteger micDelay = [self.delayArray[index] integerValue];
  783. if (micDelay > 10 && micDelay < 100) {
  784. totalDelay += micDelay;
  785. }
  786. else {
  787. errorCount++;
  788. }
  789. }
  790. NSMutableDictionary *contentParm = [NSMutableDictionary dictionaryWithDictionary:content];
  791. if (errorCount > 1) { // 错误次数过多
  792. [contentParm setValue:@(NO) forKey:@"result"];
  793. }
  794. else {
  795. [contentParm setValue:@(YES) forKey:@"result"];
  796. NSInteger averageDelay = totalDelay / (self.delayArray.count - errorCount);
  797. UserDefaultSet([NSNumber numberWithDouble:averageDelay], @"micDelay");
  798. }
  799. NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
  800. [sendParm setValue:@"finishTune" forKey:@"api"];
  801. [sendParm setValue:contentParm forKey:@"content"];
  802. [self postMessage:sendParm];
  803. [self.delayArray removeAllObjects];
  804. self.checkIndex = 0;
  805. }
  806. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"getDeviceDelay"]) {
  807. NSInteger micDelay = [UserDefaultObjectForKey(@"micDelay") integerValue];
  808. NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
  809. [content setValue:[NSNumber numberWithInteger:micDelay] forKey:@"value"];
  810. NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
  811. [sendParm setValue:@"getDeviceDelay" forKey:@"api"];
  812. [sendParm setValue:content forKey:@"content"];
  813. [self postMessage:sendParm];
  814. }
  815. // 音视频合成
  816. else if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"openAdjustRecording"]) {
  817. KSMediaMergeView *mergeView = [[KSMediaMergeView alloc] init];
  818. if (self.bgAudioUrl == nil) {
  819. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"当前曲目无mp3伴奏"];
  820. }
  821. else {
  822. if (self.AQManager && self.AQManager.audioUrl) {
  823. self.recordUrl = self.AQManager.audioUrl;
  824. [self.view addSubview:mergeView];
  825. [mergeView mas_makeConstraints:^(MASConstraintMaker *make) {
  826. make.left.right.top.bottom.mas_equalTo(self.view);
  827. }];
  828. NSDictionary *content = [parm ks_dictionaryValueForKey:@"content"];
  829. mergeView.recordId = [content ks_stringValueForKey:@"recordId"];
  830. mergeView.songName = [content ks_stringValueForKey:@"title"];
  831. mergeView.coverImage = [content ks_stringValueForKey:@"coverImg"];
  832. MJWeakSelf;
  833. [mergeView configWithVideoUrl:self.videoRecordManager.videoFileURL bgAudioUrl:self.bgAudioUrl remoteBgUrl:self.accompanyUrl recordUrl:self.recordUrl offsetTime:self.offsetTime mergeCallback:^{
  834. [weakSelf musicPublishCallBack:content];
  835. }];
  836. }
  837. else {
  838. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"麦克风被占用"];
  839. }
  840. }
  841. }
  842. else {
  843. [super handleScriptMessageSource:parm];
  844. }
  845. });
  846. }
  847. }
  848. - (void)musicPublishCallBack:(NSDictionary *)content {
  849. NSMutableDictionary *parm = [NSMutableDictionary dictionary];
  850. [parm setValue:@"hideComplexButton" forKey:@"api"];
  851. [parm setValue:@{} forKey:@"content"];
  852. [self postMessage:parm];
  853. }
  854. - (void)uploadVideoWithParm:(NSMutableDictionary *)contentParm sendParm:(NSMutableDictionary *)sendParm {
  855. MJWeakSelf;
  856. [self.videoRecordManager uploadRecordVideoSuccess:^(NSString * _Nonnull videoUrl) {
  857. [contentParm setValue:@"success" forKey:@"type"];
  858. [contentParm setValue:videoUrl forKey:@"filePath"];
  859. [contentParm setValue:@"上传成功" forKey:@"message"];
  860. [sendParm setValue:contentParm forKey:@"content"];
  861. [weakSelf postMessage:sendParm];
  862. } failure:^(NSString * _Nonnull desc) {
  863. [contentParm setValue:@"error" forKey:@"type"];
  864. [contentParm setValue:desc forKey:@"message"];
  865. [sendParm setValue:contentParm forKey:@"content"];
  866. [weakSelf postMessage:sendParm];
  867. }];
  868. }
  869. - (void)showAlertWithMessage:(NSString *)message type:(CHECKDEVICETYPE)deviceType {
  870. [KSPremissionAlert shareInstanceDisplayImage:deviceType message:message showInView:self.view cancel:^{
  871. } confirm:^{
  872. [self openSettingView];
  873. }];
  874. }
  875. - (void)openSettingView {
  876. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
  877. }
  878. - (void)downloadUrl:(NSString *)url success:(void(^)(void))success faliure:(void(^)(void))faliure {
  879. [KSNetworkingManager downloadFileRequestWithFileUrl:url progress:^(int64_t bytesRead, int64_t totalBytes) {
  880. } success:^(NSURL * _Nonnull fileUrl) {
  881. if ([self saveAccompanyFileWithUrl:fileUrl accompanyUrl:url]) {
  882. if (success) {
  883. success();
  884. }
  885. }
  886. } faliure:^(NSError * _Nonnull error) {
  887. if (faliure) {
  888. faliure();
  889. }
  890. }];
  891. }
  892. - (void)configVideoRecord:(NSURL *)path {
  893. self.videoRecordManager.bgAudioUrl = path;
  894. self.bgAudioUrl = path;
  895. }
  896. - (void)showBeatViewRepeatCount:(NSInteger)repeatCount supplement:(NSInteger)supplement {
  897. KSCloudBeatView *beatView = [KSCloudBeatView shareInstanceWithBeatType:self.beatType speed:self.currentSpeed repeatCount:repeatCount supplement:supplement];
  898. MJWeakSelf;
  899. [beatView startPlayWithEndCallback:^(BOOL isCancle) {
  900. if (isCancle) { // 取消
  901. [weakSelf sendEndMetronomeMessage:YES];
  902. }
  903. else { // 播放完成
  904. [weakSelf sendEndMetronomeMessage:NO];
  905. }
  906. }];
  907. [self.view addSubview:beatView];
  908. }
  909. - (void)sendEndMetronomeMessage:(BOOL)isCancel {
  910. NSString *status = isCancel ? @"cancel" : @"finish";
  911. NSMutableDictionary *valueDic = [NSMutableDictionary dictionaryWithDictionary:[self.metronomeParm ks_dictionaryValueForKey:@"content"]];
  912. [valueDic setValue:status forKey:@"status"];
  913. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:self.metronomeParm];
  914. [sendParm setValue:valueDic forKey:@"content"];
  915. [self postMessage:sendParm];
  916. }
  917. - (void)downloadMidiFile:(NSString *)midiUrl success:(void(^)(void))success faliure:(void(^)(void))faliure {
  918. [KSNetworkingManager downloadFileRequestWithFileUrl:midiUrl progress:^(int64_t bytesRead, int64_t totalBytes) {
  919. } success:^(NSURL * _Nonnull fileUrl) {
  920. if ([self saveMidiFileWithUrl:fileUrl midiUrl:midiUrl]) {
  921. success();
  922. }
  923. } faliure:^(NSError * _Nonnull error) {
  924. faliure();
  925. }];
  926. }
  927. - (BOOL)saveMidiFileWithUrl:(NSURL *)fileUrl midiUrl:(NSString *)midiUrl {
  928. NSData *sourceData = [NSData dataWithContentsOfURL:fileUrl];
  929. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  930. NSString *filePath= [cachePath stringByAppendingPathComponent:@"MidiSong"];
  931. // 先创建子目录
  932. NSFileManager *fileManager = [NSFileManager defaultManager];
  933. if (![fileManager fileExistsAtPath:filePath]) {
  934. [fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
  935. }else{
  936. NSLog(@"已创建文件夹");
  937. }
  938. NSString *fileName = [midiUrl getUrlFileName];
  939. NSString *tempPath = [filePath stringByAppendingPathComponent:fileName];
  940. BOOL success = [sourceData writeToFile:tempPath atomically:NO];
  941. return success;
  942. }
  943. - (NSString *)getFilePathWithName:(NSString *)fileName {
  944. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  945. NSString *filePath= [cachePath stringByAppendingPathComponent:@"MidiSong"];
  946. return [filePath stringByAppendingPathComponent:fileName];;
  947. }
  948. - (BOOL)checkSongHasSaveWithSongUrl:(NSString *)songUrl {
  949. BOOL hasSaveFile = NO;
  950. NSString *fileName = [songUrl getUrlFileName];
  951. NSString *filePath = [self getFilePathWithName:fileName];
  952. NSFileManager *fileManager = [NSFileManager defaultManager];
  953. if ([fileManager fileExistsAtPath:filePath]) {
  954. hasSaveFile = YES;
  955. }
  956. return hasSaveFile;
  957. }
  958. - (void)sendMessageToSocket:(NSDictionary *)parm {
  959. NSString *messageHeader = @"proxyMessage";
  960. NSString *sendMessage = [self configDataCommond:messageHeader body:[parm ks_dictionaryValueForKey:@"content"]];
  961. [self sendDataToSocketService:sendMessage];
  962. }
  963. - (void)configAudioDeviceType:(NSDictionary *)parm {
  964. AUDIODEVICE_TYPE type = [KSAQRecordManager queryAudioOutputDeviceType];
  965. NSString *valueStr = @"";
  966. BOOL checkIsWired = NO;
  967. switch (type) {
  968. case AUDIODEVICE_TYPE_HEADPHONE:
  969. {
  970. valueStr = @"有线耳机";
  971. checkIsWired = YES;
  972. }
  973. break;
  974. case AUDIODEVICE_TYPE_BLUETOOTH:
  975. {
  976. valueStr = @"蓝牙耳机";
  977. checkIsWired = YES;
  978. }
  979. break;
  980. case AUDIODEVICE_TYPE_NONE:
  981. {
  982. valueStr = @"";
  983. checkIsWired = NO;
  984. }
  985. break;
  986. default:
  987. break;
  988. }
  989. NSMutableDictionary *valueDic = [NSMutableDictionary dictionaryWithDictionary:[parm ks_dictionaryValueForKey:@"content"]];
  990. [valueDic setValue:valueStr forKey:@"type"];
  991. [valueDic setValue:[NSNumber numberWithBool:checkIsWired] forKey:@"checkIsWired"];
  992. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:parm];
  993. [sendParm setValue:valueDic forKey:@"content"];
  994. [self postMessage:sendParm];
  995. }
  996. - (void)startRecordService {
  997. if (self.AQManager.isRunning) {
  998. [self.AQManager stopRecord];
  999. }
  1000. [self.AQManager startRecord];
  1001. }
  1002. - (void)stopRecordService {
  1003. if (self.AQManager.isRunning) {
  1004. [self.AQManager stopRecord];
  1005. }
  1006. }
  1007. - (void)puaseRecordService {
  1008. if (self.AQManager.isRunning) {
  1009. [self.AQManager pauserRecord];
  1010. }
  1011. }
  1012. - (void)resumeRecordService {
  1013. [self.AQManager resumeRecord];
  1014. }
  1015. - (void)sendEndMessage {
  1016. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1017. // 上传停止的信息 发送给服务端
  1018. NSString *endMessage = @"recordEnd";
  1019. NSString *endData = [self configDataCommond:endMessage body:nil type:@"SOUND_COMPARE"];
  1020. [self sendDataToSocketService:endData];
  1021. self.isCompareStart = NO;
  1022. NSLog(@"---- send end message");
  1023. });
  1024. }
  1025. - (void)sendAdjustEndMessage {
  1026. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1027. // 上传停止的信息 发送给服务端
  1028. NSString *endMessage = @"recordEnd";
  1029. NSString *endData = [self configDataCommond:endMessage body:nil type:@"DELAY_CHECK"];
  1030. [self sendDataToSocketService:endData];
  1031. self.isDelayCheckStart = NO;
  1032. NSLog(@"---- send adjust end message");
  1033. });
  1034. }
  1035. - (void)sendOffsetTimeToService {
  1036. // 上传停止的信息 发送给服务端
  1037. NSString *offsetMessage = @"audioPlayStart";
  1038. NSTimeInterval micDelay = [UserDefault(@"micDelay") doubleValue];
  1039. NSDictionary *dic = @{@"offsetTime" : [NSNumber numberWithInteger:self.offsetTime], @"micDelay": [NSNumber numberWithInteger:micDelay]};
  1040. NSString *endData = [self configDataCommond:offsetMessage body:dic type:@"SOUND_COMPARE"];
  1041. NSLog(@"------ %@", endData);
  1042. [self sendDataToSocketService:endData];
  1043. self.isCompareStart = NO;
  1044. }
  1045. #pragma mark-------- KSAQRecordManagerDelegate
  1046. - (void)recordInterruption {
  1047. NSDictionary *postParm = @{@"api" : @"cancelEvaluating",
  1048. @"content" : @{@"reson":@"录制错误,请重试"}
  1049. };
  1050. [self postMessage:postParm];
  1051. }
  1052. - (void)audioRouteChange:(AUDIODEVICE_TYPE)type {
  1053. NSString *valueStr = @"";
  1054. BOOL checkIsWired = NO;
  1055. switch (type) {
  1056. case AUDIODEVICE_TYPE_HEADPHONE:
  1057. {
  1058. valueStr = @"有线耳机";
  1059. checkIsWired = YES;
  1060. }
  1061. break;
  1062. case AUDIODEVICE_TYPE_BLUETOOTH:
  1063. {
  1064. valueStr = @"蓝牙耳机";
  1065. checkIsWired = YES;
  1066. }
  1067. break;
  1068. case AUDIODEVICE_TYPE_NONE:
  1069. {
  1070. valueStr = @"";
  1071. checkIsWired = NO;
  1072. }
  1073. break;
  1074. default:
  1075. break;
  1076. }
  1077. NSDictionary *postParm = @{@"api" : @"listenerWiredStatus",
  1078. @"content" : @{@"type":valueStr,
  1079. @"checkIsWired":[NSNumber numberWithBool:checkIsWired]
  1080. }
  1081. };
  1082. [self postMessage:postParm];
  1083. }
  1084. #pragma mark ------- 评测app播放
  1085. /*
  1086. - (void)recordDidStart:(NSTimeInterval)time { // ms
  1087. self.recordStartTime = time;
  1088. if (self.isDelayCheckStart) {
  1089. NSLog(@"---- delay - record did start %f", time);
  1090. // 播放音频
  1091. // 播放校音音频
  1092. dispatch_main_sync_safe(^{
  1093. if (self.checkIndex % 2 == 0) {
  1094. [self.dongPlayer startPlay];
  1095. }
  1096. else {
  1097. [self.dingPlayer startPlay];
  1098. }
  1099. });
  1100. }
  1101. else if (self.isCompareStart) {
  1102. NSLog(@"---- compare - record did start %f", time);
  1103. // 播放伴奏
  1104. dispatch_main_sync_safe(^{
  1105. [self.musicPlayer startPlay];
  1106. });
  1107. }
  1108. }
  1109. */
  1110. - (void)audioRecord:(KSAQRecordManager *)audioRecord didRecordAudioData:(void *)data length:(UInt32)length {
  1111. if (self.socketManager.socketReadyState != SR_OPEN) {
  1112. return;
  1113. }
  1114. NSData *pushData = [[NSData alloc] initWithBytes:data length:length];
  1115. if (self.isCompareStart) { // 发送评测开始消息
  1116. dispatch_async(dispatch_get_main_queue(), ^{
  1117. NSDate *date = [NSDate date];
  1118. NSTimeInterval inteveral = [date timeIntervalSince1970];
  1119. double beginTime = inteveral - audioRecord.sampleTime;
  1120. NSDictionary *parm = @{
  1121. @"api" : @"recordStartTime",
  1122. @"content" : @{@"inteveral" : [NSNumber numberWithDouble:beginTime]}
  1123. };
  1124. [self postMessage:parm];
  1125. });
  1126. NSLog(@"--------- send start message");
  1127. _isCompareStart = NO;
  1128. NSString *startMessage = @"recordStart";
  1129. NSString *startString = [self configDataCommond:startMessage body:nil type:@"SOUND_COMPARE"];
  1130. [self sendDataToSocketService:startString];
  1131. }
  1132. else if (self.isSoundCheckStart) { // 校音开始
  1133. NSLog(@"--------- send check start message");
  1134. _isSoundCheckStart = NO;
  1135. NSString *checkStartMessage = @"start";
  1136. NSString *startString = [self configDataCommond:checkStartMessage body:nil type:@"PITCH_DETECTION"];
  1137. [self sendDataToSocketService:startString];
  1138. }
  1139. else if (self.isDelayCheckStart) {
  1140. NSLog(@"--------- send delay check start message");
  1141. _isDelayCheckStart = NO;
  1142. NSString *checkStartMessage = @"recordStart";
  1143. NSInteger frequence = 0.0f;
  1144. if (self.checkIndex % 2 == 0) {
  1145. frequence = self.secondFrequence;
  1146. }
  1147. else {
  1148. frequence = self.firstFrequence;
  1149. }
  1150. NSDictionary *parm = @{@"HZ" : @(frequence)};
  1151. NSString *startString = [self configDataCommond:checkStartMessage body:parm type:@"DELAY_CHECK"];
  1152. [self sendDataToSocketService:startString];
  1153. }
  1154. // NSLog(@"--------- send audio data length %d", length);
  1155. [self sendDataToSocketService:pushData];
  1156. }
  1157. - (NSString *)configDataCommond:(NSString *)commond body:(id)bodyMessage type:(NSString *)dataType {
  1158. NSMutableDictionary *parm = [NSMutableDictionary dictionary];
  1159. if (bodyMessage) {
  1160. [parm setValue:bodyMessage forKey:@"body"];
  1161. }
  1162. NSMutableDictionary *headerParm = [NSMutableDictionary dictionary];
  1163. if ([NSString isEmptyString:commond]) {
  1164. [headerParm setValue:@"" forKey:@"commond"];
  1165. }
  1166. else {
  1167. [headerParm setValue:commond forKey:@"commond"];
  1168. }
  1169. if (![NSString isEmptyString:dataType]) {
  1170. [headerParm setValue:dataType forKey:@"type"];
  1171. }
  1172. [headerParm setValue:@(200) forKey:@"status"];
  1173. [parm setValue:headerParm forKey:@"header"];
  1174. return [parm mj_JSONString];
  1175. }
  1176. - (NSString *)configDataCommond:(NSString *)commond body:(id)bodyMessage {
  1177. NSMutableDictionary *parm = [NSMutableDictionary dictionary];
  1178. if (bodyMessage) {
  1179. [parm setValue:bodyMessage forKey:@"body"];
  1180. }
  1181. if ([NSString isEmptyString:commond]) {
  1182. [parm setValue:@{@"commond":@""} forKey:@"header"];
  1183. }
  1184. else {
  1185. [parm setValue:@{@"commond":commond} forKey:@"header"];
  1186. }
  1187. return [parm mj_JSONString];
  1188. }
  1189. - (KSWebSocketManager *)socketManager {
  1190. if (!_socketManager) {
  1191. _socketManager = [[KSWebSocketManager alloc] init];
  1192. }
  1193. return _socketManager;
  1194. }
  1195. #pragma mark --- lazying
  1196. - (UIView *)viewContainer {
  1197. if (!_viewContainer) {
  1198. _viewContainer = [[UIView alloc] init];
  1199. }
  1200. return _viewContainer;
  1201. }
  1202. - (KSVideoRecordManager *)videoRecordManager {
  1203. if (!_videoRecordManager) {
  1204. MJWeakSelf;
  1205. _videoRecordManager = [[KSVideoRecordManager alloc] initSessionRecordCallback:^(BOOL isSuccess, NSString * _Nullable message) {
  1206. if (isSuccess) {
  1207. [weakSelf showSuccessMessage:message];
  1208. }
  1209. else {
  1210. if (![NSString isEmptyString:message]) {
  1211. [LOADING_MANAGER MBShowAUTOHidingInWindow:message];
  1212. }
  1213. }
  1214. }];
  1215. }
  1216. return _videoRecordManager;
  1217. }
  1218. - (void)showSuccessMessage:(NSString *)message {
  1219. if (![NSString isEmptyString:message]) {
  1220. [LOADING_MANAGER MBShowAUTOHidingInWindow:message];
  1221. }
  1222. // 成功
  1223. if (self.endRecordParm) {
  1224. [self postMessage:self.endRecordParm];
  1225. self.endRecordParm = nil;
  1226. }
  1227. }
  1228. - (MetronomeType)getBeatTypeFromString:(NSString *)typeString {
  1229. if ([typeString isEqualToString:@"1/4"]) {
  1230. return MetronomeType1V4;
  1231. }
  1232. else if ([typeString isEqualToString:@"2/4"]) {
  1233. return MetronomeType2V4;
  1234. }
  1235. else if ([typeString isEqualToString:@"3/4"]) {
  1236. return MetronomeType3V4;
  1237. }
  1238. else if ([typeString isEqualToString:@"4/4"]) {
  1239. return MetronomeType4V4;
  1240. }
  1241. else if ([typeString isEqualToString:@"3/8"]) {
  1242. return MetronomeType3V8;
  1243. }
  1244. else if ([typeString isEqualToString:@"6/8"]) {
  1245. return MetronomeType6V8;
  1246. }
  1247. else {
  1248. return MetronomeType4V4;
  1249. }
  1250. }
  1251. #pragma mark ------- midi 播放相关
  1252. - (void)configPlayerEngineWithSong:(NSString *)songPath reportTime:(NSInteger)reportTime {
  1253. self.initEngineSuccess = NO;
  1254. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  1255. self.playerEngine = [[MidiPlayerEngine alloc] init];
  1256. self.playerEngine.reportTime = reportTime;
  1257. self.playerEngine.delegate = self;
  1258. [self.playerEngine configSoundFilePath:[[NSBundle mainBundle]
  1259. pathForResource:@"synthgms" ofType:@"sf2"]];
  1260. [self.playerEngine loadMIDIFileWithString:songPath];
  1261. });
  1262. }
  1263. - (void)configAudioSession {
  1264. self.audioSessionManager = [[KSAudioSessionManager alloc] init];
  1265. self.audioSessionManager.delegate = self;
  1266. [self.audioSessionManager configAudioSession:AUDIOCONFIG_PLAYANDRECORD];
  1267. }
  1268. #pragma mark ---- PlayerEngineDelegate
  1269. /** 进度更新
  1270. api: 'cloudTimeUpdae',
  1271. content: {
  1272. // 当前曲目id
  1273. songID: 0,
  1274. // 当前位置时间(ms)
  1275. currentTime: 0
  1276. }
  1277. */
  1278. /** 播放结束事件
  1279. api: 'cloudplayed',
  1280. content: {
  1281. // 当前曲目id
  1282. songID: 0,
  1283. }
  1284. */
  1285. - (void)ProgressUpdated:(float)progress currentTime:(MusicTimeStamp)currentTime {
  1286. if (self.isPlaying == NO) {
  1287. return;
  1288. }
  1289. // 回调
  1290. NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
  1291. [sendParm setValue:@"cloudTimeUpdae" forKey:@"api"];
  1292. NSMutableDictionary *content = [NSMutableDictionary dictionary];
  1293. [content setValue:self.currentSongId forKey:@"songID"];
  1294. [content setValue:@(currentTime*1000) forKey:@"currentTime"];
  1295. [sendParm setValue:content forKey:@"content"];
  1296. [self postMessage:sendParm];
  1297. }
  1298. - (void)playEnd {
  1299. [self stopPlayAction];
  1300. NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
  1301. [sendParm setValue:@"cloudplayed" forKey:@"api"];
  1302. NSMutableDictionary *content = [NSMutableDictionary dictionary];
  1303. [content setValue:self.currentSongId forKey:@"songID"];
  1304. [sendParm setValue:content forKey:@"content"];
  1305. [self postMessage:sendParm];
  1306. }
  1307. - (void)initPlayerEngineSuccess:(float)totalTime {
  1308. self.initEngineSuccess = YES;
  1309. if (self.configEngineParm) {
  1310. NSMutableDictionary *sendParm = [NSMutableDictionary dictionaryWithDictionary:self.configEngineParm];
  1311. NSMutableDictionary *content = [NSMutableDictionary dictionaryWithDictionary:[sendParm ks_dictionaryValueForKey:@"content"]];
  1312. [content setValue:@(totalTime*1000) forKey:@"midiDuration"];
  1313. [sendParm setValue:content forKey:@"content"];
  1314. [self postMessage:sendParm];
  1315. self.configEngineParm = nil;
  1316. }
  1317. }
  1318. // 总时长
  1319. - (void)GetMusicTotalTime:(float)time {
  1320. }
  1321. #pragma mark ----- 播放控制
  1322. - (void)playAction {
  1323. if (self.playerEngine) {
  1324. self.isPlaying = YES;
  1325. [self.playerEngine playMIDIFile];
  1326. }
  1327. }
  1328. - (void)stopPlayAction {
  1329. if (self.playerEngine) {
  1330. self.isPlaying = NO;
  1331. if ([self.playerEngine isPlayingFile]) {
  1332. [self.playerEngine stopPlayingMIDIFile];
  1333. }
  1334. }
  1335. }
  1336. #pragma mark ----- 小酷AI loading
  1337. - (AccompanyLoadingView *)loadingView {
  1338. if (!_loadingView) {
  1339. _loadingView = [AccompanyLoadingView shareInstance];
  1340. MJWeakSelf;
  1341. [_loadingView loadingCallback:^{
  1342. [weakSelf backAction];
  1343. }];
  1344. }
  1345. return _loadingView;
  1346. }
  1347. - (void)showCustomLoading {
  1348. if ([self.view.subviews containsObject:self.loadingView]) {
  1349. return;
  1350. }
  1351. [self.view addSubview:self.loadingView];
  1352. [self.loadingView mas_makeConstraints:^(MASConstraintMaker *make) {
  1353. make.left.top.right.bottom.mas_equalTo(self.view);
  1354. }];
  1355. [self.view bringSubviewToFront:self.loadingView];
  1356. [self.loadingView showLoading];
  1357. }
  1358. - (void)removeCustomLoadingView {
  1359. [self.loadingView stopLoading];
  1360. }
  1361. #pragma mark ----- 跟音模块
  1362. - (void)startTuner {
  1363. if (self.isTunerRuning == NO) {
  1364. self.isTunerRuning = YES;
  1365. [self.tuner start];
  1366. }
  1367. }
  1368. - (void)stopTuner {
  1369. if (self.isTunerRuning) {
  1370. self.isTunerRuning = NO;
  1371. [self.tuner stop];
  1372. }
  1373. }
  1374. - (Tuner *)tuner {
  1375. if (!_tuner) {
  1376. _tuner = [[Tuner alloc] initWithThreshold:0 smoothing:0.25];
  1377. _tuner.delegate = self;
  1378. }
  1379. return _tuner;
  1380. }
  1381. - (void)tunerDidUpdate:(Tuner *)tuner output:(TunerOutput *)output {
  1382. if (output.amplitude < 0.01) {
  1383. }
  1384. else {
  1385. // 回调频率
  1386. NSDictionary *parm = @{
  1387. @"api" : @"cloudFollowTime",
  1388. @"content" : @{@"frequency" : [NSNumber numberWithDouble:output.frequency]}
  1389. };
  1390. [self postMessage:parm];
  1391. }
  1392. NSLog(@"-------- %@%zd --- distance :%f frequence : %f" , output.pitch, output.octave, output.distance, output.frequency);
  1393. }
  1394. #pragma mark ---- 保存伴奏
  1395. - (BOOL)saveAccompanyFileWithUrl:(NSURL *)fileUrl accompanyUrl:(NSString *)accompanyUrl {
  1396. NSData *sourceData = [NSData dataWithContentsOfURL:fileUrl];
  1397. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  1398. NSString *filePath= [cachePath stringByAppendingPathComponent:@"AccompanySong"];
  1399. // 先创建子目录
  1400. NSFileManager *fileManager = [NSFileManager defaultManager];
  1401. if (![fileManager fileExistsAtPath:filePath]) {
  1402. [fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
  1403. }else{
  1404. NSLog(@"已创建文件夹");
  1405. }
  1406. NSString *fileName = [accompanyUrl getUrlFileName];
  1407. NSString *tempPath = [filePath stringByAppendingPathComponent:fileName];
  1408. BOOL success = [sourceData writeToFile:tempPath atomically:NO];
  1409. return success;
  1410. }
  1411. - (NSString *)getAccompanyFilePathWithName:(NSString *)fileName {
  1412. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  1413. NSString *filePath= [cachePath stringByAppendingPathComponent:@"AccompanySong"];
  1414. return [filePath stringByAppendingPathComponent:fileName];;
  1415. }
  1416. - (BOOL)checkSongHasSaveAccompanyWithSongUrl:(NSString *)songUrl {
  1417. BOOL hasSaveFile = NO;
  1418. NSString *fileName = [songUrl getUrlFileName];
  1419. NSString *filePath = [self getAccompanyFilePathWithName:fileName];
  1420. NSFileManager *fileManager = [NSFileManager defaultManager];
  1421. if ([fileManager fileExistsAtPath:filePath]) {
  1422. hasSaveFile = YES;
  1423. }
  1424. return hasSaveFile;
  1425. }
  1426. #pragma mark ---- player
  1427. - (void)configPlayerDelegate {
  1428. self.dingPlayer.delegate = self;
  1429. self.dongPlayer.delegate = self;
  1430. self.musicPlayer.delegate = self;
  1431. }
  1432. - (kSNewPlayer *)dingPlayer {
  1433. if (!_dingPlayer) {
  1434. _dingPlayer = [[kSNewPlayer alloc] init];
  1435. }
  1436. return _dingPlayer;
  1437. }
  1438. - (kSNewPlayer *)dongPlayer {
  1439. if (!_dongPlayer) {
  1440. _dongPlayer = [[kSNewPlayer alloc] init];
  1441. }
  1442. return _dongPlayer;
  1443. }
  1444. - (kSNewPlayer *)musicPlayer {
  1445. if (!_musicPlayer) {
  1446. _musicPlayer = [[kSNewPlayer alloc] init];
  1447. }
  1448. return _musicPlayer;
  1449. }
  1450. #pragma mark ---- new player delegate
  1451. - (void)getSongCurrentTime:(NSInteger)currentTime andTotalTime:(NSInteger)totalTime andProgress:(CGFloat)progress currentInterval:(NSTimeInterval)currentInterval playTime:(NSTimeInterval)playTime inPlayer:(kSNewPlayer *)player {
  1452. if (player == self.dingPlayer || player == self.dongPlayer) {
  1453. if (playTime >= 300 && playTime < 310 && self.recordStartTime > 0) {
  1454. NSLog(@" --- check player start play time %f", currentInterval*1000 - playTime);
  1455. self.playerStartTime = currentInterval*1000 - playTime;
  1456. self.offsetTime = self.playerStartTime - self.recordStartTime;
  1457. NSLog(@"--------- check player offset time -- %zd", self.offsetTime);
  1458. }
  1459. }
  1460. if (playTime >= 300 && playTime < 310 && player == self.musicPlayer) {
  1461. if (self.recordStartTime > 0) {
  1462. NSLog(@" --- music player start play time %f", currentInterval*1000 - playTime);
  1463. self.playerStartTime = currentInterval*1000 - playTime;
  1464. self.offsetTime = self.playerStartTime - self.recordStartTime;
  1465. NSLog(@"--------- music play offset time -- %zd", self.offsetTime);
  1466. [self sendOffsetTimeToService];
  1467. }
  1468. NSLog(@"------- record start time %f", self.recordStartTime);
  1469. }
  1470. // 回调进度
  1471. if (player == self.musicPlayer) {
  1472. // NSLog(@"------ music play progress - %f", progress);
  1473. // 回调进度
  1474. NSDictionary *parm = @{
  1475. @"api" : @"playProgress",
  1476. @"content" : @{@"currentTime" : [NSNumber numberWithInteger:currentTime],
  1477. @"totalDuration" : [NSNumber numberWithInteger:totalTime],
  1478. }
  1479. };
  1480. // NSLog(@" -----music play progress %@---- ", parm);
  1481. [self postMessage:parm];
  1482. }
  1483. }
  1484. - (void)sendPlayerReadyMsg {
  1485. if (self.playerParm) {
  1486. [self postMessage:self.playerParm];
  1487. }
  1488. }
  1489. - (void)preparePlay:(kSNewPlayer *)player {
  1490. if (player == self.musicPlayer) {
  1491. self.musicPlayerReady = YES;
  1492. }
  1493. else if (player == self.dingPlayer) {
  1494. self.dingPlayerReady = YES;
  1495. }
  1496. else if (player == self.dongPlayer) {
  1497. self.dongPlayerReady = YES;
  1498. }
  1499. // 如果都准备好
  1500. if (self.musicPlayerReady && self.dingPlayerReady && self.dongPlayerReady) {
  1501. [self sendPlayerReadyMsg];
  1502. }
  1503. }
  1504. - (NSMutableArray *)delayArray {
  1505. if (!_delayArray) {
  1506. _delayArray = [NSMutableArray array];
  1507. }
  1508. return _delayArray;
  1509. }
  1510. /*
  1511. #pragma mark - Navigation
  1512. // In a storyboard-based application, you will often want to do a little preparation before navigation
  1513. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  1514. // Get the new view controller using [segue destinationViewController].
  1515. // Pass the selected object to the new view controller.
  1516. }
  1517. */
  1518. @end