KSAccompanyWebViewController.m 72 KB

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