KSMediaMergeView.m 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. //
  2. // KSMediaMergeView.m
  3. // KulexiuSchoolStudent
  4. //
  5. // Created by 王智 on 2023/8/29.
  6. //
  7. #import "KSMediaMergeView.h"
  8. #import "KSMergeAudioControlView.h"
  9. #import "KSAudioAnimationView.h"
  10. #import <KSToolLibrary/KSMediaEditor.h>
  11. #import "KSPlayerView.h"
  12. #import "KSPlayerSliderView.h"
  13. #import <CloudAccompanyLibrary/kSNewPlayer.h>
  14. #import "KSVideoPlayerView.h"
  15. #import "KSAudioPlayAnimationView.h"
  16. #import "KSNewAlertView.h"
  17. #import "MusicPublistAlert.h"
  18. #import "KSMediaManager.h"
  19. #import <RSKImageCropper/RSKImageCropper.h>
  20. #import "KSVideoCropViewController.h"
  21. #import <KSToolLibrary/KSAudioSessionManager.h>
  22. @interface KSMediaMergeView ()<kSNewPlayerManagerDelegate,KSVideoPlayerViewDelegate,RSKImageCropViewControllerDelegate,RSKImageCropViewControllerDataSource>
  23. @property (nonatomic, strong) KSAudioAnimationView *animationView;
  24. @property (nonatomic, strong) KSMergeAudioControlView *contrlView;
  25. @property (nonatomic, strong) NSURL *videoUrl;
  26. @property (nonatomic, strong) NSURL *bgAudioUrl;
  27. @property (nonatomic, strong) NSURL *recordUrl;
  28. @property (nonatomic, assign) NSInteger offsetTime;
  29. @property (nonatomic, strong) KSPlayerView *playerView;
  30. @property (nonatomic, strong) KSPlayerSliderView *playControlView;
  31. @property (nonatomic, strong) kSNewPlayer *bgPlayer;
  32. @property (nonatomic, strong) kSNewPlayer *recordPlayer;
  33. @property (nonatomic, assign) BOOL isPause;
  34. @property (nonatomic, strong) NSString *filePath;
  35. @property (nonatomic, assign) NSInteger originalOffset;
  36. @property (nonatomic, strong) KSVideoPlayerView *videoView;
  37. @property (nonatomic, assign) BOOL isVideoPlay;
  38. @property (nonatomic, assign) BOOL isHideControlView;
  39. @property (nonatomic, strong) UIButton *showButton;
  40. @property (nonatomic, strong) KSAudioPlayAnimationView *playAnimationView;
  41. @property (nonatomic, strong) NSTimer *timer;
  42. // 远端资源
  43. @property (nonatomic, strong) NSString *remoteVideoUrl;
  44. @property (nonatomic, strong) NSString *remoteBgAudioUrl;
  45. @property (nonatomic, strong) NSString *remoteRecrodUrl;
  46. @property (nonatomic, strong) NSString *jsonConfig;
  47. @property (nonatomic, assign) NSInteger originalVolume;
  48. @property (nonatomic, assign) NSInteger accompanyVolume;
  49. @property (nonatomic, strong) dispatch_group_t requestGroup;
  50. @property (nonatomic, copy) DraftEditCallback draftCallback;
  51. @property (nonatomic, strong) NSDictionary *preJsonDic;
  52. @property (nonatomic, strong) KSNewAlertView *alertView;
  53. @property (nonatomic, assign) BOOL hasSave;
  54. @property (nonatomic, copy) MergeCallback mergeCallback;
  55. @property (nonatomic, strong) MusicPublistAlert *publishAlert;
  56. @property (nonatomic, strong) KSMediaManager *mediaManager;
  57. @property (nonatomic, strong) UIImage *settingImage; // 图片
  58. @property (nonatomic, assign) BOOL hasModify;
  59. @property (nonatomic, strong) UIImage *videoCoverImage;
  60. @property (nonatomic, assign) BOOL isChooseVideoCover;
  61. @property (nonatomic, strong) NSString *videoCoverUrl; // 视频封面
  62. @property (nonatomic, assign) BOOL isOtherLogin;
  63. @property (nonatomic, assign) NSInteger defaultDelay;
  64. @property (nonatomic, assign) CGFloat bgPlayerRate;
  65. @property (nonatomic, assign) NSInteger addTime;
  66. //@property (nonatomic, strong) UILabel *offsetTimeLabel;
  67. @property (nonatomic, assign) NSInteger evaluateDelay;
  68. @property (nonatomic, assign) BOOL fromDraftPage; // 是否从草稿页面进入
  69. @end
  70. @implementation KSMediaMergeView
  71. - (instancetype)init {
  72. self = [super init];
  73. if (self) {
  74. self.hasModify = NO;
  75. self.bgPlayerRate = 1.0;
  76. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterBackground) name:@"appEnterBackground" object:nil];
  77. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherLogin) name:@"otherLogin" object:nil];
  78. self.addTime = 0;
  79. [self configAudioSession];
  80. }
  81. return self;
  82. }
  83. - (void)configAudioSession {
  84. [[[KSAudioSessionManager alloc] init] configAudioSession:AUDIOCONFIG_PLAYANDRECORD];
  85. }
  86. - (void)otherLogin {
  87. [self stopPlay];
  88. }
  89. - (void)appEnterBackground {
  90. [self stopPlay];
  91. }
  92. - (instancetype)initWithFrame:(CGRect)frame {
  93. self = [super initWithFrame:frame];
  94. if (self) {
  95. }
  96. return self;
  97. }
  98. - (void)configWithVideoUrl:(NSURL *)videoUrl bgAudioUrl:(NSURL *)bgAudioUrl remoteBgUrl:(NSString *)remoteBgUrl recordUrl:(NSURL *)recordUrl offsetTime:(NSInteger)offsetTime mergeCallback:(MergeCallback)callback {
  99. if (callback) {
  100. self.mergeCallback = callback;
  101. }
  102. if (videoUrl) {
  103. self.isVideoPlay = YES;
  104. }
  105. else {
  106. self.isVideoPlay = NO;
  107. }
  108. self.fromDraftPage = NO;
  109. self.remoteBgAudioUrl = remoteBgUrl;
  110. self.videoUrl = videoUrl;
  111. self.bgAudioUrl = bgAudioUrl;
  112. self.recordUrl = recordUrl;
  113. self.defaultDelay = -offsetTime; // default delay = evaluate delay
  114. self.evaluateDelay = -offsetTime; // 播放延迟和收音延迟
  115. self.originalOffset = 0;
  116. [self.contrlView configWithOffsetTime:0];
  117. self.contrlView.hideBackView = NO;
  118. [self configPlayer];
  119. [self configUI];
  120. }
  121. - (void)configRemoteVideoUrl:(NSString *)remoteVideoUrl bgAudioUrl:(NSString *)remoteBgAudioUrl recordUrl:(NSString *)remoteRecrodUrl jsonConfig:(NSString *)jsonConfig callback:(DraftEditCallback)callback {
  122. self.addTime = 0;
  123. if (callback) {
  124. self.draftCallback = callback;
  125. }
  126. if (![NSString isEmptyString:remoteVideoUrl]) {
  127. self.isVideoPlay = YES;
  128. }
  129. else {
  130. self.isVideoPlay = NO;
  131. }
  132. self.fromDraftPage = YES;
  133. self.remoteVideoUrl = remoteVideoUrl;
  134. self.remoteBgAudioUrl = remoteBgAudioUrl;
  135. self.remoteRecrodUrl = remoteRecrodUrl;
  136. self.preJsonDic = [jsonConfig mj_JSONObject];
  137. self.originalOffset = [self.preJsonDic ks_integerValueForKey:@"offset"];
  138. self.defaultDelay = [self.preJsonDic ks_integerValueForKey:@"defaultDelay"];
  139. self.evaluateDelay = [self.preJsonDic ks_integerValueForKey:@"evaluateDelay"]; // 播放延迟和收音延迟
  140. self.offsetTime = self.originalOffset;
  141. [self.contrlView configWithOffsetTime:self.originalOffset];
  142. self.contrlView.hideBackView = YES;
  143. [self downloadFileSource];
  144. }
  145. - (void)downloadFileSource {
  146. [LOADING_MANAGER showCustomLoading:@"资源下载中"];
  147. [self downloadVideo];
  148. [self downloadAccompany];
  149. [self downloadAudio];
  150. dispatch_group_notify(self.requestGroup, dispatch_get_main_queue(), ^{
  151. [LOADING_MANAGER removeCustomLoading];
  152. [self configPlayer];
  153. [self configUI];
  154. });
  155. }
  156. - (void)downloadVideo {
  157. if (![NSString isEmptyString:self.remoteVideoUrl]) {
  158. dispatch_group_enter(self.requestGroup);
  159. [KSNetworkingManager downloadFileRequestWithFileUrl:self.remoteVideoUrl progress:^(int64_t bytesRead, int64_t totalBytes) {
  160. } success:^(NSURL * _Nonnull fileUrl) {
  161. dispatch_group_leave(self.requestGroup);
  162. self.videoUrl = fileUrl;
  163. } faliure:^(NSError * _Nonnull error) {
  164. dispatch_group_leave(self.requestGroup);
  165. }];
  166. }
  167. }
  168. - (void)downloadAudio {
  169. if (![NSString isEmptyString:self.remoteRecrodUrl]) {
  170. dispatch_group_enter(self.requestGroup);
  171. [KSNetworkingManager downloadFileRequestWithFileUrl:self.remoteRecrodUrl progress:^(int64_t bytesRead, int64_t totalBytes) {
  172. } success:^(NSURL * _Nonnull fileUrl) {
  173. dispatch_group_leave(self.requestGroup);
  174. self.recordUrl = fileUrl;
  175. } faliure:^(NSError * _Nonnull error) {
  176. dispatch_group_leave(self.requestGroup);
  177. }];
  178. }
  179. }
  180. - (void)downloadAccompany {
  181. if (![NSString isEmptyString:self.remoteBgAudioUrl]) {
  182. dispatch_group_enter(self.requestGroup);
  183. [KSNetworkingManager downloadFileRequestWithFileUrl:self.remoteBgAudioUrl progress:^(int64_t bytesRead, int64_t totalBytes) {
  184. } success:^(NSURL * _Nonnull fileUrl) {
  185. dispatch_group_leave(self.requestGroup);
  186. self.bgAudioUrl = fileUrl;
  187. } faliure:^(NSError * _Nonnull error) {
  188. dispatch_group_leave(self.requestGroup);
  189. }];
  190. }
  191. }
  192. - (void)configPlayer {
  193. if (self.bgAudioUrl) {
  194. [self.bgPlayer preparePlayNativeSongWithPath:self.bgAudioUrl];
  195. }
  196. if (self.recordUrl) {
  197. [self.recordPlayer preparePlayNativeSongWithPath:self.recordUrl];
  198. }
  199. if (self.isVideoPlay) {
  200. [self.videoView preparePlayNativeVideoWithPath:self.videoUrl];
  201. self.videoView.isMute = YES;
  202. }
  203. // 音量同步
  204. NSInteger accompanyVolume = 100;
  205. if ([[self.preJsonDic allKeys] containsObject:@"accompanyVolume"]) {
  206. accompanyVolume = [self.preJsonDic ks_integerValueForKey:@"accompanyVolume"];
  207. }
  208. self.accompanyVolume = accompanyVolume;
  209. self.bgPlayer.volume = accompanyVolume / 100.0;
  210. NSInteger originalVolume = 100;
  211. if ([[self.preJsonDic allKeys] containsObject:@"originalVolume"]) {
  212. originalVolume = [self.preJsonDic ks_integerValueForKey:@"originalVolume"];
  213. }
  214. self.originalVolume = originalVolume;
  215. self.recordPlayer.volume = originalVolume / 100.0;
  216. [self.contrlView configRecordVolume:originalVolume bgVolume:accompanyVolume];
  217. }
  218. - (void)configUI {
  219. self.backgroundColor = [UIColor whiteColor];
  220. if (self.isVideoPlay) {
  221. [self addSubview:self.videoView];
  222. }
  223. else {
  224. [self addSubview:self.playerView];
  225. }
  226. [self addSubview:self.showButton];
  227. self.showButton.hidden = YES;
  228. self.showButton.userInteractionEnabled = NO;
  229. [self addSubview:self.contrlView];
  230. [self.contrlView mas_makeConstraints:^(MASConstraintMaker *make) {
  231. make.right.top.bottom.mas_equalTo(self);
  232. make.width.mas_equalTo(289);
  233. }];
  234. if (self.isVideoPlay) {
  235. [self.videoView mas_makeConstraints:^(MASConstraintMaker *make) {
  236. make.left.top.bottom.mas_equalTo(self);
  237. make.right.mas_equalTo(self.contrlView.mas_left).offset(20);
  238. }];
  239. }
  240. else { // 音频
  241. // 添加投影
  242. UIImageView *shadowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"merge_music_bg"]];
  243. [self.playerView addSubview:shadowImage];
  244. [self.playerView addSubview:self.playAnimationView];
  245. [self.playAnimationView mas_makeConstraints:^(MASConstraintMaker *make) {
  246. make.centerX.mas_equalTo(self.playerView.mas_centerX);
  247. make.centerY.mas_equalTo(self.playerView.mas_centerY);
  248. make.width.mas_equalTo(424);
  249. make.height.mas_equalTo(80);
  250. }];
  251. [self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
  252. make.left.top.bottom.mas_equalTo(self);
  253. make.right.mas_equalTo(self.contrlView.mas_left).offset(20);
  254. }];
  255. [self.playerView addSubview:self.animationView];
  256. [self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
  257. make.centerX.mas_equalTo(self.playerView.mas_centerX);
  258. make.centerY.mas_equalTo(self.playerView.mas_centerY);
  259. make.width.height.mas_equalTo(200);
  260. }];
  261. [shadowImage mas_makeConstraints:^(MASConstraintMaker *make) {
  262. make.width.mas_equalTo(284);
  263. make.height.mas_equalTo(151);
  264. make.centerX.mas_equalTo(self.playerView.mas_centerX);
  265. make.top.mas_equalTo(self.animationView.mas_top).offset(86);
  266. }];
  267. [self.animationView configWithImageWithUrl:self.coverImage];
  268. }
  269. [self addSubview:self.playControlView];
  270. [self.playControlView mas_makeConstraints:^(MASConstraintMaker *make) {
  271. make.left.mas_equalTo(self.mas_left);
  272. make.right.mas_equalTo(self.contrlView.mas_left).offset(-20);
  273. make.height.mas_equalTo(44);
  274. make.bottom.mas_equalTo(self.mas_bottom).offset(-30);
  275. }];
  276. [self.playControlView configViewDisplayColor:self.isVideoPlay];
  277. NSString *imgName = self.isVideoPlay ? @"back_button_white" : @"back_black";
  278. UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
  279. [backButton setImage:[UIImage imageNamed:imgName] forState:UIControlStateNormal];
  280. [backButton addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside];
  281. [self addSubview:backButton];
  282. [backButton mas_makeConstraints:^(MASConstraintMaker *make) {
  283. make.width.height.mas_equalTo(44);
  284. make.left.mas_equalTo(self.mas_left).offset(10);
  285. make.top.mas_equalTo(self.mas_top).offset(10);
  286. }];
  287. float totalTime = [self.recordPlayer getTotalDuration];
  288. [self.playControlView configWithDuration:totalTime];
  289. UILabel *songLabel = [[UILabel alloc] init];
  290. songLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightSemibold];
  291. songLabel.text = [NSString returnNoNullStringWithString:self.songName];
  292. songLabel.textColor = self.isVideoPlay ? HexRGB(0xffffff) : HexRGB(0x131415);
  293. [self addSubview:songLabel];
  294. [songLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  295. make.left.mas_equalTo(backButton.mas_right);
  296. make.centerY.mas_equalTo(backButton.mas_centerY);
  297. make.height.mas_equalTo(22);
  298. make.right.mas_greaterThanOrEqualTo(self.contrlView.mas_left).offset(20);
  299. }];
  300. // self.offsetTimeLabel = [[UILabel alloc] init];
  301. // self.offsetTimeLabel.font = [UIFont systemFontOfSize:14.0f weight:UIFontWeightSemibold];
  302. // self.offsetTimeLabel.textColor = self.isVideoPlay ? HexRGB(0xffffff) : HexRGB(0x131415);
  303. // [self addSubview:self.offsetTimeLabel];
  304. // [self.offsetTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
  305. // make.height.mas_equalTo(22);
  306. // make.centerX.mas_equalTo(self.mas_centerX);
  307. // make.centerY.mas_equalTo(songLabel.mas_centerY);
  308. // }];
  309. // [self startPlay];
  310. // 缓冲完成后播放
  311. }
  312. - (void)backAction {
  313. if (self.hasModify) {
  314. MJWeakSelf;
  315. [self.alertView configTitle:@"提示" descMessage:@"是否将本次录制的作品保存为草稿?" leftButtonTitle:@"取消" rightButtonTitle:@"确认" leftButtonAction:^{
  316. [weakSelf removeViewTips:NO];
  317. } rightButtonAction:^{
  318. [weakSelf saveCurrentDraft:YES];
  319. }];
  320. [self.alertView showAlert];
  321. }
  322. else {
  323. if (self.mergeCallback) {
  324. [self removeViewTips:NO];
  325. }
  326. else {
  327. [self removeView];
  328. }
  329. }
  330. }
  331. #pragma mark ----- lazying
  332. - (KSAudioAnimationView *)animationView {
  333. if (!_animationView) {
  334. _animationView = [KSAudioAnimationView shareInstance];
  335. }
  336. return _animationView;
  337. }
  338. - (KSPlayerView *)playerView {
  339. if (!_playerView) {
  340. _playerView = [[KSPlayerView alloc] init];
  341. }
  342. return _playerView;
  343. }
  344. - (KSPlayerSliderView *)playControlView {
  345. if (!_playControlView) {
  346. _playControlView = [KSPlayerSliderView shareInstance];
  347. MJWeakSelf;
  348. [_playControlView sliderControlAction:^(PLAYERTYPE type, NSInteger rate) {
  349. [weakSelf playSliderAction:type rate:rate];
  350. }];
  351. }
  352. return _playControlView;
  353. }
  354. - (void)startPlay {
  355. self.bgPlayerRate = 1.0;
  356. self.playControlView.isPlay = YES;
  357. self.animationView.isPlay = YES;
  358. NSInteger recordPlayerPosition = self.playControlView.playScheduleTime*1000;
  359. [self.recordPlayer seekToTimePlay:recordPlayerPosition];
  360. NSInteger realOffsetTime = self.offsetTime + self.evaluateDelay;
  361. NSInteger offsetTime = recordPlayerPosition + realOffsetTime;
  362. if (offsetTime >= 0) {
  363. [self.bgPlayer seekToTimePlay:offsetTime];
  364. }
  365. else {
  366. [self.bgPlayer seekToStart];
  367. @weakObj(self);
  368. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((labs(offsetTime) + self.addTime) * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
  369. @strongObj(self);
  370. // NSLog(@"--bgPlayer start---");
  371. if (self.playControlView.isPlay == YES) {
  372. [self.bgPlayer resumePlay];
  373. [self snapPlayerProgress];
  374. }
  375. });
  376. }
  377. if (self.isVideoPlay) {
  378. [self.videoView seekToTimePlay:recordPlayerPosition];
  379. }
  380. else {
  381. [self.playAnimationView startAnimation];
  382. [self startTimer];
  383. }
  384. }
  385. - (void)stopPlay {
  386. self.animationView.isPlay = NO;
  387. self.playControlView.isPlay = NO;
  388. [self.bgPlayer puasePlay];
  389. [self.recordPlayer puasePlay];
  390. if (self.isVideoPlay) {
  391. [self.videoView puasePlay];
  392. }
  393. else {
  394. [self.playAnimationView stopAnimation];
  395. [self stopTimer];
  396. }
  397. }
  398. - (void)playSliderAction:(PLAYERTYPE)type rate:(NSInteger)rate {
  399. switch (type) {
  400. case PLAYERTYPE_PLAY:
  401. {
  402. [self startPlay];
  403. }
  404. break;
  405. case PLAYERTYPE_PAUSE:
  406. {
  407. [self stopPlay];
  408. }
  409. break;
  410. case PLAYERTYPE_RATE:
  411. {
  412. [self.recordPlayer seekOffsetTime:rate*1000];
  413. NSInteger realOffsetTime = self.offsetTime + self.evaluateDelay;
  414. NSInteger offsetTime = rate*1000 + realOffsetTime;
  415. if (offsetTime >= 0) {
  416. [self.bgPlayer seekOffsetTime:offsetTime];
  417. }
  418. else {
  419. [self.bgPlayer puasePlay];
  420. if (self.recordPlayer.isPlaying) {
  421. [self.bgPlayer seekToStart];
  422. @weakObj(self);
  423. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((labs(offsetTime) + self.addTime) * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
  424. @strongObj(self);
  425. if (self.playControlView.isPlay == YES) {
  426. [self.bgPlayer resumePlay];
  427. [self snapPlayerProgress];
  428. }
  429. });
  430. }
  431. else {
  432. [self.bgPlayer seekToStart];
  433. }
  434. }
  435. if (self.isVideoPlay) {
  436. [self.videoView seekOffsetTime:rate*1000];
  437. }
  438. }
  439. break;
  440. default:
  441. break;
  442. }
  443. }
  444. // 对齐播放延迟
  445. - (void)snapPlayerProgress {
  446. @weakObj(self);
  447. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
  448. @strongObj(self);
  449. if (self.playControlView.isPlay == YES) {
  450. CMTime time = [self.recordPlayer getCurrentPlayTime];
  451. NSInteger newDelayTime = CMTimeGetSeconds(time) * 1000 + self.offsetTime + self.evaluateDelay;
  452. [self.recordPlayer seekOffsetTimeNoPuase:CMTimeGetSeconds(time) * 1000];
  453. [self.bgPlayer seekOffsetTime:newDelayTime];
  454. }
  455. });
  456. }
  457. - (void)startTimer {
  458. [self.timer setFireDate:[NSDate distantPast]];
  459. }
  460. - (void)stopTimer {
  461. [self.timer setFireDate:[NSDate distantFuture]];
  462. }
  463. - (KSMergeAudioControlView *)contrlView {
  464. if (!_contrlView) {
  465. _contrlView = [KSMergeAudioControlView shareIntance];
  466. MJWeakSelf;
  467. [_contrlView controlActionCallback:^(MERGEACTION type, NSInteger recordVolume, NSInteger bgVolume, NSInteger offsetTime) {
  468. [weakSelf megerAction:type recordVolume:recordVolume bgVolume:bgVolume offsetTime:offsetTime];
  469. }];
  470. }
  471. return _contrlView;
  472. }
  473. - (void)megerAction:(MERGEACTION)action recordVolume:(NSInteger)recordVolume bgVolume:(NSInteger)bgVolume offsetTime:(NSInteger)offsetTime {
  474. switch (action) {
  475. case MERGEACTION_CANCLE:
  476. {
  477. [self backAction];
  478. }
  479. break;
  480. case MERGEACTION_MODIFY:
  481. {
  482. self.hasModify = YES;
  483. self.accompanyVolume = bgVolume;
  484. self.originalVolume = recordVolume;
  485. self.bgPlayer.volume = bgVolume / 100.0;
  486. self.recordPlayer.volume = recordVolume / 100.0;
  487. }
  488. break;
  489. case MERGEACTION_DELAY: // offset
  490. {
  491. self.hasModify = YES;
  492. if (self.bgPlayer.isPlaying) {
  493. CMTime time = [self.recordPlayer getCurrentPlayTime];
  494. NSInteger newDelayTime = CMTimeGetSeconds(time) * 1000 + offsetTime + self.evaluateDelay;
  495. [self.recordPlayer seekOffsetTime:CMTimeGetSeconds(time) * 1000];
  496. [self.bgPlayer seekOffsetTime:newDelayTime];
  497. }
  498. self.offsetTime = offsetTime;
  499. }
  500. break;
  501. case MERGEACTION_SAVE: // 保存
  502. {
  503. // 暂停播放
  504. [self stopPlay];
  505. [self saveCurrentDraft:NO];
  506. }
  507. break;
  508. case MERGEACTION_UPLOAD: // 上传
  509. {
  510. [self showPublishAlert];
  511. }
  512. break;
  513. case MERGEACTION_HIDEVIEW:
  514. {
  515. [self hideControlView];
  516. }
  517. break;
  518. default:
  519. break;
  520. }
  521. }
  522. - (void)showPublishAlert {
  523. self.publishAlert = [MusicPublistAlert shareInstance];
  524. [self.publishAlert configUI:self.isVideoPlay];
  525. [self.publishAlert evaluateMusicName:self.songName userName:UserDefault(NicknameKey) musicImage:self.coverImage];
  526. MJWeakSelf;
  527. [self.publishAlert chooseAction:^(PUBLISH_ACTION type) {
  528. [weakSelf publishAction:type];
  529. }];
  530. [self.publishAlert showAlert];
  531. }
  532. - (void)publishAction:(PUBLISH_ACTION)type {
  533. switch (type) {
  534. case PUBLISH_ACTION_PUBLISH:
  535. {
  536. // 暂停播放
  537. [self stopPlay];
  538. self.desc = [NSString isEmptyString:self.publishAlert.publishContainView.textView.text] ? @"我发布了一首演奏作品,快来听听吧~" :self.publishAlert.publishContainView.textView.text;
  539. if (self.settingImage || self.videoCoverImage) { // 上传图片
  540. [self updateWithCoverImage];
  541. }
  542. else { // 直接上传
  543. [self publishMusic];
  544. }
  545. }
  546. break;
  547. case PUBLISH_ACTION_CHOOSEIMG:
  548. {
  549. // 暂停播放
  550. [self stopPlay];
  551. self.isChooseVideoCover = NO;
  552. // 调用相册
  553. self.mediaManager = [[KSMediaManager alloc] init];
  554. self.mediaManager.mediaType = MEDIATYPE_PHOTO;
  555. self.mediaManager.maxPhotoNumber = 1;
  556. self.mediaManager.baseCtrl = [self findViewController];
  557. self.mediaManager.needCropImage = NO;
  558. MJWeakSelf;
  559. [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
  560. // 裁剪
  561. UIImage *sendImg = [imageArray lastObject];
  562. // 跳转到裁剪功能
  563. RSKImageCropViewController *imageCropVC = [[RSKImageCropViewController alloc] initWithImage:sendImg cropMode:RSKImageCropModeCustom];
  564. imageCropVC.avoidEmptySpaceAroundImage = YES;
  565. imageCropVC.rotationEnabled = YES;
  566. imageCropVC.delegate = weakSelf;
  567. imageCropVC.dataSource = weakSelf;
  568. imageCropVC.modalPresentationStyle = UIModalPresentationFullScreen;
  569. UIViewController *baseCtrl = [weakSelf findViewController];
  570. [baseCtrl.navigationController presentViewController:imageCropVC animated:YES completion:nil];
  571. }];
  572. [self.mediaManager pushImagePickerController];
  573. }
  574. break;
  575. case PUBLISH_ACTION_VIDEOCOVER: // 视频封面
  576. {
  577. // 暂停播放
  578. [self stopPlay];
  579. self.isChooseVideoCover = YES;
  580. // 调用相册
  581. self.mediaManager = [[KSMediaManager alloc] init];
  582. self.mediaManager.mediaType = MEDIATYPE_PHOTO;
  583. self.mediaManager.maxPhotoNumber = 1;
  584. self.mediaManager.baseCtrl = [self findViewController];
  585. self.mediaManager.needCropImage = NO;
  586. MJWeakSelf;
  587. [self.mediaManager noAlertCallback:^(NSString * _Nullable videoUrl, NSMutableArray * _Nullable imageArray, NSMutableArray * _Nullable imageAsset) {
  588. // 裁剪
  589. UIImage *sendImg = [imageArray lastObject];
  590. // 跳转到裁剪功能
  591. RSKImageCropViewController *imageCropVC = [[RSKImageCropViewController alloc] initWithImage:sendImg cropMode:RSKImageCropModeCustom];
  592. imageCropVC.avoidEmptySpaceAroundImage = YES;
  593. imageCropVC.rotationEnabled = YES;
  594. imageCropVC.delegate = weakSelf;
  595. imageCropVC.dataSource = weakSelf;
  596. imageCropVC.modalPresentationStyle = UIModalPresentationFullScreen;
  597. UIViewController *baseCtrl = [weakSelf findViewController];
  598. [baseCtrl.navigationController presentViewController:imageCropVC animated:YES completion:nil];
  599. }];
  600. [self.mediaManager pushImagePickerController];
  601. }
  602. break;
  603. case PUBLISH_ACTION_VIDEOCROP:
  604. {
  605. // 暂停播放
  606. [self stopPlay];
  607. KSVideoCropViewController *ctrl = [[KSVideoCropViewController alloc] init];
  608. [ctrl configWithVideoPath:self.videoUrl];
  609. UIViewController *baseCtrl = [self findViewController];
  610. MJWeakSelf;
  611. [ctrl chooseCropImageCallback:^(UIImage * _Nonnull cropImage) {
  612. [weakSelf displayCoverImage:cropImage];
  613. }];
  614. ctrl.modalPresentationStyle = UIModalPresentationFullScreen;
  615. [baseCtrl.navigationController presentViewController:ctrl animated:YES completion:nil];
  616. }
  617. break;
  618. case PUBLISH_ACTION_CANCLE:
  619. {
  620. self.settingImage = nil;
  621. self.videoCoverImage = nil;
  622. }
  623. break;
  624. default:
  625. break;
  626. }
  627. }
  628. - (void)displayCoverImage:(UIImage *)image {
  629. self.videoCoverImage = image;
  630. [self.publishAlert.coverView.coverImage setImage:self.videoCoverImage];
  631. }
  632. - (void)updateWithCoverImage {
  633. [self uploadMusicCover];
  634. }
  635. - (void)uploadMusicCover {
  636. NSString *tips = self.isVideoPlay ? @"视频合成中" : @"音频合成中";
  637. [LOADING_MANAGER showProgressLoading:tips progress:0];
  638. if (self.settingImage) {
  639. NSData *imgData = [UIImage turnsImaegDataByImage:self.settingImage];
  640. NSString *fileName = @"musicCoverImg";
  641. [UPLOAD_MANAGER configWithfilePath:@"klx"];
  642. [[KSUploadManager shareInstance] uploadImage:imgData fileName:fileName successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
  643. NSString *avatarUrl = [fileUrlArray lastObject];
  644. self.coverImage = avatarUrl;
  645. [self uploadVideoCover];
  646. } faliure:^(NSError * _Nullable error, NSString *descMessaeg) {
  647. if (![NSString isEmptyString:descMessaeg]) {
  648. [LOADING_MANAGER MBShowAUTOHidingInWindow:descMessaeg];
  649. }
  650. [self uploadVideoCover];
  651. }];
  652. }
  653. else {
  654. [self uploadVideoCover];
  655. }
  656. }
  657. - (void)uploadVideoCover {
  658. if (self.videoCoverImage) {
  659. NSData *imgData = [UIImage turnsImaegDataByImage:self.videoCoverImage];
  660. NSString *fileName = @"musicCoverImg";
  661. [UPLOAD_MANAGER configWithfilePath:@"klx"];
  662. [[KSUploadManager shareInstance] uploadImage:imgData fileName:fileName successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
  663. NSString *avatarUrl = [fileUrlArray lastObject];
  664. self.videoCoverUrl = avatarUrl;
  665. [self publishMusic];
  666. } faliure:^(NSError * _Nullable error, NSString *descMessaeg) {
  667. if (![NSString isEmptyString:descMessaeg]) {
  668. [LOADING_MANAGER MBShowAUTOHidingInWindow:descMessaeg];
  669. }
  670. [self publishMusic];
  671. }];
  672. }
  673. else {
  674. [self publishMusic];
  675. }
  676. }
  677. - (void)refreshViewCoverImg:(NSMutableArray *)imageArray {
  678. UIImage *img = [imageArray lastObject];
  679. self.settingImage = img;
  680. [self.publishAlert.publishContainView.musicImage setImage:self.settingImage];
  681. }
  682. - (void)publishMusic {
  683. CGFloat progress = 1.0/3;
  684. CGFloat rate = 1.0/3;
  685. if (self.isVideoPlay) {
  686. [LOADING_MANAGER showProgressLoading:@"视频合成中" progress:0];
  687. CGFloat offsetTime = self.offsetTime + self.evaluateDelay;
  688. [KSMediaEditor mixVideoWithRecordAudio:self.recordUrl recordVolume:self.recordPlayer.volume bgAudio:self.bgAudioUrl bgAudioVolume:self.bgPlayer.volume offsetTime:offsetTime videoUrlStr:self.videoUrl completion:^(NSString * _Nonnull outPath, BOOL isSuccess, NSString * _Nonnull desc) {
  689. [LOADING_MANAGER showProgressLoading:@"视频合成中" progress:progress];
  690. // 保存文件到指定文件夹
  691. if (isSuccess) {
  692. self.filePath = outPath;
  693. MJWeakSelf;
  694. [self sendVideoActionWithUrl:outPath isFormal:YES startProgress:progress rate:rate success:^(NSString * _Nonnull uploadVideoUrl) {
  695. [weakSelf saveMusic:YES isFormal:YES fileUrl:uploadVideoUrl progress:progress*2];
  696. } failure:^(NSString * _Nonnull desc) {
  697. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"上传失败"];
  698. }];
  699. }
  700. else {
  701. [LOADING_MANAGER removeProgressLoading];
  702. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"视频合成失败"];
  703. }
  704. }];
  705. }
  706. else {
  707. [LOADING_MANAGER showProgressLoading:@"音频合成中" progress:0];
  708. NSInteger realOffsetTime = self.offsetTime + self.evaluateDelay;
  709. [KSMediaEditor mixRecordAudio:self.recordUrl recordVolume:self.recordPlayer.volume bgAudio:self.bgAudioUrl bgAudioVolume:self.bgPlayer.volume offsetTime:realOffsetTime completion:^(NSString * _Nonnull outPath, BOOL isSuccess, NSString * _Nonnull desc) {
  710. // 保存文件到指定文件夹
  711. [LOADING_MANAGER showProgressLoading:@"音频合成中" progress:progress];
  712. if (isSuccess) {
  713. self.filePath = outPath;
  714. MJWeakSelf;
  715. [self sendAudioWithPath:outPath isFormal:YES startProgress:progress rate:rate success:^(NSString *audioUrl) {
  716. [weakSelf saveMusic:NO isFormal:YES fileUrl:audioUrl progress:progress*2];
  717. } failure:^(NSString *desc) {
  718. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"上传失败"];
  719. }];
  720. }
  721. else {
  722. [LOADING_MANAGER removeProgressLoading];
  723. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"音频合成失败"];
  724. }
  725. }];
  726. }
  727. }
  728. - (void)saveCurrentDraft:(BOOL)needBack {
  729. self.hasModify = NO;
  730. if (self.isVideoPlay) {
  731. if (self.remoteVideoUrl) {
  732. // 保存草稿
  733. [LOADING_MANAGER showProgressLoading:@"正在保存草稿" progress:0 promptCompletion:^{
  734. [self saveMusic:YES isFormal:NO fileUrl:self.remoteVideoUrl needBack:needBack progress:0.5];
  735. }];
  736. }
  737. else {
  738. // 合成
  739. [LOADING_MANAGER showProgressLoading:@"正在上传草稿" progress:0];
  740. MJWeakSelf;
  741. [KSMediaEditor mixRecordVideoWithAudio:self.recordUrl recordVolume:100 videoUrlStr:self.videoUrl completion:^(NSString * _Nonnull outPath, BOOL isSuccess, NSString * _Nonnull desc) {
  742. if (isSuccess) {
  743. [self sendVideoActionWithUrl:outPath isFormal:NO startProgress:0 rate:0.5 success:^(NSString * _Nonnull uploadVideoUrl) {
  744. // 保存草稿
  745. [weakSelf saveMusic:YES isFormal:NO fileUrl:uploadVideoUrl needBack:needBack progress:0.5];
  746. } failure:^(NSString * _Nonnull desc) {
  747. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"上传失败"];
  748. }];
  749. }
  750. else {
  751. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"上传失败"];
  752. }
  753. }];
  754. }
  755. }
  756. else {
  757. if (self.remoteRecrodUrl) {
  758. [LOADING_MANAGER showProgressLoading:@"正在保存草稿" progress:0 promptCompletion:^{
  759. [self saveMusic:NO isFormal:NO fileUrl:self.remoteRecrodUrl needBack:needBack progress:0.5];
  760. }];
  761. }
  762. else {
  763. MJWeakSelf;
  764. [LOADING_MANAGER showProgressLoading:@"正在上传草稿" progress:0];
  765. [self sendAudioWithURLPath:self.recordUrl isFormal:NO startProgress:0 rate:0.5 success:^(NSString *audioUrl) {
  766. // 保存草稿
  767. [weakSelf saveMusic:NO isFormal:NO fileUrl:audioUrl needBack:needBack progress:0.5];
  768. } failure:^(NSString *desc) {
  769. [LOADING_MANAGER MBShowAUTOHidingInWindow:@"上传失败"];
  770. }];
  771. }
  772. }
  773. }
  774. - (void)removeViewTips:(BOOL)needTips {
  775. [self freePlayer];
  776. [self removeFromSuperview];
  777. if (self.draftCallback) {
  778. self.draftCallback();
  779. }
  780. if (needTips && self.mergeCallback) {
  781. self.mergeCallback();
  782. }
  783. }
  784. - (void)removeView {
  785. [self removeViewTips:YES];
  786. }
  787. - (void)freePlayer {
  788. if (_bgPlayer) {
  789. [self.bgPlayer freePlayer];
  790. }
  791. if (_recordPlayer) {
  792. [self.recordPlayer freePlayer];
  793. }
  794. if (_videoView) {
  795. [self.videoView freePlayer];
  796. }
  797. }
  798. - (kSNewPlayer *)bgPlayer {
  799. if (!_bgPlayer) {
  800. _bgPlayer = [[kSNewPlayer alloc] init];
  801. _bgPlayer.delegate = self;
  802. }
  803. return _bgPlayer;
  804. }
  805. - (kSNewPlayer *)recordPlayer {
  806. if (!_recordPlayer) {
  807. _recordPlayer = [[kSNewPlayer alloc] init];
  808. _recordPlayer.delegate = self;
  809. }
  810. return _recordPlayer;
  811. }
  812. #pragma mark ----- player delegate
  813. - (void)videoPlayerIsReadyPlay:(AVPlayer *)player {
  814. }
  815. - (void)playerIsReadyPlay:(kSNewPlayer *)player {
  816. if (self.bgPlayer.isReady && self.recordPlayer.isReady) {
  817. [self startPlay];
  818. }
  819. }
  820. - (void)getSongCurrentTime:(NSInteger)currentTime andTotalTime:(NSInteger)totalTime andProgress:(CGFloat)progress currentInterval:(NSTimeInterval)currentInterval playTime:(NSTimeInterval)playTime inPlayer:(kSNewPlayer *_Nonnull)player {
  821. if (player == self.recordPlayer) {
  822. // NSLog(@"--- ---- ----- %f", playTime);
  823. self.playControlView.playScheduleTime = (NSInteger)(playTime / 1000);
  824. NSInteger realOffset = (NSInteger)(CMTimeGetSeconds([self.bgPlayer getCurrentPlayTime]) *1000 - CMTimeGetSeconds([self.recordPlayer getCurrentPlayTime])*1000);
  825. // NSLog(@" offset ---- %ld" , realOffset);
  826. // 如果延迟大于11ms 调整
  827. NSInteger expectOffset = self.offsetTime + self.evaluateDelay;
  828. NSLog(@"---- expectOffset == %@", [NSString stringWithFormat:@"实际: %ld, 期望偏差 %ld", realOffset, expectOffset]);
  829. // self.offsetTimeLabel.text = [NSString stringWithFormat:@"实际: %ld, 期望偏差 %ld", realOffset, expectOffset];
  830. // if (labs(labs(realOffset) - labs(expectOffset)) >= 11) { // 需要调整
  831. //
  832. // if (labs(realOffset) < labs(expectOffset)) { // 要扩大差距
  833. // if (expectOffset > 0) { // 300
  834. // if (self.bgPlayerRate != 1.02) {
  835. // self.bgPlayerRate = 1.02;
  836. // [self.bgPlayer configPlayerRate:1.02];
  837. // [self.recordPlayer configPlayerRate:0.98];
  838. // }
  839. // }
  840. // else { // expectOffset < 0 -300
  841. // if (self.bgPlayerRate != 0.98) {
  842. // self.bgPlayerRate = 0.98;
  843. // [self.bgPlayer configPlayerRate:0.98];
  844. // [self.recordPlayer configPlayerRate:1.02];
  845. // }
  846. // }
  847. // }
  848. // else { // 需要减小差距
  849. // if (realOffset > 0) {
  850. // if (self.bgPlayerRate != 0.98) {
  851. // self.bgPlayerRate = 0.98;
  852. // [self.bgPlayer configPlayerRate:0.98];
  853. // [self.recordPlayer configPlayerRate:1.02];
  854. // }
  855. // }
  856. // else {
  857. // if (self.bgPlayerRate != 1.02) {
  858. // self.bgPlayerRate = 1.02;
  859. // [self.bgPlayer configPlayerRate:1.02];
  860. // [self.recordPlayer configPlayerRate:0.98];
  861. // }
  862. // }
  863. // }
  864. // }
  865. // else {
  866. // if (self.bgPlayerRate != 1.0) {
  867. // self.bgPlayerRate = 1.0;
  868. // [self.recordPlayer configPlayerRate:1.0];
  869. // [self.bgPlayer configPlayerRate:1.0];
  870. // }
  871. // }
  872. }
  873. else {
  874. // NSLog(@"------- bgPlayer ----- %f", playTime);
  875. }
  876. }
  877. - (void)playFinished:(kSNewPlayer *)player {
  878. if (player == self.recordPlayer) {
  879. [self.recordPlayer puasePlay];
  880. [self.recordPlayer seekToStart];
  881. [self.bgPlayer puasePlay];
  882. [self.bgPlayer seekToStart];
  883. self.animationView.isPlay = NO;
  884. self.playControlView.isPlay = NO;
  885. [self.playAnimationView stopAnimation];
  886. [self stopTimer];
  887. if (self.isVideoPlay) {
  888. [self.videoView puasePlay];
  889. [self.videoView seekToStart];
  890. }
  891. }
  892. }
  893. - (void)playerDidError:(kSNewPlayer *)player {
  894. [self stopPlay];
  895. }
  896. - (KSVideoPlayerView *)videoView {
  897. if (!_videoView) {
  898. _videoView = [[KSVideoPlayerView alloc] init];
  899. _videoView.delegate = self;
  900. }
  901. return _videoView;
  902. }
  903. - (UIButton *)showButton {
  904. if (!_showButton) {
  905. _showButton = [UIButton buttonWithType:UIButtonTypeCustom];
  906. _showButton.frame = CGRectMake(KLandscapeWidth-30, (KLandscapeHeight-30)/2.0, 30, 30);
  907. [_showButton setImage:[UIImage imageNamed:@"mergeControl_show"] forState:UIControlStateNormal];
  908. [_showButton addTarget:self action:@selector(showControlView) forControlEvents:UIControlEventTouchUpInside];
  909. }
  910. return _showButton;
  911. }
  912. - (void)hideControlView {
  913. [UIView animateWithDuration:0.5f animations:^{
  914. [self.contrlView mas_remakeConstraints:^(MASConstraintMaker *make) {
  915. make.top.bottom.mas_equalTo(self);
  916. make.width.mas_equalTo(289);
  917. make.right.mas_equalTo(self.mas_right).offset(289);
  918. }];
  919. } completion:^(BOOL finished) {
  920. self.showButton.hidden = NO;
  921. self.showButton.userInteractionEnabled = YES;
  922. }];
  923. }
  924. - (void)showControlView {
  925. [UIView animateWithDuration:0.5f animations:^{
  926. [self.contrlView mas_remakeConstraints:^(MASConstraintMaker *make) {
  927. make.right.top.bottom.mas_equalTo(self);
  928. make.width.mas_equalTo(289);
  929. }];
  930. } completion:^(BOOL finished) {
  931. self.showButton.hidden = YES;
  932. self.showButton.userInteractionEnabled = NO;
  933. }];
  934. }
  935. - (void)saveMusic:(BOOL)isVideo isFormal:(BOOL)isFormal fileUrl:(NSString *)fileUrl progress:(CGFloat)progress {
  936. [self saveMusic:isVideo isFormal:isFormal fileUrl:fileUrl needBack:NO progress:progress];
  937. }
  938. - (void)saveMusic:(BOOL)isVideo isFormal:(BOOL)isFormal fileUrl:(NSString *)fileUrl needBack:(BOOL)needBack progress:(CGFloat)progress {
  939. NSString *type = isFormal ? @"FORMAL" : @"DRAFT";
  940. NSMutableDictionary *parm = [NSMutableDictionary dictionary];
  941. [parm setValue:@(self.offsetTime) forKey:@"offset"];
  942. [parm setValue:@(self.originalVolume) forKey:@"originalVolume"];
  943. [parm setValue:@(self.accompanyVolume) forKey:@"accompanyVolume"];
  944. [parm setValue:@(self.defaultDelay) forKey:@"defaultDelay"];
  945. [parm setValue:@(self.evaluateDelay) forKey:@"evaluateDelay"];
  946. self.jsonConfig = [parm mj_JSONString];
  947. [KSNetworkingManager saveMusicMessage:KS_POST jsonConfig:self.jsonConfig img:self.coverImage videoUrl:fileUrl accompanyUrl:self.remoteBgAudioUrl desc:self.desc type:type musicPracticeRecordId:self.recordId videoImg:self.videoCoverUrl success:^(NSDictionary * _Nonnull dic) {
  948. if ([dic ks_integerValueForKey:@"code"] == 200) {
  949. if (isFormal) {
  950. [LOADING_MANAGER KSShowProgressMsg:@"发布成功" promptCompletion:^{
  951. [self removeView];
  952. }];
  953. }
  954. else {
  955. [LOADING_MANAGER KSShowProgressMsg:@"保存成功" promptCompletion:^{
  956. self.hasModify = NO;
  957. if (needBack) {
  958. [self removeViewTips:NO];
  959. }
  960. else { // 从云教练进入 点击保存 显示保存弹窗
  961. if (self.fromDraftPage == NO) {
  962. [self showSaveDraftTipsAlert];
  963. }
  964. }
  965. }];
  966. }
  967. }
  968. else {
  969. [LOADING_MANAGER removeProgressLoading];
  970. [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
  971. }
  972. } faliure:^(NSError * _Nonnull error) {
  973. [LOADING_MANAGER removeProgressLoading];
  974. }];
  975. }
  976. - (void)showSaveDraftTipsAlert {
  977. MJWeakSelf;
  978. [self.alertView configTitle:@"提示" descMessage:@"已成功保存到草稿,草稿7天未发布将自动删除。" leftButtonTitle:@"确认" rightButtonTitle:@"查看草稿" leftButtonAction:^{
  979. } rightButtonAction:^{
  980. [weakSelf displayDraft];
  981. }];
  982. [self.alertView showAlert];
  983. }
  984. - (void)displayDraft {
  985. // 跳转到我的作品
  986. UIViewController *baseCtrl = [self findViewController];
  987. [baseCtrl.navigationController popToRootViewControllerAnimated:YES];
  988. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  989. [[NSNotificationCenter defaultCenter] postNotificationName:@"DisplayDraft" object:nil];
  990. });
  991. }
  992. - (void)sendVideoActionWithUrlPath:(NSURL *)fileUrl isFormal:(BOOL)isFormal beginProgress:(CGFloat)beginProgress rate:(CGFloat)rate success:(void (^)(NSString * _Nonnull uploadVideoUrl))success failure:(void (^)(NSString * _Nonnull desc))faliure {
  993. NSString *tips = isFormal ? @"正在上传作品" : @"正在上传草稿";
  994. [LOADING_MANAGER showProgressLoading:tips progress:beginProgress];
  995. NSData *fileData = [NSData dataWithContentsOfURL:fileUrl];
  996. NSString *suffix = [NSString stringWithFormat:@".%@",[fileUrl pathExtension]];
  997. [UPLOAD_MANAGER configWithfilePath:@"klx"];
  998. [[KSUploadManager shareInstance] videoUpload:fileData fileName:@"video" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
  999. // 显示进度
  1000. float progress = (bytesWritten*1.0 / totalBytes) * rate + beginProgress;
  1001. dispatch_main_async_safe(^{
  1002. [LOADING_MANAGER showProgressNoAnimationLoading:tips progress:progress];
  1003. });
  1004. } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
  1005. dispatch_main_async_safe(^{
  1006. NSString *fileUrl = [fileUrlArray lastObject];
  1007. success(fileUrl);
  1008. });
  1009. } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
  1010. dispatch_main_async_safe(^{
  1011. [LOADING_MANAGER removeProgressLoading];
  1012. faliure(descMessaeg);
  1013. });
  1014. }];
  1015. }
  1016. - (void)sendVideoActionWithUrl:(NSString *)fileUrl isFormal:(BOOL)isFormal startProgress:(CGFloat)beginProgress rate:(CGFloat)rate success:(void (^)(NSString * _Nonnull uploadVideoUrl))success failure:(void (^)(NSString * _Nonnull desc))faliure {
  1017. [self sendVideoActionWithUrlPath:[NSURL fileURLWithPath:fileUrl] isFormal:isFormal beginProgress:beginProgress rate:rate success:success failure:faliure];
  1018. }
  1019. - (void)sendAudioWithURLPath:(NSURL *)fileUrl isFormal:(BOOL)isFormal startProgress:(CGFloat)beginProgress rate:(CGFloat)rate success:(void(^)(NSString *audioUrl))success failure:(void(^)(NSString *desc))faliure {
  1020. NSString *tips = isFormal ? @"正在上传作品" : @"正在上传草稿";
  1021. [LOADING_MANAGER showProgressLoading:tips progress:beginProgress];
  1022. NSData *fileData = [NSData dataWithContentsOfURL:fileUrl];
  1023. NSString *suffix = [NSString stringWithFormat:@".%@",[fileUrl pathExtension]];
  1024. [UPLOAD_MANAGER configWithfilePath:@"klx"];
  1025. [UPLOAD_MANAGER uploadFile:fileData fileName:@"evaluateAudio" fileSuffix:suffix progress:^(int64_t bytesWritten, int64_t totalBytes) {
  1026. // 显示进度
  1027. float progress = (bytesWritten*1.0 / totalBytes) * rate + beginProgress;
  1028. dispatch_main_async_safe(^{
  1029. [LOADING_MANAGER showProgressNoAnimationLoading:tips progress:progress];
  1030. });
  1031. } successCallback:^(NSMutableArray * _Nonnull fileUrlArray) {
  1032. NSString *fileUrl = [fileUrlArray lastObject];
  1033. success(fileUrl);
  1034. } faliure:^(NSError * _Nullable error, NSString * _Nullable descMessaeg) {
  1035. [LOADING_MANAGER removeProgressLoading];
  1036. faliure(descMessaeg);
  1037. }];
  1038. }
  1039. - (void)sendAudioWithPath:(NSString *)filePath isFormal:(BOOL)isFormal startProgress:(CGFloat)beginProgress rate:(CGFloat)rate success:(void(^)(NSString *audioUrl))success failure:(void(^)(NSString *desc))faliure {
  1040. NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
  1041. [self sendAudioWithURLPath:fileUrl isFormal:isFormal startProgress:beginProgress rate:rate success:success failure:faliure];
  1042. }
  1043. - (void)removeVideoWithPath:(NSString *)videoUrl {
  1044. NSFileManager *fileMamager = [NSFileManager defaultManager];
  1045. if ([fileMamager fileExistsAtPath:videoUrl]) {
  1046. [fileMamager removeItemAtPath:videoUrl error:nil];
  1047. }
  1048. }
  1049. - (KSAudioPlayAnimationView *)playAnimationView {
  1050. if (!_playAnimationView) {
  1051. _playAnimationView = [[KSAudioPlayAnimationView alloc] init];
  1052. _playAnimationView.frame = CGRectMake(0, 0, 424, 80);
  1053. }
  1054. return _playAnimationView;
  1055. }
  1056. - (NSTimer *)timer{
  1057. if (!_timer) {
  1058. MJWeakSelf;
  1059. _timer = [NSTimer scheduledTimerWithTimeInterval:0.5f repeats:YES block:^(NSTimer * _Nonnull timer) {
  1060. [weakSelf timerAction];
  1061. }];
  1062. [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  1063. [_timer setFireDate:[NSDate distantFuture]];
  1064. }
  1065. return _timer;
  1066. }
  1067. - (void)timerAction {
  1068. float value = drand48();
  1069. [self.playAnimationView setSoundsValue:value];
  1070. }
  1071. #pragma mark -- 重置定时器
  1072. - (void)resetTimer{
  1073. [self.timer setFireDate:[NSDate distantPast]];
  1074. [_timer invalidate];
  1075. _timer = nil;
  1076. }
  1077. - (void)removeAll{
  1078. if (_timer) {
  1079. [_timer invalidate];
  1080. _timer = nil;
  1081. }
  1082. }
  1083. - (void)dealloc {
  1084. [self removeAll];
  1085. [[NSNotificationCenter defaultCenter] removeObserver:self];
  1086. }
  1087. #pragma mark ----- lazy
  1088. - (dispatch_group_t)requestGroup {
  1089. if (!_requestGroup) {
  1090. _requestGroup = dispatch_group_create();
  1091. }
  1092. return _requestGroup;
  1093. }
  1094. - (KSNewAlertView *)alertView {
  1095. if (!_alertView) {
  1096. _alertView = [KSNewAlertView shareInstance];
  1097. }
  1098. return _alertView;
  1099. }
  1100. - (UIViewController *)findViewController {
  1101. for (UIView *view = self; view; view = view.superview) {
  1102. UIResponder *nextResponder = [view nextResponder];
  1103. if ([nextResponder isKindOfClass:[UIViewController class]]) {
  1104. return (UIViewController *)nextResponder;
  1105. }
  1106. }
  1107. return nil;
  1108. }
  1109. #pragma mark --- RSKImageCropViewControllerDelegate
  1110. - (CGRect)imageCropViewControllerCustomMaskRect:(RSKImageCropViewController *)controller {
  1111. CGFloat height = KLandscapeHeight - 80;
  1112. CGFloat width = height;
  1113. if (self.isChooseVideoCover) {
  1114. width = height / 9 * 16;
  1115. }
  1116. return CGRectMake((KLandscapeWidth - width) / 2.0f, (KLandscapeHeight - height) / 2.0f, width, height);
  1117. }
  1118. - (UIBezierPath *)imageCropViewControllerCustomMaskPath:(RSKImageCropViewController *)controller {
  1119. //返回裁剪框的位置
  1120. CGFloat height = KLandscapeHeight - 80;
  1121. CGFloat width = height;
  1122. if (self.isChooseVideoCover) {
  1123. width = height / 9 * 16;
  1124. }
  1125. UIBezierPath *path=[UIBezierPath bezierPathWithRoundedRect:CGRectMake((KLandscapeWidth - width) / 2.0f, (KLandscapeHeight - height) / 2.0f, width, height) cornerRadius:0];
  1126. return path;
  1127. }
  1128. /**
  1129. 返回一个图片可以移动的矩形区域
  1130. 仅在RSKImageCropModeCustom下有效
  1131. 如果你想支持图片旋转,则必须实现该方法
  1132. */
  1133. - (CGRect)imageCropViewControllerCustomMovementRect:(RSKImageCropViewController *)controller
  1134. {
  1135. return controller.maskRect;
  1136. }
  1137. /**
  1138. 通知 delegate 取消裁剪图像。
  1139. */
  1140. - (void)imageCropViewControllerDidCancelCrop:(RSKImageCropViewController *)controller {
  1141. self.mediaManager.baseCtrl.zh_statusBarHidden = NO;
  1142. if (self.isChooseVideoCover) {
  1143. self.isChooseVideoCover = NO;
  1144. }
  1145. [controller dismissViewControllerAnimated:YES completion:nil];
  1146. }
  1147. /**
  1148. 通知 delegate 原始图像已经被裁剪。此外,还提供了一个裁剪矩形和用于生成图像的旋转角度。
  1149. */
  1150. - (void)imageCropViewController:(RSKImageCropViewController *)controller didCropImage:(UIImage *)croppedImage usingCropRect:(CGRect)cropRect rotationAngle:(CGFloat)rotationAngle {
  1151. self.mediaManager.baseCtrl.zh_statusBarHidden = NO;
  1152. // croppedImage
  1153. if (self.isChooseVideoCover) {
  1154. self.isChooseVideoCover = NO;
  1155. [self displayCoverImage:croppedImage];
  1156. }
  1157. else {
  1158. self.settingImage = croppedImage;
  1159. [self.publishAlert.publishContainView.musicImage setImage:self.settingImage];
  1160. }
  1161. [controller dismissViewControllerAnimated:YES completion:nil];
  1162. }
  1163. /*
  1164. // Only override drawRect: if you perform custom drawing.
  1165. // An empty implementation adversely affects performance during animation.
  1166. - (void)drawRect:(CGRect)rect {
  1167. // Drawing code
  1168. }
  1169. */
  1170. @end